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);
}
supported_functions代表了gadget驱动支持的类型,如下:
static struct android_usb_function *supported_functions[] = {
&adb_function,
&acm_function,
&mtp_function,
&ptp_function,
&rndis_function,
&mass_storage_function,
&accessory_function,
NULL
};
他们分别代表adb设备、acm(串口设备)、mtp(ptp的扩展)、ptp(图片传输设备)、rndis(网络设备)、U盘设备、accessory(其他一些小附件)。
不管上述何种设备,都是把它们模拟成一个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);
}
composite_driver代表一个gadget驱动:
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;
}
这里才用device_add将设备添加到设备层, 接着回调bind方法:
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,
};
usb_ep_alloc_request是为端点0分配空间对象,这样才能使用。composite_gadget_bind指针指向了android.c的bind函数:
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;
}
主要是做初始化工作以及为pid、vid赋值等。
好像到这里就完成了,都是注册并填充了一些数据、方法等,那何时才相应主机的请求呢?有中断到来的时候。
在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]);
}
}
。。。。。。
}
主机肯定首先要和ep0通讯的。sw_udc_handle_ep0把请求类型做标记保存下来,最终调用的是dev->driver->setup(&dev->gadget, crq),也就是android.c中的android_setup函数:
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;
}
enabled_list链表的数据,是上层控制的,上层使用到那个功能才会添加到链表中去,anroid系统常使用到的是mass_storage,adb两个。ctrlrequest方法可以不定义,看具体设备而定。
如果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;