gadget就是指一些比较杂的小设备,gadget类的一定是作为usb device用。
前面一篇提到usb作为device的情况,注册完成后,导出usb_gadget_probe_driver函数后就完了。
这个函数就是为gadget驱动准备的,这就要从gadget/android.c开始分析,先从它的init函数看起:
static int __init init(void) { struct android_dev *dev; int err; 。。。。。。 android_class = class_create(THIS_MODULE, "android_usb"); if (IS_ERR(android_class)) return PTR_ERR(android_class); dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; dev->functions = supported_functions; INIT_LIST_HEAD(&dev->enabled_functions); INIT_WORK(&dev->work, android_work); err = android_create_device(dev); if (err) { class_destroy(android_class); kfree(dev); return err; } _android_dev = dev; /* Override composite driver functions */ composite_driver.setup = android_setup; composite_driver.disconnect = android_disconnect; return usb_composite_probe(&android_usb_driver, android_bind); }
static struct android_usb_function *supported_functions[] = { &adb_function, &acm_function, &mtp_function, &ptp_function, &rndis_function, &mass_storage_function, &accessory_function, NULL };
不管上述何种设备,都是把它们模拟成一个usb从设备来看待,所以必须要有端点0作为控制传输、还要有其它非零端点用来传输数据。
刚好A10 CPU的usb otg 口有一个控制传输端点,4个批量传输端点和一个中断传输端点,可以符合上述的要求。
所以android.c、composite.c 的作用就是依据USB协议模拟出端点0、设备描述符等一个usb设备枚举过程所要求的功能;至于这个usb设备具体做什么,那就是由接口描述符和端点的功能决定,所以f_mtp.c、f_accessory.c、f_mass_storage.c、f_adb.c、f_acm.c等文件所做的事情的就是实现具体接口和这个接口下的端点的具体功能。
android_usb_driver代表了一个设备描述符所要具备的信息和响应的动作:
static struct usb_composite_driver android_usb_driver = { .name = "android_usb", .dev = &device_desc, .strings = dev_strings, .unbind = android_usb_unbind, };
device_desc类型为usb_device_descriptor,定义如下:
static struct usb_device_descriptor device_desc = { .bLength = sizeof(device_desc), .bDescriptorType = USB_DT_DEVICE, .bcdUSB = __constant_cpu_to_le16(0x0200), .bDeviceClass = USB_CLASS_PER_INTERFACE, .idVendor = __constant_cpu_to_le16(VENDOR_ID), .idProduct = __constant_cpu_to_le16(PRODUCT_ID), .bcdDevice = __constant_cpu_to_le16(0xffff), .bNumConfigurations = 1, };
接着usb_composite_probe注册一个usb_composite_driver到composite.c 中,如果这一步能注册成功,那么gadget驱动就已经准备好了,随时可以相应主机的请求:
int usb_composite_probe(struct usb_composite_driver *driver, int (*bind)(struct usb_composite_dev *cdev)) { if (!driver || !driver->dev || !bind || composite) return -EINVAL; if (!driver->name) driver->name = "composite"; if (!driver->iProduct) driver->iProduct = driver->name; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; composite = driver; composite_gadget_bind = bind; return usb_gadget_probe_driver(&composite_driver, composite_bind); }
static struct usb_gadget_driver composite_driver = { .speed = USB_SPEED_HIGH, .unbind = composite_unbind, .setup = composite_setup, .disconnect = composite_disconnect, .suspend = composite_suspend, .resume = composite_resume, .driver = { .owner = THIS_MODULE, }, };
简单的将driver和bind的值保存下来后调用。
usb_gadget_probe_driver函数就是在具体平台中定义的。前面一篇文章说过,这是导出来给gadget驱动用的,它是在usb/sun4i_usb/udc/sw_udc.c中:
int usb_gadget_probe_driver(struct usb_gadget_driver *driver, int (*bind)(struct usb_gadget *)) { 。。。。。。 if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) { DMSG_PANIC("ERR: Invalid driver: bind %p setup %p speed %d\n", bind, driver->setup, driver->speed); return -EINVAL; } 。。。。。。 /* Bind the driver */ if ((retval = device_add(&udc->gadget.dev)) != 0) { DMSG_PANIC("ERR: Error in device_add() : %d\n",retval); goto register_error; } DMSG_INFO_UDC("[%s]: binding gadget driver '%s'\n", gadget_name, driver->driver.name); if ((retval = bind (&udc->gadget)) != 0) { DMSG_PANIC("ERR: Error in bind() : %d\n",retval); device_del(&udc->gadget.dev); goto register_error; }
static int composite_bind(struct usb_gadget *gadget) { struct usb_composite_dev *cdev; int status = -ENOMEM; cdev = kzalloc(sizeof *cdev, GFP_KERNEL); if (!cdev) return status; spin_lock_init(&cdev->lock); cdev->gadget = gadget; set_gadget_data(gadget, cdev); INIT_LIST_HEAD(&cdev->configs); /* preallocate control response and buffer */ cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); if (!cdev->req) goto fail; cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL); if (!cdev->req->buf) goto fail; cdev->req->complete = composite_setup_complete; gadget->ep0->driver_data = cdev; 。。。。。。 if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW) usb_gadget_set_selfpowered(gadget); /* interface and string IDs start at zero via kzalloc. * we force endpoints to start unassigned; few controller * drivers will zero ep->driver_data. */ usb_ep_autoconfig_reset(cdev->gadget); /* composite gadget needs to assign strings for whole device (like * serial number), register function drivers, potentially update * power state and consumption, etc */ status = composite_gadget_bind(cdev); 。。。。。。 /* standardized runtime overrides for device ID data */ if (idVendor) cdev->desc.idVendor = cpu_to_le16(idVendor); if (idProduct) cdev->desc.idProduct = cpu_to_le16(idProduct); if (bcdDevice) cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); /* string overrides */ if (iManufacturer || !cdev->desc.iManufacturer) { if (!iManufacturer && !composite->iManufacturer && !*composite_manufacturer) snprintf(composite_manufacturer, sizeof composite_manufacturer, "%s %s with %s", init_utsname()->sysname, init_utsname()->release, gadget->name); cdev->manufacturer_override = override_id(cdev, &cdev->desc.iManufacturer); } if (iProduct || (!cdev->desc.iProduct && composite->iProduct)) cdev->product_override = override_id(cdev, &cdev->desc.iProduct); if (iSerialNumber) cdev->serial_override = override_id(cdev, &cdev->desc.iSerialNumber); 。。。。。。 }首先认识usb_gadget这个结构体,这是具体平台定义的gadget资源,在sun4i_usb/udc/sw_udc.c中:
static struct sw_udc sw_udc = { .gadget = { .ops = &sw_udc_ops, .ep0 = &sw_udc.ep[0].ep, .name = gadget_name, .dev = { .init_name = "gadget", }, }, /* control endpoint */ .ep[0] = { .num = 0, .ep = { .name = ep0name, .ops = &sw_udc_ep_ops, .maxpacket = EP0_FIFO_SIZE, }, .dev = &sw_udc, }, /* first group of endpoints */ .ep[1] = { .num = 1, .ep = { .name = "ep1-bulk", .ops = &sw_udc_ep_ops, .maxpacket = SW_UDC_EP_FIFO_SIZE, }, .dev = &sw_udc, .fifo_size = (SW_UDC_EP_FIFO_SIZE * (SW_UDC_FIFO_NUM + 1)), .bEndpointAddress = 1, .bmAttributes = USB_ENDPOINT_XFER_BULK, }, 。。。。。。 .ep[5] = { .num = 5, .ep = { .name = "ep5-int", .ops = &sw_udc_ep_ops, .maxpacket = SW_UDC_EP_FIFO_SIZE, }, .dev = &sw_udc, .fifo_size = (SW_UDC_EP_FIFO_SIZE * (SW_UDC_FIFO_NUM + 1)), .bEndpointAddress = 5, .bmAttributes = USB_ENDPOINT_XFER_INT, }, };一个端点0,4个bulk和一个int传输全部定义在这里,他们的ops指针都指向同一个sw_udc_ep_ops:
static const struct usb_ep_ops sw_udc_ep_ops = { .enable = sw_udc_ep_enable, .disable = sw_udc_ep_disable, .alloc_request = sw_udc_alloc_request, .free_request = sw_udc_free_request, .queue = sw_udc_queue, .dequeue = sw_udc_dequeue, .set_halt = sw_udc_set_halt, };
static int android_bind(struct usb_composite_dev *cdev) { struct android_dev *dev = _android_dev; struct usb_gadget *gadget = cdev->gadget; int gcnum, id, ret; usb_gadget_disconnect(gadget); ret = android_init_functions(dev->functions, cdev); 。。。。。。 usb_gadget_set_selfpowered(gadget); dev->cdev = cdev; return 0; }
好像到这里就完成了,都是注册并填充了一些数据、方法等,那何时才相应主机的请求呢?有中断到来的时候。
在sun4i_usb/udc/sw_udc.c中,中断到来就表示主机有请求了,会调用注册的中断函数sw_udc_irq:
static irqreturn_t sw_udc_irq(int dummy, void *_dev) { 。。。。。。 if (tx_irq & USBC_INTTx_FLAG_EP0) { DMSG_DBG_UDC("USB ep0 irq\n"); /* Clear the interrupt bit by setting it to 1 */ USBC_INT_ClearEpPending(g_sw_udc_io.usb_bsp_hdle, USBC_EP_TYPE_TX, 0); if(dev->gadget.speed == USB_SPEED_UNKNOWN){ if(USBC_Dev_QueryTransferMode(g_sw_udc_io.usb_bsp_hdle) == USBC_TS_MODE_HS){ dev->gadget.speed = USB_SPEED_HIGH; }else{ dev->gadget.speed= USB_SPEED_FULL; } } sw_udc_handle_ep0(dev); } 。。。。。。 /* tx endpoint data transfers */ for (i = 1; i < SW_UDC_ENDPOINTS; i++) { u32 tmp = 1 << i; if (tx_irq & tmp) { DMSG_DBG_UDC("USB tx ep%d irq\n", i); /* Clear the interrupt bit by setting it to 1 */ USBC_INT_ClearEpPending(g_sw_udc_io.usb_bsp_hdle, USBC_EP_TYPE_TX, i); sw_udc_handle_ep(&dev->ep[i]); } } /* rx endpoint data transfers */ for (i = 1; i < SW_UDC_ENDPOINTS; i++) { u32 tmp = 1 << i; if (rx_irq & tmp) { DMSG_DBG_UDC("USB rx ep%d irq\n", i); /* Clear the interrupt bit by setting it to 1 */ USBC_INT_ClearEpPending(g_sw_udc_io.usb_bsp_hdle, USBC_EP_TYPE_RX, i); sw_udc_handle_ep(&dev->ep[i]); } } 。。。。。。 }
static int android_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c) { 。。。。。。 list_for_each_entry(f, &dev->enabled_functions, enabled_list) { if (f->ctrlrequest) { value = f->ctrlrequest(f, cdev, c); if (value >= 0) break; } } 。。。。。。 /* Special case the accessory function. * It needs to handle control requests before it is enabled. */ if (value < 0) value = acc_ctrlrequest(cdev, c); if (value < 0) value = composite_setup(gadget, c); spin_lock_irqsave(&cdev->lock, flags); if (!dev->connected) { dev->connected = 1; schedule_work(&dev->work); } else if (c->bRequest == USB_REQ_SET_CONFIGURATION && cdev->config) { schedule_work(&dev->work); } spin_unlock_irqrestore(&cdev->lock, flags); return value; }
如果acc_ctrlrequest方法无法处理,最终调用composite_setup来处理,它会相应主机的获取描述符,设置地址等请求。比如获取或者设置接口描述符也在这里完成:
case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) break; f = cdev->config->interface[intf]; if (!f) break; if (w_value && !f->set_alt) break; value = f->set_alt(f, w_index, w_value); if (value == USB_GADGET_DELAYED_STATUS) { DBG(cdev, "%s: interface %d (%s) requested delayed status\n", __func__, intf, f->name); cdev->delayed_status++; DBG(cdev, "delayed_status count %d\n", cdev->delayed_status); } break; case USB_REQ_GET_INTERFACE: if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) goto unknown; if (!cdev->config || intf >= MAX_CONFIG_INTERFACES) break; f = cdev->config->interface[intf]; if (!f) break; /* lots of interfaces only need altsetting zero... */ value = f->get_alt ? f->get_alt(f, w_index) : 0; if (value < 0) break; *((u8 *)req->buf) = value; value = min(w_length, (u16) 1); break;