gadget之usb_gadget

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);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值