USB子系统gadget analyse
struct usb_gadget_driver { char *function; enum usb_device_speed speed; 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 *); /* FIXME support safe rmmod */ struct device_driver driver; }; struct s3c2410_udc {spinlock_t lock;struct s3c2410_ep ep[S3C2410_ENDPOINTS];int address;struct usb_gadget gadget;struct usb_gadget_driver *driver;struct s3c2410_request fifo_req;u8 fifo_buf[EP_FIFO_SIZE];u16 devstatus;u32 port_status;int ep0state;unsigned got_irq : 1;unsigned req_std : 1;unsigned req_config : 1;unsigned req_pending : 1;u8 vbus;struct dentry *regs_info;}; USB从设备测分析. 首先我们要知道把usb 运行于client角色时, 它的USB控制器是运行在otg模式, USB OTG标准在完全兼容USB2.0标准的基础之上, 它允许设备既可以做为主机, 也可作为外设操作, 而此时控制USB设备控制器的驱动称之为UDC驱动, 我们记得HOST模式下控制USB设备控制器的是:USB主机控制器驱动. 这些概念比较多.只要我们理清楚就容易理解了. UDC之上就是Gadget api .再之上就是gadeget 驱动. USB OTG的设备控制器被抽象为:" struct s3c2410_udc { spinlock_t lock; struct s3c2410_ep ep[S3C2410_ENDPOINTS]; int address; struct usb_gadget gadget; struct usb_gadget_driver *driver; struct s3c2410_request fifo_req; u8 fifo_buf[EP_FIFO_SIZE]; u16 devstatus; u32 port_status; int ep0state; unsigned got_irq : 1; unsigned req_std : 1; unsigned req_config : 1; unsigned req_pending : 1; u8 vbus; struct dentry *regs_info; }; /*---------------------------------------------------------------------------*/ static struct s3c2410_udc memory = { .gadget = { .ops = &s3c2410_ops, .ep0 = &memory.ep[0].ep, .name = gadget_name, .dev = { .init_name = "gadget", }, }, /* control endpoint */ .ep[0] = { .num = 0, .ep = { .name = ep0name, .ops = &s3c2410_ep_ops, .maxpacket = EP0_FIFO_SIZE, }, .dev = &memory, }, /* first group of endpoints */ .ep[1] = { .num = 1, .ep = { .name = "ep1-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, .bEndpointAddress = 1, .bmAttributes = USB_ENDPOINT_XFER_BULK, }, .ep[2] = { .num = 2, .ep = { .name = "ep2-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, .bEndpointAddress = 2, .bmAttributes = USB_ENDPOINT_XFER_BULK, }, .ep[3] = { .num = 3, .ep = { .name = "ep3-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, .bEndpointAddress = 3, .bmAttributes = USB_ENDPOINT_XFER_BULK, }, .ep[4] = { .num = 4, .ep = { .name = "ep4-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, .bEndpointAddress = 4, .bmAttributes = USB_ENDPOINT_XFER_BULK, } };
usb_add_function .
为configuration 添加一个或一个以上的functions, 添加过程条用@bind 函数.
比如下面添加下面的adb
static int adb_bind_config(struct usb_configuration *c) { struct adb_dev *dev = _adb_dev; printk(KERN_INFO "adb_bind_config\n"); dev->cdev = c->cdev; dev->function.name = "adb"; dev->function.descriptors = fs_adb_descs; dev->function.hs_descriptors = hs_adb_descs; dev->function.bind = adb_function_bind; dev->function.unbind = adb_function_unbind; dev->function.set_alt = adb_function_set_alt; dev->function.disable = adb_function_disable; return usb_add_function(c, &dev->function); }
这里dev->function.bind = adb_function_bind; 把bind函数的进行了赋值
下面在调用
usb_add_function
这个函数时会调用这个bind函数 ,不信往下看
/** * usb_add_function() - add a function to a configuration * @config: the configuration * @function: the function being added * Context: single threaded during gadget setup * * After initialization, each configuration must have one or more * functions added to it. Adding a function involves calling its @bind() * method to allocate resources such as interface and string identifiers * and endpoints. * * This function returns the value of the function's bind(), which is * zero for success else a negative errno value. */ int usb_add_function(struct usb_configuration *config, struct usb_function *function) { int value = -EINVAL; DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", function->name, function, config->label, config); if (!function->set_alt || !function->disable) goto done; function->config = config; list_add_tail(&function->list, &config->functions); /* REVISIT *require* function->bind? */
/*这里就在调用bind 函数就行configuration和 usb_function的绑定*/
if (function->bind) { value = function->bind(config, function); //调用开始 if (value < 0) { list_del(&function->list); function->config = NULL; } } else value = 0; /* We allow configurations that don't work at both speeds. * If we run into a lowspeed Linux system, treat it the same * as full speed ... it's the function drivers that will need * to avoid bulk and ISO transfers. */ if (!config->fullspeed && function->descriptors) config->fullspeed = true; if (!config->highspeed && function->hs_descriptors) config->highspeed = true; if (!config->superspeed && function->ss_descriptors) config->superspeed = true; done: if (value) DBG(config->cdev, "adding '%s'/%p --> %d\n", function->name, function, value); return value; }
看上面的这部分代码,. 就是调用了dev->function.bind = adb_function_bind; 这个函数进行functions 和configuration的绑定.
再看下 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
* @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.
* @config: assigned when @usb_add_function() is called; this is the
* configuration with which this function is associated.
* @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.
* @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.
* @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 recepient 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.
*/