Linux gadget 驱动1
来源:互联网 发布:云计算工资多少 编辑:程序博客网 时间:2024/05/17 10:28
为了解决一个问题,简单看了一遍linux gadget驱动的加载流程.做一下记录.
使用的内核为linux 2.6.35 硬件为芯唐NUC950. gadget是在UDC驱动上面的一层,如果要编写gadget驱动只需调用linux 的gadget API,不需设计底层的UDC驱动. 但要是分析驱动BUG,就需要了同时了解一下UDC.
下面以简单的gadget zero驱动分析驱动的加载流程.
主要是一系列的bind的调用,让gadget驱动一步步与硬件的端点联系起来.
从insmod g_zero.ko开始.
zero.c
1 static struct usb_composite_driver zero_driver = {2 .name = "zero",3 .dev = &device_desc,4 .strings = dev_strings,5 .bind = zero_bind,6 .unbind = zero_unbind,7 .suspend = zero_suspend,8 .resume = zero_resume,9 };
这个结构体是zero.c中的,如果是自己写的gadget驱动,这个结构体及这些函数需要自己实现.
先不去细看结构体中的具体内容,现在只关注注册流程.
1 static int __init init(void)2 {3 return usb_composite_register(&zero_driver);4 }
调用
usb_composite_register(&zero_driver);
zero_driver作为参数传递,类型为struct usb_composite_driver
composite.c
int usb_composite_register(struct usb_composite_driver *driver)//zero_driver{ if (!driver || !driver->dev || !driver->bind || composite) return -EINVAL; if (!driver->name) driver->name = "composite"; composite_driver.function = (char *) driver->name; composite_driver.driver.name = driver->name; composite = driver; return usb_gadget_register_driver(&composite_driver);}
composite_driver定义在composite.c中
1 static struct usb_gadget_driver composite_driver = { 2 .speed = USB_SPEED_HIGH, 3 4 .bind = composite_bind, 5 .unbind = composite_unbind, 6 7 .setup = composite_setup, 8 .disconnect = composite_disconnect, 9 10 .suspend = composite_suspend,11 .resume = composite_resume,12 13 .driver = {14 .owner = THIS_MODULE,15 },16 };
composite = driver;
用全局指针指向zero_driver,后面用到compoite这个指针时候知道它的值在这里赋好了.
最后调用usb_gadget_register_driver(&composite_driver);
不同的芯片实现不同,但原理应该类似,一般在xxx_udc.c中
nuc950在nuc900_udc.c中:
1 int usb_gadget_register_driver (struct usb_gadget_driver *driver) 2 { 3 struct nuc900_udc *udc = &controller; 4 int retval; 5 6 7 printk("usb_gadget_register_driver() '%s'\n", driver->driver.name); 8 9 if (!udc)10 return -ENODEV;11 12 if (udc->driver)13 return -EBUSY;14 if (!driver->bind || !driver->unbind || !driver->setup15 || driver->speed == USB_SPEED_UNKNOWN)16 return -EINVAL;17 printk("driver->speed=%d\n", driver->speed);18 udc->gadget.name = gadget_name;19 udc->gadget.ops = &nuc900_ops;20 udc->gadget.is_dualspeed = 1;21 udc->gadget.speed = USB_SPEED_HIGH;//USB_SPEED_FULL;22 udc->ep0state = EP0_IDLE;23 24 udc->gadget.dev.release = nop_release;25 26 udc->driver = driver;27 28 udc->gadget.dev.driver = &driver->driver;29 30 printk( "binding gadget driver '%s'\n", driver->driver.name);31 if ((retval = driver->bind (&udc->gadget)) != 0) {32 printk("bind fail\n");33 udc->driver = 0;34 udc->gadget.dev.driver = 0;35 return retval;36 }37 printk( "after driver bind:%p\n" , driver->bind);38 39 mdelay(300);40 __raw_writel(__raw_readl(REG_PWRON) | 0x400, REG_PWRON);//power on usb D+ high41 42 return 0;43 }
controller是udc中很重要的一个变量,结构为
1 struct nuc900_udc { 2 spinlock_t lock; 3 4 struct nuc900_ep ep[NUC900_ENDPOINTS]; 5 struct usb_gadget gadget; 6 struct usb_gadget_driver *driver; 7 struct platform_device *pdev; 8 9 struct clk *clk;10 struct resource *res;11 void __iomem *reg;12 int irq;13 14 enum ep0_state ep0state;15 16 u8 usb_devstate;17 u8 usb_address;18 19 20 u8 usb_dma_dir;21 22 u8 usb_dma_trigger;//bool. dma triggered23 u8 usb_dma_trigger_next;//need trigger again24 u8 usb_less_mps;25 u32 usb_dma_cnt;//one dma transfer count26 u32 usb_dma_loop;//for short packet only;dma loop, each loop 32byte;27 u32 usb_dma_owner;28 29 struct usb_ctrlrequest crq;30 s32 setup_ret;31 32 u32 irq_enbl;33 };
这个结构中大部分不需要关注,需要关注的是第5行:
struct usb_gadget gadget;
定义在gadget.h中,这linux标准的结构体:
1 struct usb_gadget { 2 /* readonly to gadget driver */ 3 const struct usb_gadget_ops *ops; 4 struct usb_ep *ep0; 5 struct list_head ep_list; /* of usb_ep */ 6 enum usb_device_speed speed; 7 unsigned is_dualspeed:1; 8 unsigned is_otg:1; 9 unsigned is_a_peripheral:1;10 unsigned b_hnp_enable:1;11 unsigned a_hnp_support:1;12 unsigned a_alt_hnp_support:1;13 const char *name;14 struct device dev;15 };
大致先扫一下这个结构,然后回到
usb_gadget_register_driver函数。
大体意思就是对上面的结构体进行了一番赋值,具体意义再回头看
然后在31行调用
if ((retval = driver->bind (&udc->gadget)) != 0)
第一个bind被调用了。
继续贴代码
1 static int composite_bind(struct usb_gadget *gadget) 2 { 3 struct usb_composite_dev *cdev; 4 int status = -ENOMEM; 5 6 cdev = kzalloc(sizeof *cdev, GFP_KERNEL); 7 if (!cdev) 8 return status; 9 10 spin_lock_init(&cdev->lock);11 cdev->gadget = gadget;12 set_gadget_data(gadget, cdev);13 INIT_LIST_HEAD(&cdev->configs);14 15 /* preallocate control response and buffer */16 cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);17 if (!cdev->req)18 goto fail;19 cdev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);20 if (!cdev->req->buf)21 goto fail;22 cdev->req->complete = composite_setup_complete;23 gadget->ep0->driver_data = cdev;24 25 cdev->bufsiz = USB_BUFSIZ;26 cdev->driver = composite;27 28 usb_gadget_set_selfpowered(gadget);29 30 /* interface and string IDs start at zero via kzalloc.31 * we force endpoints to start unassigned; few controller32 * drivers will zero ep->driver_data.33 */34 usb_ep_autoconfig_reset(cdev->gadget);35 36 /* standardized runtime overrides for device ID data */37 if (idVendor)38 cdev->desc.idVendor = cpu_to_le16(idVendor);39 if (idProduct)40 cdev->desc.idProduct = cpu_to_le16(idProduct);41 if (bcdDevice)42 cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);43 44 /* composite gadget needs to assign strings for whole device (like45 * serial number), register function drivers, potentially update46 * power state and consumption, etc47 */48 status = composite->bind(cdev);49 if (status < 0)50 goto fail;51 52 cdev->desc = *composite->dev;53 cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;54 55 /* strings can't be assigned before bind() allocates the56 * releavnt identifiers57 */58 if (cdev->desc.iManufacturer && iManufacturer)59 string_override(composite->strings,60 cdev->desc.iManufacturer, iManufacturer);61 if (cdev->desc.iProduct && iProduct)62 string_override(composite->strings,63 cdev->desc.iProduct, iProduct);64 if (cdev->desc.iSerialNumber && iSerialNumber)65 string_override(composite->strings,66 cdev->desc.iSerialNumber, iSerialNumber);67 68 status = device_create_file(&gadget->dev, &dev_attr_suspended);69 if (status)70 goto fail;71 72 INFO(cdev, "%s ready\n", composite->name);73 return 0;74 75 fail:76 composite_unbind(gadget);77 return status;78 }
还是简单分析
11~12行就是你中有我,我中有你
13行值得注意一下,初始化一个链表,config就是配置链表。
一个设备可能有多个配置
一个配置可能有多个接口
一个接口可能有多个端点或设置
15~23行 都与ep0这个控制端口有关,控制端口的相关内直接在设备bind的时候做也比较合理。
26行 cdev->driver = composite; //还记得composite指向的是谁,就是zero_driver
这就bind好了吧。
直接看48行
status = composite->bind(cdev);
第二个bind被调用,
satic int __init zero_bind(struct usb_composite_dev *cdev)
这个函数需要关注的这几行
if (loopdefault) { loopback_add(cdev, autoresume != 0); sourcesink_add(cdev, autoresume != 0); } else { sourcesink_add(cdev, autoresume != 0); loopback_add(cdev, autoresume != 0); }
应该就是gadget zero的两种配置
sourcesink_add()在f_sourcesink.c中,是自己实现的
在此函数中调用
1 return usb_add_config(cdev, &sourcesink_driver);
1 static struct usb_configuration sourcesink_driver = {2 .label = "source/sink",3 .strings = sourcesink_strings,4 .bind = sourcesink_bind_config,5 .setup = sourcesink_setup,6 .bConfigurationValue = 3,7 .bmAttributes = USB_CONFIG_ATT_SELFPOWER,8 /* .iConfiguration = DYNAMIC */9 };
注意这个结构体中又出现一个bind
usb_add_config 在composite.c 中
1 int usb_add_config(struct usb_composite_dev *cdev, 2 struct usb_configuration *config) 3 { 4 int status = -EINVAL; 5 struct usb_configuration *c; 6 7 DBG(cdev, "adding config #%u '%s'/%p\n", 8 config->bConfigurationValue, 9 config->label, config);10 11 if (!config->bConfigurationValue || !config->bind)12 goto done;13 14 /* Prevent duplicate configuration identifiers */15 list_for_each_entry(c, &cdev->configs, list) {16 if (c->bConfigurationValue == config->bConfigurationValue) {17 status = -EBUSY;18 goto done;19 }20 }21 22 config->cdev = cdev;23 list_add_tail(&config->list, &cdev->configs);24 25 INIT_LIST_HEAD(&config->functions);26 config->next_interface_id = 0;27 28 status = config->bind(config);29 if (status < 0) {30 list_del(&config->list);31 config->cdev = NULL;32 } else {33 unsigned i;34 35 DBG(cdev, "cfg %d/%p speeds:%s%s\n",36 config->bConfigurationValue, config,37 config->highspeed ? " high" : "",38 config->fullspeed39 ? (gadget_is_dualspeed(cdev->gadget)40 ? " full"41 : " full/low")42 : "");43 44 for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {45 struct usb_function *f = config->interface[i];46 47 if (!f)48 continue;49 DBG(cdev, " interface %d = %s/%p\n",50 i, f->name, f);51 }52 }53 54 /* set_alt(), or next config->bind(), sets up55 * ep->driver_data as needed.56 */57 usb_ep_autoconfig_reset(cdev->gadget);58 59 done:60 if (status)61 DBG(cdev, "added config '%s'/%u --> %d\n", config->label,62 config->bConfigurationValue, status);63 return status;64 }
23行,把配置插入链表。(bind设备的时候初始化的那个链表)
25行,又初始化一个function链表。(一个配置可以有多个接口)
28行,status = config->bind(config);
第三次调用bind
找到config->bind的真身,在f_sourcesink.c中
1 static int __init sourcesink_bind_config(struct usb_configuration *c) 2 { 3 struct f_sourcesink *ss; 4 int status; 5 6 ss = kzalloc(sizeof *ss, GFP_KERNEL); 7 if (!ss) 8 return -ENOMEM; 9 init_completion(&ss->gdt_completion);10 ss->function.name = "source/sink";11 ss->function.descriptors = fs_source_sink_descs;12 ss->function.bind = sourcesink_bind;13 ss->function.unbind = sourcesink_unbind;14 ss->function.set_alt = sourcesink_set_alt;15 ss->function.disable = sourcesink_disable;16 17 status = usb_add_function(c, &ss->function);18 if (status)19 kfree(ss);20 return status;21 }
留意一下12行function.bind
17行status = usb_add_function(c, &ss->function);
函数在composite.c中
1 int usb_add_function(struct usb_configuration *config, 2 struct usb_function *function) 3 { 4 int value = -EINVAL; 5 6 DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n", 7 function->name, function, 8 config->label, config); 9 10 if (!function->set_alt || !function->disable)11 goto done;12 13 function->config = config;14 list_add_tail(&function->list, &config->functions);15 16 /* REVISIT *require* function->bind? */17 if (function->bind) {18 value = function->bind(config, function);19 if (value < 0) {20 list_del(&function->list);21 function->config = NULL;22 }23 } else24 value = 0;25 26 /* We allow configurations that don't work at both speeds.27 * If we run into a lowspeed Linux system, treat it the same28 * as full speed ... it's the function drivers that will need29 * to avoid bulk and ISO transfers.30 */31 if (!config->fullspeed && function->descriptors)32 config->fullspeed = true;33 if (!config->highspeed && function->hs_descriptors)34 config->highspeed = true;35 36 done:37 if (value)38 DBG(config->cdev, "adding '%s'/%p --> %d\n",39 function->name, function, value);40 return value;41 }
14行,同样把function插入链表
18行,第四次调用bind
回顾一下第一次bind设备,第二次bind配置,第三次bind接口,第四次该端点了
直接到f_sourcesink.c中:
1 static int __init 2 sourcesink_bind(struct usb_configuration *c, struct usb_function *f) 3 { 4 struct usb_composite_dev *cdev = c->cdev; 5 struct f_sourcesink *ss = func_to_ss(f); 6 int id; 7 8 /* allocate interface ID(s) */ 9 id = usb_interface_id(c, f);10 if (id < 0)11 return id;12 source_sink_intf.bInterfaceNumber = id;13 14 /* allocate endpoints */15 ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);16 if (!ss->in_ep) {17 autoconf_fail:18 ERROR(cdev, "%s: can't autoconfigure on %s\n",19 f->name, cdev->gadget->name);20 return -ENODEV;21 }22 ss->in_ep->driver_data = cdev; /* claim */23 24 ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);25 if (!ss->out_ep)26 goto autoconf_fail;27 ss->out_ep->driver_data = cdev; /* claim */28 29 /* support high speed hardware */30 if (gadget_is_dualspeed(c->cdev->gadget)) {31 hs_source_desc.bEndpointAddress =32 fs_source_desc.bEndpointAddress;33 hs_sink_desc.bEndpointAddress =34 fs_sink_desc.bEndpointAddress;35 f->hs_descriptors = hs_source_sink_descs;36 }37 38 DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",39 gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",40 f->name, ss->in_ep->name, ss->out_ep->name);41 return 0;42 }
15 和24 行分别获得了一个端口。 gadget zero设备使用了两个端口来收发数据。
以上差不多就是gadget驱动的注册和bind的过程。
- Linux gadget 驱动1
- Linux gadget驱动应用
- s3c6410 linux gadget hid驱动
- linux usb gadget驱动开发
- linux usb gadget代码分析--- gadget功能驱动层
- Linux设备驱动子系统 - USB Gadget
- linux gadget 驱动应用
- gadget 驱动
- 自娱自乐2之Linux gadget驱动1(linux-3.2.36的composite)
- Linux USB gadget设备驱动解析(4)--编写一个gadget驱动
- Linux USB gadget设备驱动解析(4)--编写一个gadget驱动
- Linux USB gadget设备驱动解析(4)--编写一个gadget驱动
- Linux USB gadget设备驱动解析(4)--编写一个gadget驱动
- Linux USB gadget设备驱动解析(2)---驱动调试
- Linux USB gadget设备驱动解析(2)---驱动调试
- Linux USB gadget设备驱动解析(2)---驱动调试
- Linux USB gadget设备驱动解析(2)---驱动调试
- Linux USB gadget设备驱动解析(2)---驱动调试
- 网站建设图片问题
- 我的第一篇博客
- 黑马程序员:Java自定义标记与Java方法重载(overload)
- 1018
- android Couldn't load ** findLibrary returned null
- Linux gadget 驱动1
- Configuration.ConfigurationSettings.AppSettings已过时
- 安家了!
- myeclipse fatjar 打包jar文件
- http权威指南笔记
- Squid编译安装及基本配置
- Jquery的ajax方法往后台传参中带#号问题解决方案
- Eclipse 快捷
- [分享]四杂.cn中未被注册的好组合