精华内容
下载资源
问答
  • gadgetusb_gadget

    2021-03-17 22:27:13
    gadgetusb_gadget 简介 略。 struct usb_gadget /** * struct usb_gadget - represents a usb slave device * @work: (internal use) Workqueue to be used for sysfs_notify() * @udc: struct usb_udc pointer...

    gadget之usb_gadget

    简介

    略。

    struct usb_gadget

    /**
     * struct usb_gadget - represents a usb slave device
     * @work: (internal use) Workqueue to be used for sysfs_notify()
     * @udc: struct usb_udc pointer for this gadget
     * @ops: Function pointers used to access hardware-specific operations.
     * @ep0: Endpoint zero, used when reading or writing responses to
     *	driver setup() requests
     * @ep_list: List of other endpoints supported by the device.
     * @speed: Speed of current connection to USB host.
     * @max_speed: Maximal speed the UDC can handle.  UDC must support this
     *      and all slower speeds.
     * @state: the state we are now (attached, suspended, configured, etc)
     * @name: Identifies the controller hardware type.  Used in diagnostics
     *	and sometimes configuration.
     * @dev: Driver model state for this abstract device.
     * @isoch_delay: value from Set Isoch Delay request. Only valid on SS/SSP
     * @out_epnum: last used out ep number
     * @in_epnum: last used in ep number
     * @mA: last set mA value
     * @otg_caps: OTG capabilities of this gadget.
     * @sg_supported: true if we can handle scatter-gather
     * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
     *	gadget driver must provide a USB OTG descriptor.
     * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable
     *	is in the Mini-AB jack, and HNP has been used to switch roles
     *	so that the "A" device currently acts as A-Peripheral, not A-Host.
     * @a_hnp_support: OTG device feature flag, indicating that the A-Host
     *	supports HNP at this port.
     * @a_alt_hnp_support: OTG device feature flag, indicating that the A-Host
     *	only supports HNP on a different root port.
     * @b_hnp_enable: OTG device feature flag, indicating that the A-Host
     *	enabled HNP support.
     * @hnp_polling_support: OTG device feature flag, indicating if the OTG device
     *	in peripheral mode can support HNP polling.
     * @host_request_flag: OTG device feature flag, indicating if A-Peripheral
     *	or B-Peripheral wants to take host role.
     * @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
     *	MaxPacketSize.
     * @quirk_altset_not_supp: UDC controller doesn't support alt settings.
     * @quirk_stall_not_supp: UDC controller doesn't support stalling.
     * @quirk_zlp_not_supp: UDC controller doesn't support ZLP.
     * @quirk_avoids_skb_reserve: udc/platform wants to avoid skb_reserve() in
     *	u_ether.c to improve performance.
     * @is_selfpowered: if the gadget is self-powered.
     * @deactivated: True if gadget is deactivated - in deactivated state it cannot
     *	be connected.
     * @connected: True if gadget is connected.
     * @lpm_capable: If the gadget max_speed is FULL or HIGH, this flag
     *	indicates that it supports LPM as per the LPM ECN & errata.
     *
     * Gadgets have a mostly-portable "gadget driver" implementing device
     * functions, handling all usb configurations and interfaces.  Gadget
     * drivers talk to hardware-specific code indirectly, through ops vectors.
     * That insulates the gadget driver from hardware details, and packages
     * the hardware endpoints through generic i/o queues.  The "usb_gadget"
     * and "usb_ep" interfaces provide that insulation from the hardware.
     *
     * Except for the driver data, all fields in this structure are
     * read-only to the gadget driver.  That driver data is part of the
     * "driver model" infrastructure in 2.6 (and later) kernels, and for
     * earlier systems is grouped in a similar structure that's not known
     * to the rest of the kernel.
     *
     * Values of the three OTG device feature flags are updated before the
     * setup() call corresponding to USB_REQ_SET_CONFIGURATION, and before
     * driver suspend() calls.  They are valid only when is_otg, and when the
     * device is acting as a B-Peripheral (so is_a_peripheral is false).
     */
    struct usb_gadget {
    	struct work_struct		work;
    	struct usb_udc			*udc;
    	/* readonly to gadget driver */
    	const struct usb_gadget_ops	*ops;
    	struct usb_ep			*ep0;
    	struct list_head		ep_list;	/* of usb_ep */
    	enum usb_device_speed		speed;
    	enum usb_device_speed		max_speed;
    	enum usb_device_state		state;
    	const char			*name;
    	struct device			dev;
    	unsigned			isoch_delay;
    	unsigned			out_epnum;
    	unsigned			in_epnum;
    	unsigned			mA;
    	struct usb_otg_caps		*otg_caps;
    
    	unsigned			sg_supported:1;
    	unsigned			is_otg:1;
    	unsigned			is_a_peripheral:1;
    	unsigned			b_hnp_enable:1;
    	unsigned			a_hnp_support:1;
    	unsigned			a_alt_hnp_support:1;
    	unsigned			hnp_polling_support:1;
    	unsigned			host_request_flag:1;
    	unsigned			quirk_ep_out_aligned_size:1;
    	unsigned			quirk_altset_not_supp:1;
    	unsigned			quirk_stall_not_supp:1;
    	unsigned			quirk_zlp_not_supp:1;
    	unsigned			quirk_avoids_skb_reserve:1;
    	unsigned			is_selfpowered:1;
    	unsigned			deactivated:1;
    	unsigned			connected:1;
    	unsigned			lpm_capable:1;
    };
    

    struct usb_gadget_ops

    该ops主要是usb device conctrl相关控制的实例。

    /* the rest of the api to the controller hardware: device operations,
     * which don't involve endpoints (or i/o).
     */
    struct usb_gadget_ops {
    	int	(*get_frame)(struct usb_gadget *);
    	int	(*wakeup)(struct usb_gadget *);
    	int	(*set_selfpowered) (struct usb_gadget *, int is_selfpowered);
    	int	(*vbus_session) (struct usb_gadget *, int is_active);
    	int	(*vbus_draw) (struct usb_gadget *, unsigned mA);
    	int	(*pullup) (struct usb_gadget *, int is_on);
    	int	(*ioctl)(struct usb_gadget *,
    				unsigned code, unsigned long param);
    	void	(*get_config_params)(struct usb_dcd_config_params *);
    	int	(*udc_start)(struct usb_gadget *,
    			struct usb_gadget_driver *);
    	int	(*udc_stop)(struct usb_gadget *);
    	void	(*udc_set_speed)(struct usb_gadget *, enum usb_device_speed);
    	struct usb_ep *(*match_ep)(struct usb_gadget *,
    			struct usb_endpoint_descriptor *,
    			struct usb_ss_ep_comp_descriptor *);
    };
    

    usb_gadget创建:

    该成员需由实现udc控制器驱动者创建及初始化,示例如下:

    	udc->gadget.ops             = &arobot_gadget_ops; //初始化usb_gadget_ops
    	udc->gadget.speed           = USB_SPEED_FULL;
    	udc->gadget.max_speed       = USB_SPEED_FULL;       // usb 1.1
    	udc->gadget.dev.parent      = &pdev->dev;
    	udc->gadget.dev.init_name   = "gadget";
    	udc->gadget.name            = arobot_udc_name;
    	udc->gadget.ep0             = &udc->ep[0]->uep;
    	INIT_LIST_HEAD(&udc->gadget.ep_list);//初始化ep链表
    	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
    	
    	//初始化endpoint
    	buff_use_base = AROBOT_EP0_BUFF_BASE;
    	for (i = USBD_EPT0; i < USBD_MAXEPT; i++) {
    		_ep = udc->ep[i];
    		_ep->udc = udc;
    		_ep->uep.desc = NULL;
    		_ep->uep.name = udc_ep_name[i];
    		_ep->uep.ops  = &arobot_udc_ep_ops;
    
    		INIT_LIST_HEAD(&_ep->queue);
    		spin_lock_init(&_ep->lock);
    
    		if (i == USBD_EPT0) {           // endpoint 0
    			_ep->buff_addr = buff_use_base;
    			buff_use_base += AROBOT_EP_04567_BUFF_MAX_SIZE;
    
    			_ep->uep.caps.type_control = true;
    			_ep->uep.caps.type_iso     = false;
    			_ep->uep.caps.type_bulk    = false;
    			_ep->uep.caps.type_int     = false;
    		} else if (i <= USBD_EPT3) {    // endpoint 1~3
    			_ep->buff_addr = buff_use_base;
    			buff_use_base += (AROBOT_EP_123_BUFF_MAX_SIZE);
    
    			_ep->uep.caps.type_control = false;
    			_ep->uep.caps.type_iso     = false;
    			_ep->uep.caps.type_bulk    = true;
    			_ep->uep.caps.type_int     = true;
    		} else {                        // endpoint 4~7
    			_ep->buff_addr = buff_use_base;
    			buff_use_base += AROBOT_EP_04567_BUFF_MAX_SIZE;
    			_ep->uep.caps.type_control = false;
    			_ep->uep.caps.type_iso     = true;
    			_ep->uep.caps.type_bulk    = true;
    			_ep->uep.caps.type_int     = true;
    		}
    
    		_ep->uep.caps.dir_in  = true;
    		_ep->uep.caps.dir_out = true;
    
            //将endpoint添加到gadget.ep_list链表中
    		if (USBD_EPT0 != i) {
    			list_add_tail(&_ep->uep.ep_list, &udc->gadget.ep_list);
    		}
    
    		usb_ep_set_maxpacket_limit(&_ep->uep, AROBOT_EP_BUFF_MAX_SIZE);
    
    		udc_dbg("%s:0x%x \r\n", _ep->uep.name, _ep->buff_addr);
    	}
    

    usb_gadget_ops的创建:

    该成员需由实现udc控制器驱动者创建及初始化,示例如下:

    static const struct usb_gadget_ops arobot_gadget_ops = {
    	.get_frame       = arobot_udc_get_frame,
    	.wakeup          = arobot_udc_wakeup,
    	.set_selfpowered = arobot_udc_selfpowered,
    	.vbus_session	 = arobot_udc_vbus_session,
    	.vbus_draw	     = arobot_udc_vbus_draw,
    	.pullup          = arobot_udc_pullup,
    	.udc_start       = arobot_udc_start,
    	.udc_stop        = arobot_udc_stop,
    };
    

    usb_gadget的注册:
    该函数将创建一个usb_udc设备,并添加到udc_list链表中,具体过程详见:gadget之udc。

    /**
     * usb_add_gadget_udc - adds a new gadget to the udc class driver list
     * @parent: the parent device to this udc. Usually the controller
     * driver's device.
     * @gadget: the gadget to be added to the list
     *
     * Returns zero on success, negative errno otherwise.
     */
    int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
    {
    	return usb_add_gadget_udc_release(parent, gadget, NULL);
    }
    EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
    

    struct usb_gadget_driver

    /**
     * struct usb_gadget_driver - driver for usb 'slave' devices
     * @function: String describing the gadget's function
     * @max_speed: Highest speed the driver handles.
     * @setup: Invoked for ep0 control requests that aren't handled by
     *	the hardware level driver. Most calls must be handled by
     *	the gadget driver, including descriptor and configuration
     *	management.  The 16 bit members of the setup data are in
     *	USB byte order. Called in_interrupt; this may not sleep.  Driver
     *	queues a response to ep0, or returns negative to stall.
     * @disconnect: Invoked after all transfers have been stopped,
     *	when the host is disconnected.  May be called in_interrupt; this
     *	may not sleep.  Some devices can't detect disconnect, so this might
     *	not be called except as part of controller shutdown.
     * @bind: the driver's bind callback
     * @unbind: Invoked when the driver is unbound from a gadget,
     *	usually from rmmod (after a disconnect is reported).
     *	Called in a context that permits sleeping.
     * @suspend: Invoked on USB suspend.  May be called in_interrupt.
     * @resume: Invoked on USB resume.  May be called in_interrupt.
     * @reset: Invoked on USB bus reset. It is mandatory for all gadget drivers
     *	and should be called in_interrupt.
     * @driver: Driver model state for this driver.
     * @udc_name: A name of UDC this driver should be bound to. If udc_name is NULL,
     *	this driver will be bound to any available UDC.
     * @pending: UDC core private data used for deferred probe of this driver.
     * @match_existing_only: If udc is not found, return an error and don't add this
     *      gadget driver to list of pending driver
     *
     * Devices are disabled till a gadget driver successfully bind()s, which
     * means the driver will handle setup() requests needed to enumerate (and
     * meet "chapter 9" requirements) then do some useful work.
     *
     * If gadget->is_otg is true, the gadget driver must provide an OTG
     * descriptor during enumeration, or else fail the bind() call.  In such
     * cases, no USB traffic may flow until both bind() returns without
     * having called usb_gadget_disconnect(), and the USB host stack has
     * initialized.
     *
     * Drivers use hardware-specific knowledge to configure the usb hardware.
     * endpoint addressing is only one of several hardware characteristics that
     * are in descriptors the ep0 implementation returns from setup() calls.
     *
     * Except for ep0 implementation, most driver code shouldn't need change to
     * run on top of different usb controllers.  It'll use endpoints set up by
     * that ep0 implementation.
     *
     * The usb controller driver handles a few standard usb requests.  Those
     * include set_address, and feature flags for devices, interfaces, and
     * endpoints (the get_status, set_feature, and clear_feature requests).
     *
     * Accordingly, the driver's setup() callback must always implement all
     * get_descriptor requests, returning at least a device descriptor and
     * a configuration descriptor.  Drivers must make sure the endpoint
     * descriptors match any hardware constraints. Some hardware also constrains
     * other descriptors. (The pxa250 allows only configurations 1, 2, or 3).
     *
     * The driver's setup() callback must also implement set_configuration,
     * and should also implement set_interface, get_configuration, and
     * get_interface.  Setting a configuration (or interface) is where
     * endpoints should be activated or (config 0) shut down.
     *
     * (Note that only the default control endpoint is supported.  Neither
     * hosts nor devices generally support control traffic except to ep0.)
     *
     * Most devices will ignore USB suspend/resume operations, and so will
     * not provide those callbacks.  However, some may need to change modes
     * when the host is not longer directing those activities.  For example,
     * local controls (buttons, dials, etc) may need to be re-enabled since
     * the (remote) host can't do that any longer; or an error state might
     * be cleared, to make the device behave identically whether or not
     * power is maintained.
     */
     //该驱动是usbcore和composite之间交互必不可少的一环,
     //两者之间的联系主要靠他来维持,
     //内核已经提供好了,不需要我们去实现。
    struct usb_gadget_driver {
    	char			*function;
    	enum usb_device_speed	max_speed;
    	int			(*bind)(struct usb_gadget *gadget,
    					struct usb_gadget_driver *driver);
    	void			(*unbind)(struct usb_gadget *);
    	int			(*setup)(struct usb_gadget *,
    					const struct usb_ctrlrequest *); 枚举过程中必不可少的函数。不需要驱动去实现。
    	void			(*disconnect)(struct usb_gadget *);
    	void			(*suspend)(struct usb_gadget *);
    	void			(*resume)(struct usb_gadget *);
    	void			(*reset)(struct usb_gadget *);
    
    	/* FIXME support safe rmmod */
    	struct device_driver	driver;
    
    	char			*udc_name;
    	struct list_head	pending;
    	unsigned                match_existing_only:1;
    };
    

    usb_gadget_driver的创建:

    源码:drivers/usb/gadget/composite.c

    static const struct usb_gadget_driver composite_driver_template = {
    	.bind		= composite_bind,
    	.unbind		= composite_unbind,
    
    	.setup		= composite_setup,
    	.reset		= composite_disconnect,
    	.disconnect	= composite_disconnect,
    
    	.suspend	= composite_suspend,
    	.resume		= composite_resume,
    
    	.driver	= {
    		.owner		= THIS_MODULE,
    	},
    };
    

    usb_gadget_driver的注册:

    以serial为例:源码为drivers/usb/gadget/legacy/serial.c

    static int __init init(void)
    {
    	/* We *could* export two configs; that'd be much cleaner...
    	 * but neither of these product IDs was defined that way.
    	 */
    	if (use_acm) {
    		serial_config_driver.label = "CDC ACM config";
    		serial_config_driver.bConfigurationValue = 2;
    		device_desc.bDeviceClass = USB_CLASS_COMM;
    		device_desc.idProduct =
    				cpu_to_le16(GS_CDC_PRODUCT_ID);
    	} else if (use_obex) {
    		serial_config_driver.label = "CDC OBEX config";
    		serial_config_driver.bConfigurationValue = 3;
    		device_desc.bDeviceClass = USB_CLASS_COMM;
    		device_desc.idProduct =
    			cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
    	} else {
    		serial_config_driver.label = "Generic Serial config";
    		serial_config_driver.bConfigurationValue = 1;
    		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
    		device_desc.idProduct =
    				cpu_to_le16(GS_PRODUCT_ID);
    	}
    	strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
    
    	return usb_composite_probe(&gserial_driver);
    }
    module_init(init);
    
    static void __exit cleanup(void)
    {
    	usb_composite_unregister(&gserial_driver);
    }
    module_exit(cleanup);
    

    源码:drivers/usb/gadget/composite.c

    int usb_composite_probe(struct usb_composite_driver *driver)
    {
    	struct usb_gadget_driver *gadget_driver;
    
    	if (!driver || !driver->dev || !driver->bind)
    		return -EINVAL;
    
    	if (!driver->name)
    		driver->name = "composite";
    
        //usb_gadget_driver注册到usb_composite_driver
    	driver->gadget_driver = composite_driver_template;
    	gadget_driver = &driver->gadget_driver;
    
    	gadget_driver->function =  (char *) driver->name;
    	gadget_driver->driver.name = driver->name;
    	gadget_driver->max_speed = driver->max_speed;
    
    	return usb_gadget_probe_driver(gadget_driver);
    }
    EXPORT_SYMBOL_GPL(usb_composite_probe);
    
    int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
    {
    	struct usb_udc		*udc = NULL;
    	int			ret = -ENODEV;
    
    	if (!driver || !driver->bind || !driver->setup)
    		return -EINVAL;
    
    	mutex_lock(&udc_lock);
    	//遍历udc_list链表,查找udc设备
    	if (driver->udc_name) {
    		list_for_each_entry(udc, &udc_list, list) {
    			ret = strcmp(driver->udc_name, dev_name(&udc->dev));
    			if (!ret)
    				break;
    		}
    		if (ret)
    			ret = -ENODEV;
    		else if (udc->driver)
    			ret = -EBUSY;
    		else
    			goto found;
    	} else {
    		list_for_each_entry(udc, &udc_list, list) {
    			/* For now we take the first one */
    			if (!udc->driver)
    				goto found;
    		}
    	}
    
        //无udc设备,则将usb_gadget_driver添加到gadget_driver_pending_list链表
    	if (!driver->match_existing_only) {
    		list_add_tail(&driver->pending, &gadget_driver_pending_list);
    		pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
    			driver->function);
    		ret = 0;
    	}
    
    	mutex_unlock(&udc_lock);
    	return ret;
    found:
        //udc设备与usb_gadget_driver绑定,详见gadget之udc
    	ret = udc_bind_to_driver(udc, driver);
    	mutex_unlock(&udc_lock);
    	return ret;
    }
    EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
    
    展开全文
  • 1、USB设备状态在USB 2.0协议中第 9.1 USB Device States 章节规定了USB设备的6种状态,包括:linuxAttached/Powered/Default/Address/Configured/Suspendedapi其状态迁移图以下:less 在 Linux Kernel ch9.h 文件...

    1、USB设备状态

    在USB 2.0协议中第 9.1 USB Device States 章节规定了USB设备的6种状态,包括:linux

    Attached/Powered/Default/Address/Configured/Suspendedapi

    其状态迁移图以下:less

    3eda6c883bf22702e5c614ac174677eb.png

    在 Linux Kernel ch9.h 文件中用 enum usb_device_state 来标记这几种状态。函数

    // /include/uapi/linux/usb/ch9.h

    enum usb_device_state {

    /* NOTATTACHED isn't in the USB spec, and this state acts

    * the same as ATTACHED ... but it's clearer this way.

    */

    USB_STATE_NOTATTACHED = 0,

    /* chapter 9 and authentication (wireless) device states */

    USB_STATE_ATTACHED,

    USB_STATE_POWERED, /* wired */

    USB_STATE_RECONNECTING, /* auth */

    USB_STATE_UNAUTHENTICATED, /* auth */

    USB_STATE_DEFAULT, /* limited function */

    USB_STATE_ADDRESS,

    USB_STATE_CONFIGURED, /* most functions */

    USB_STATE_SUSPENDED

    /* NOTE: there are actually four different SUSPENDED

    * states, returning to POWERED, DEFAULT, ADDRESS, or

    * CONFIGURED respectively when SOF tokens flow again.

    * At this level there's no difference between L1 and L2

    * suspend states. (L2 being original USB 1.1 suspend.)

    */

    };

    2、状态设置函数usb_gadget_set_state()this

    // /drivers/usb/gadget/udc/udc-core.c

    void usb_gadget_set_state(struct usb_gadget *gadget,

    enum usb_device_state state)

    {

    gadget->state = state;

    schedule_work(&gadget->work);

    }

    EXPORT_SYMBOL_GPL(usb_gadget_set_state);

    // /include/linux/usb/gadget.h

    extern void usb_gadget_set_state(struct usb_gadget *gadget, enum usb_device_state state);

    在 udc-core.c 文件中,会去定义usb_gadget_set_state()函数,将状态state的值赋值给gadget->state。其中struct usb_gadget是用来标记一个USB设备的信息。此时USB设备的状态就能够肯定了。以后启动工做队列schedule_work(&gadget->work);将状态信息给到sysfs。code

    在USB的枚举阶段,会根据USB所处的状态调用usb_gadget_set_state()去设置USB设备的状态。

    好比说在USB设备的枚举阶段,在composite_setup()函数中USB设备接收到了USB Host发过来的USB_REQ_SET_CONFIGURATION命令后调用set_config()设置相应的配置,这以后就会调用usb_gadget_set_state()去设置为USB_STATE_CONFIGURED状态。orm

    3、usb_gadget_state_work()

    // /drivers/usb/gadget/udc/udc-core.c

    * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list

    * @parent: the parent device to this udc. Usually the controller driver's

    * device.

    * @gadget: the gadget to be added to the list.

    * @release: a gadget release function.

    *

    * Returns zero on success, negative errno otherwise.

    */

    int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,

    void (*release)(struct device *dev))

    在usb_add_gadget_udc_release()中会去绑定 gadget->work 到 usb_gadget_state_work() 函数。blog

    static void usb_gadget_state_work(struct work_struct *work)

    {

    struct usb_gadget *gadget = work_to_gadget(work);

    struct usb_udc *udc = gadget->udc;

    if (udc)

    sysfs_notify(&udc->dev.kobj, NULL, "state");

    }

    这个函数主要目的就是将当前的 state 信息写入到 sysfs 中去。这个信息能够cat出来。token

    #cat /sys/devices/platform/xxx_udc/state

    路径不彻底是这个,可是在 /sys/devices 目录下会有对应udc控制器 xxx_udc 的状态节点。不只包含状态的节点,还包含其余的信息。队列

    -r--r--r-- 0 0 4096 2017-05-01 16:17 a_alt_hnp_support

    -r--r--r-- 0 0 4096 2017-05-01 16:17 a_hnp_support

    -r--r--r-- 0 0 4096 2017-05-01 16:17 b_hnp_enable

    -r--r--r-- 0 0 4096 2017-05-01 16:17 current_speed

    lrwxrwxrwx 0 0 2017-05-01 16:17 device -> ../../../panasonic_udc.1

    -r--r--r-- 0 0 4096 2017-05-01 16:17 is_a_peripheral

    -r--r--r-- 0 0 4096 2017-05-01 16:17 is_otg

    -r--r--r-- 0 0 4096 2017-05-01 16:17 maximum_speed

    drwxr-xr-x 0 0 2017-05-01 16:17 power

    --w------- 0 0 4096 2017-05-01 16:17 soft_connect

    --w------- 0 0 4096 2017-05-01 16:17 srp

    -r--r--r-- 0 0 4096 2017-05-01 16:17 state

    lrwxrwxrwx 0 0 2017-05-01 16:17 subsystem -> ../../../../../class/udc

    -rw-r--r-- 0 0 4096 2017-05-01 16:17 uevent

    这里面的信息其实就是一个USB设备的信息,用 struct usb_gadget 来描述。关于USB Gadget的内容将在后续的文章中整理出来。

    展开全文
  • usb_gadget

    2012-04-01 07:51:38
    数据结构usb_gadget
  • USB设备状态设置-- usb_gadget_set_state()

    千次阅读 2017-07-22 13:08:06
    一、USB设备状态在USB 2.0协议中第 9.1 USB Device States 章节规定了USB设备的6种状态,包括: Attached/Powered/Default/Address/Configured/Suspended其状态迁移图如下: 在 Linux Kernel ch9.h 文件中用 enum ...

    一、USB设备状态

    在USB 2.0协议中第 9.1 USB Device States 章节规定了USB设备的6种状态,包括:
    Attached/Powered/Default/Address/Configured/Suspended

    其状态迁移图如下:
    USB设备状态迁移

    在 Linux Kernel ch9.h 文件中用 enum usb_device_state 来标记这几种状态。

    // <kernel_dir>/include/uapi/linux/usb/ch9.h
    
    enum usb_device_state {
        /* NOTATTACHED isn't in the USB spec, and this state acts
         * the same as ATTACHED ... but it's clearer this way.
         */
        USB_STATE_NOTATTACHED = 0,
    
        /* chapter 9 and authentication (wireless) device states */
        USB_STATE_ATTACHED,
        USB_STATE_POWERED,          /* wired */
        USB_STATE_RECONNECTING,         /* auth */
        USB_STATE_UNAUTHENTICATED,      /* auth */
        USB_STATE_DEFAULT,          /* limited function */
        USB_STATE_ADDRESS,
        USB_STATE_CONFIGURED,           /* most functions */
    
        USB_STATE_SUSPENDED
    
        /* NOTE:  there are actually four different SUSPENDED
         * states, returning to POWERED, DEFAULT, ADDRESS, or
         * CONFIGURED respectively when SOF tokens flow again.
         * At this level there's no difference between L1 and L2
         * suspend states.  (L2 being original USB 1.1 suspend.)
         */
    };

    二、状态设置函数usb_gadget_set_state()

    // <kernel_dir>/drivers/usb/gadget/udc/udc-core.c
    
    void usb_gadget_set_state(struct usb_gadget *gadget,
            enum usb_device_state state)
    {
        gadget->state = state;
        schedule_work(&gadget->work);
    }
    EXPORT_SYMBOL_GPL(usb_gadget_set_state);
    
    // <kernel_dir>/include/linux/usb/gadget.h
    extern void usb_gadget_set_state(struct usb_gadget *gadget,  enum usb_device_state state);

    在 udc-core.c 文件中,会去定义usb_gadget_set_state()函数,将状态state的值赋值给gadget->state其中struct usb_gadget是用来标记一个USB设备的信息。此时USB设备的状态就可以确定了。之后启动工作队列schedule_work(&gadget->work);将状态信息给到sysfs。

    在USB的枚举阶段,会根据USB所处的状态调用usb_gadget_set_state()去设置USB设备的状态。
    比如说在USB设备的枚举阶段,在composite_setup()函数中USB设备接收到了USB Host发过来的USB_REQ_SET_CONFIGURATION命令后调用set_config()设置相应的配置,这之后就会调用usb_gadget_set_state()去设置为USB_STATE_CONFIGURED状态。

    三、usb_gadget_state_work()

    // <kernel_dir>/drivers/usb/gadget/udc/udc-core.c
    
    * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
     * @parent: the parent device to this udc. Usually the controller driver's
     * device.
     * @gadget: the gadget to be added to the list.
     * @release: a gadget release function.
     *
     * Returns zero on success, negative errno otherwise.
     */
    int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
            void (*release)(struct device *dev))
    

    usb_add_gadget_udc_release()中会去绑定 gadget->workusb_gadget_state_work() 函数。

    static void usb_gadget_state_work(struct work_struct *work)
    {
        struct usb_gadget *gadget = work_to_gadget(work);
        struct usb_udc *udc = gadget->udc;
    
        if (udc)
            sysfs_notify(&udc->dev.kobj, NULL, "state");
    }

    这个函数主要目的就是将当前的 state 信息写入到 sysfs 中去。这个信息可以cat出来。

    #cat /sys/devices/platform/xxx_udc/state

    路径不完全是这个,但是在 /sys/devices 目录下会有对应udc控制器 xxx_udc 的状态节点。不仅包含状态的节点,还包含其他的信息。

    -r--r--r-- 0        0              4096 2017-05-01 16:17 a_alt_hnp_support
    -r--r--r-- 0        0              4096 2017-05-01 16:17 a_hnp_support
    -r--r--r-- 0        0              4096 2017-05-01 16:17 b_hnp_enable
    -r--r--r-- 0        0              4096 2017-05-01 16:17 current_speed
    lrwxrwxrwx 0        0               2017-05-01 16:17 device -> ../../../panasonic_udc.1
    -r--r--r-- 0        0              4096 2017-05-01 16:17 is_a_peripheral
    -r--r--r-- 0        0              4096 2017-05-01 16:17 is_otg
    -r--r--r-- 0        0              4096 2017-05-01 16:17 maximum_speed
    drwxr-xr-x 0        0                   2017-05-01 16:17 power
    --w------- 0        0              4096 2017-05-01 16:17 soft_connect
    --w------- 0        0              4096 2017-05-01 16:17 srp
    -r--r--r-- 0        0              4096 2017-05-01 16:17 state
    lrwxrwxrwx 0        0                   2017-05-01 16:17 subsystem -> ../../../../../class/udc
    -rw-r--r-- 0        0              4096 2017-05-01 16:17 uevent

    这里面的信息其实就是一个USB设备的信息,用 struct usb_gadget 来描述。关于USB Gadget的内容将在后续的文章中整理出来。

    展开全文
  • gadgetusb_function

    2021-03-17 22:26:25
    gadgetusb_function usb_function /** * struct usb_function - describes one function of a configuration * @name: For diagnostics, identifies the function. * @strings: tables of strings, keyed by ...

    gadget之usb_function

    usb_function

    
    /**
     * struct usb_function - describes one function of a configuration
     * @name: For diagnostics, identifies the function.
     * @strings: tables of strings, keyed by identifiers assigned during bind()
     *	and by language IDs provided in control requests
     * @fs_descriptors: Table of full (or low) speed descriptors, using interface and
     *	string identifiers assigned during @bind().  If this pointer is null,
     *	the function will not be available at full speed (or at low speed).
     * @hs_descriptors: Table of high speed descriptors, using interface and
     *	string identifiers assigned during @bind().  If this pointer is null,
     *	the function will not be available at high speed.
     * @ss_descriptors: Table of super speed descriptors, using interface and
     *	string identifiers assigned during @bind(). If this
     *	pointer is null after initiation, the function will not
     *	be available at super speed.
     * @ssp_descriptors: Table of super speed plus descriptors, using
     *	interface and string identifiers assigned during @bind(). If
     *	this pointer is null after initiation, the function will not
     *	be available at super speed plus.
     * @config: assigned when @usb_add_function() is called; this is the
     *	configuration with which this function is associated.
     * @os_desc_table: Table of (interface id, os descriptors) pairs. The function
     *	can expose more than one interface. If an interface is a member of
     *	an IAD, only the first interface of IAD has its entry in the table.
     * @os_desc_n: Number of entries in os_desc_table
     * @bind: Before the gadget can register, all of its functions bind() to the
     *	available resources including string and interface identifiers used
     *	in interface or class descriptors; endpoints; I/O buffers; and so on.
     * @unbind: Reverses @bind; called as a side effect of unregistering the
     *	driver which added this function.
     * @free_func: free the struct usb_function.
     * @mod: (internal) points to the module that created this structure.
     * @set_alt: (REQUIRED) Reconfigures altsettings; function drivers may
     *	initialize usb_ep.driver data at this time (when it is used).
     *	Note that setting an interface to its current altsetting resets
     *	interface state, and that all interfaces have a disabled state.
     * @get_alt: Returns the active altsetting.  If this is not provided,
     *	then only altsetting zero is supported.
     * @disable: (REQUIRED) Indicates the function should be disabled.  Reasons
     *	include host resetting or reconfiguring the gadget, and disconnection.
     * @setup: Used for interface-specific control requests.
     * @req_match: Tests if a given class request can be handled by this function.
     * @suspend: Notifies functions when the host stops sending USB traffic.
     * @resume: Notifies functions when the host restarts USB traffic.
     * @get_status: Returns function status as a reply to
     *	GetStatus() request when the recipient is Interface.
     * @func_suspend: callback to be called when
     *	SetFeature(FUNCTION_SUSPEND) is reseived
     *
     * A single USB function uses one or more interfaces, and should in most
     * cases support operation at both full and high speeds.  Each function is
     * associated by @usb_add_function() with a one configuration; that function
     * causes @bind() to be called so resources can be allocated as part of
     * setting up a gadget driver.  Those resources include endpoints, which
     * should be allocated using @usb_ep_autoconfig().
     *
     * To support dual speed operation, a function driver provides descriptors
     * for both high and full speed operation.  Except in rare cases that don't
     * involve bulk endpoints, each speed needs different endpoint descriptors.
     *
     * Function drivers choose their own strategies for managing instance data.
     * The simplest strategy just declares it "static', which means the function
     * can only be activated once.  If the function needs to be exposed in more
     * than one configuration at a given speed, it needs to support multiple
     * usb_function structures (one for each configuration).
     *
     * A more complex strategy might encapsulate a @usb_function structure inside
     * a driver-specific instance structure to allows multiple activations.  An
     * example of multiple activations might be a CDC ACM function that supports
     * two or more distinct instances within the same configuration, providing
     * several independent logical data links to a USB host.
     */
    //描述一个配置的一个功能
    struct usb_function {
    	const char			*name;//功能名称,匹配时需要用到
    	struct usb_gadget_strings	**strings;//string数组,通过bind中分配的id访问
    	struct usb_descriptor_header	**fs_descriptors;//全速和低速的描述符表,用于bind中分配的接口描述符和string描述符
    	struct usb_descriptor_header	**hs_descriptors;//高速描述符表
    	struct usb_descriptor_header	**ss_descriptors;
    	struct usb_descriptor_header	**ssp_descriptors;
    
    	struct usb_configuration	*config;//调用usb_add_function()函数赋值,是这个功能关联的配置描述符
    
    	struct usb_os_desc_table	*os_desc_table;
    	unsigned			os_desc_n;
    
    	/* REVISIT:  bind() functions can be marked __init, which
    	 * makes trouble for section mismatch analysis.  See if
    	 * we can't restructure things to avoid mismatching.
    	 * Related:  unbind() may kfree() but bind() won't...
    	 */
    
    	/* configuration management:  bind/unbind */
    	int			(*bind)(struct usb_configuration *,
    					struct usb_function *);/*unbind的逆操作*/
    	void			(*unbind)(struct usb_configuration *,
    					struct usb_function *);
    	void			(*free_func)(struct usb_function *f);
    	struct module		*mod;
    
    	/* runtime state management */
    	int			(*set_alt)(struct usb_function *,
    					unsigned interface, unsigned alt);
    	int			(*get_alt)(struct usb_function *,
    					unsigned interface);
    	void			(*disable)(struct usb_function *);
    	int			(*setup)(struct usb_function *,
    					const struct usb_ctrlrequest *);
    	bool			(*req_match)(struct usb_function *,
    					const struct usb_ctrlrequest *,
    					bool config0);
    	void			(*suspend)(struct usb_function *);
    	void			(*resume)(struct usb_function *);
    
    	/* USB 3.0 additions */
    	int			(*get_status)(struct usb_function *);
    	int			(*func_suspend)(struct usb_function *,
    						u8 suspend_opt);
    	/* private: */
    	/* internals */
    	struct list_head		list;
    	DECLARE_BITMAP(endpoints, 32);
    	const struct usb_function_instance *fi;
    
    	unsigned int		bind_deactivated:1;
    };
    
    

    usb_function_driver

    struct usb_function_driver {
    	const char *name;//usb_function_driver的name,如:"acm"
    	struct module *mod;
    	struct list_head list;
    	struct usb_function_instance *(*alloc_inst)(void);//alloc usb_function_instance
    	struct usb_function *(*alloc_func)(struct usb_function_instance *inst);//alloc usb_function
    };
    

    创建usb_function_driver
    源码:include/linux/usb/composite.h

    #define DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)		\
    	static struct usb_function_driver _name ## usb_func = {		\
    		.name = __stringify(_name),				\
    		.mod  = THIS_MODULE,					\
    		.alloc_inst = _inst_alloc,				\
    		.alloc_func = _func_alloc,				\
    	};								\
    	MODULE_ALIAS("usbfunc:"__stringify(_name));
    

    注册usb_function_driver
    源码:include/linux/usb/composite.h

    #define DECLARE_USB_FUNCTION_INIT(_name, _inst_alloc, _func_alloc)	\
    	DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)		\
    	static int __init _name ## mod_init(void)			\
    	{								\
    		return usb_function_register(&_name ## usb_func);	\
    	}								\
    	static void __exit _name ## mod_exit(void)			\
    	{								\
    		usb_function_unregister(&_name ## usb_func);		\
    	}								\
    	module_init(_name ## mod_init);					\
    	module_exit(_name ## mod_exit)
    

    源码:drivers/usb/gadget/functions.c

    int usb_function_register(struct usb_function_driver *newf)
    {
    	struct usb_function_driver *fd;
    	int ret;
    
    	ret = -EEXIST;
    
    	mutex_lock(&func_lock);
    	//遍历func_list链表,根据func_name判断该func是否注册
    	list_for_each_entry(fd, &func_list, list) {
    		if (!strcmp(fd->name, newf->name))
    			goto out;
    	}
    	ret = 0;
    	//将new_func添加到func_list中
    	list_add_tail(&newf->list, &func_list);
    out:
    	mutex_unlock(&func_lock);
    	return ret;
    }
    EXPORT_SYMBOL_GPL(usb_function_register);
    
    void usb_function_unregister(struct usb_function_driver *fd)
    {
    	mutex_lock(&func_lock);
    	list_del(&fd->list);
    	mutex_unlock(&func_lock);
    }
    EXPORT_SYMBOL_GPL(usb_function_unregister);
    

    示例:以acm function为例说明,如下:

    源码:drivers/usb/gadget/function/f_acm.c

    DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func);
    

    usb_function_instance

    源码:include/linux/usb/composite.h

    struct usb_function_instance {
    	struct config_group group;
    	struct list_head cfs_list;
    	struct usb_function_driver *fd;
    	int (*set_inst_name)(struct usb_function_instance *inst,
    			      const char *name);
    	void (*free_func_inst)(struct usb_function_instance *inst);
    };
    
    展开全文
  • 一、简介  目前正在做的项目的那部分是将SOC... 测试的原理是这样的,在主机端有usbtest内核模块,他是一个专用于测试的usb主机上的设备驱动,该模块通过ioctl接口提供了各种测试类型,比如Simple non-queued b
  • usb gadget configfs 验证

    2020-09-06 09:51:52
    1、必须打开CONFIG_CONFIGFS_FS和CONFIG_USB_LIBCOMPOSITE的宏,前者为用户空间提供访问配置内核驱动的configfs文件系统,后者提供usb gadget composite框架; 2、必须打开UDC(USB Device Controller)的配置,这个是...
  • 开始写usb gadget驱动

    2019-09-21 14:28:21
    主要填充usb_driver数据结构, 主要的包括id_table为设备-驱动匹配的依据(如pid, vid或class, protocol等), 其次就是probe, disconnect等回调函数, probe即匹配驱动后的探测函数, 需要做class...
  • USB Gadget软件结构总共分为三层,其软件架构图如下 一. UDC层  这一层是与硬件相关层。相关文件ambarella_udc.c ambarella_udc.h。ambarella设备控制器作为一个linux设备在这一层是作为platform...
  • 16.5 USB OTG驱动 OTG是On-The-Go的缩写,是近年来发展的技术,2001年12月18日由USB Implementers Forum公布,主要应用于各种不同的设备或移动设备之间的联接,进行数据交换。 特别是Pad、移动电话、消费类设备。...
  • 16.4.1 UDC(USB设备控制器)和Gadget(小配件)驱动的关键数据结构与API USB设备控制器(UDC)驱动指的是作为其他USB主机控制器外设的USB硬件设备上底层硬件控制器的驱动,该硬件和驱动负责将一个USB设备依附于一...
  • usb-gadget-configfs 的使用

    千次阅读 2020-09-29 11:24:59
    usb gadget configfs 的使用 挂载 mount -t configfs none /sys/kernel/config 挂载路径自定,上面命令挂载在 /sys/kernel/config 目录下 挂载后的目录结构如下,configfs自动生成usb_gadget目录 config | ----...
  • Android_Gadget_CDC_driver

    热门讨论 2013-02-20 17:03:17
    Android_Gadget_CDC_driver 驱动 安卓 智能机 Android 智能机驱动 下载版本驱动
  • 单独配置UAC和UVC都可以生效,配置为复合设备时,UAC不生效 试了下RNDIS和UAC复合,也是不生效的,请问需要放开什么配置或者修改内核代码吗
  • 内核gadget驱动主要有两个作用,第一是实现真实usb从设备,常见的UAC、UVC、大容量存储设备等;第二是虚拟一些USB设备,例如Hub、光驱、键盘等。本文作为Linux USB Gadget驱动的第一篇,先介绍下如gadget驱动做简单...
  • USB gadget configfs模式的使用: 即可android或linux在用户空间配置实现设备终端为HID,U盘、Adb以及cdc等功能 1、创建gadgets 每个gadget都必须创建自己相应的目录以及自己的PID和VID mkdir $CONFIGFS_HOME/usb_...
  • USB gadget设备驱动解析

    千次阅读 2018-03-28 09:22:59
    USB gadget设备驱动解析(1)——功能体验利用Linux USB gadget设备驱动可以实现一些比较有意思的功能,举两个例子: 1、一个嵌入式产品中的某个存储设备,或是一个存储设备的某个分区,可以作为一个U盘被PC;...
  • linux usb gadget驱动详解(三)

    千次阅读 2019-07-29 14:54:05
    本文将对linux4.4.19版本usb gadget源码进行简单分析。鉴于前文反复测试U盘设备驱动,现从linux-4.4.19/drivers/usb/gadget/legacy/mass_storage.c开始分析。 目的是了解U盘设备驱动的工作原理,为啥它能让PC识别...
  • 使用configfs配置usb gadget设备

    千次阅读 2019-09-18 15:41:40
    Linux支持usb主机驱动, 同时也支持从设备驱动。 其主要使用gadget api框架实现。 软件一般分为三个层次, 1. gadget function 对应于usb ...2. gadget api(framework) 即linux提供的usb gadget驱动框架 3. UDC Dri...
  • ln -s /sys/kernel/config/usb_gadget/rockchip/functions/mass_storage.usb0 /sys/kernel/config/usb_gadget/rockchip/configs/b.1/ fi if [ $MTP_EN = on ];then mkdir /sys/kernel/config/usb_gadget/...
  • usb gadget g_webcam uvc gadget调试

    千次阅读 2017-07-20 15:30:30
    调试 usb gadget webcam时的记录: 1. 加载webcam驱动 2. 从http://git.ideasonboard.org/uvc-gadget.git下载 uvc应用层的代码,编译 3. 执行uvc_gadget时发现一直提示 iotrl 错误,原来使用的交叉编译器中的内核...
  • static struct usb_gadget_strings string_table = { .language = 0x0409, /* en-us */ .strings = strings, }; static void free_ep_req(struct usb_ep *ep, struct usb_request *req) { kfree(req->buf); usb...
  • linux usb gadget驱动详解(二)

    千次阅读 2019-07-28 15:18:23
    在上篇《linux usb gadget驱动详解(一)》中,我们了解到gadget的测试方法,但在最后,我们留下一个问题,就是怎样使用新的方法进行usb gadget驱动测试。 我们发现linux的文档是宝库! 这篇文章的测试方法主要...
  • usb hid gadget驱动

    千次阅读 2016-10-31 10:13:37
    usb gadget框架层次 1 驱动层 2 复合层 3 控制器驱动层 二 初始化流程 1 驱动层介绍 2 hidg驱动初始化详解 1 至上而下遍历搜索绑定驱动和设备 2 至下而上遍历完成初始化 三 hid gadget应用参考文献因为usb gadget...
  • linux usb gadget驱动详解(五)

    千次阅读 2020-07-04 12:46:40
    现从fsg_bind()讲起。 //不失一般性,删掉错误处理和configfs相关代码 static int fsg_bind(struct usb_configuration *c, struct usb_function *f) ... struct usb_gadget *gadget = c->cdev-...
  • Linux_USB_gadget设备驱动

    2016-10-10 14:53:09
    http://wenku.baidu.com/link?url=tEAEptNzFst1s0wgrLFu4jI2bzvnGDN8wCRywsIDUOiZ6vrGL-iU_tk4H5ZFgFELXHk4FcGPz07yIWYum41dhlwvJGer22jR-tC5YCDdstO

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,822
精华内容 1,928
关键字:

usb_gadget