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.
 */

原文地址:https://www.cnblogs.com/yuzaipiaofei/p/4124135.html