|
文件: |
UHCI.pdf |
大小: |
512KB |
下载: |
下载 | |
现在开始LINUX下USB主机和设备的驱动架构分析
这是最宏观的架构图
先讲解红框中的内容,先不在PDIUSBD12上写入HID等模块,等讲解完UHCI和PDIUSBD12的详细通讯过程之后,再在D12上写HID的模块内容,进行蓝框内容的讲解
首先是usb主机控制器UHCI在LINUX下的架构,关于sysfs的内容在” 个人对kobject的一点研究”中有介绍,为了减少图的大小和复杂度,sysfs中只简单的描述kobject的parent属性, kset和 ktype就不详细说了
现在看看usb设备在linux的sysfs体系下的宏观驱动框架
在这个架构中,展示的为基本真实的目录体系,例如在/sys s-xxxxxxx-devices中的所有目录都是连接到/sys/devices的,为什么呢个pci的框是红色的呢?因为我把pci设备和pci总线的目录合并到一起了,所以前面只说了基本........,因为我对pci的了解还不深,所以合起来,等我搞定pci总线的时候会回来修改的
对于uhci来说,重要的有3个目录,devices下的pci设备目录,重要的数据结构都挂载在这个目录所表示的设备下,bus->pci->drivers这个目录是pci设备的驱动,linux使用这些驱动管理pci总线上的设备,bus->usb->drivers这个目录是usb设备的驱动,linux使用这些驱动管理所有的usb设备
下面这个图是目录的具体数据结构组成,可以发现,和上图的结构层次是一致的
在这个图中,2个紫框中的数据结构是我们重点关注的内容,其它数据结构基本只在设备初始化和电源管理中使用
其中左边的紫框中的数据结构我还没画完整,因为没地方放了.....将在后面的介绍中完整的展示给大家
好,现在开始我们的UHCI源代码之旅(PS:碍于篇幅问题,注册失败所使用的释放函数和DEBUG代码将不会分析,我就不把这些代码列出来了,假定不使用DEBUG并且注册的条件总是满足的)
首先是usb几个重要驱动的加载,usbfs,usb和hub
usb_init在linux内核\drivers\usb\core\usb.c中
static int __init usb_init(void) { int retval; //检测内核是否支持usb if (nousb) { pr_info("%s: USB support disabled\n", usbcore_name); return 0; } //创建工作队列,工作队列就是在每个CPU上都创建一个线程,但是我在usb设备的使用中还没有接触过这个队列,所以暂不分析 retval = ksuspend_usb_init(); if (retval) goto out; //创建usb总线,这个总线模型为所有usb驱动和设备提供一个连接平台,表现为/sys s/usb这个目录 retval = bus_register(&usb_bus_type); if (retval) goto bus_register_failed; //创建usb_host类,用于连接主机控制器类设备,在/sys/class/usb_host下 retval = usb_host_init(); if (retval) goto host_init_failed; //注册一个usb字符设备,这个字符设备的用途现在不介绍 retval = usb_major_init(); if (retval) goto major_init_failed; //注册usb接口驱动usbfs,usbfs是/proc中的内容,现在2.6的内核中已经不再支持了,可以看见usbfs_driver->probe中的内容是空的 retval = usb_register(&usbfs_driver); if (retval) goto driver_register_failed; //注册usb设备的字符设备,这个字符设备的用于现在也先不介绍 retval = usb_devio_init(); if (retval) goto usb_devio_init_failed; //注册并挂载usbfs,注册/proc s/usb retval = usbfs_init(); if (retval) goto fs_init_failed; //注册usb接口驱动hub,用于驱动主机控制器 retval = usb_hub_init(); if (retval) goto hub_init_failed; //注册usb驱动usb,用于为所有的usb设备对象提供一个统一模型 retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); if (!retval) goto out }
|
现在看一下usb_generic_driver的注册,它所使用的注册函数为usb_register_device_driver,这个函数和hub,usbfs所使用的usb_register其实是大体一样的,所以以usb_generic_driver为例,就不介绍hub和usbfs的注册了,具体的区别我会提到的
usb_register_device_driver在\drivers\usb\core\driver.c中
int usb_register_device_driver(struct usb_device_driver *new_udriver, struct module *owner) { int retval = 0; if (usb_disabled()) return -ENODEV; //设置for_devices的标志为1, usb_generic_driver和hub,usbfs的注册区别就是在这里, usb_generic_driver是对于usb设备的驱动,而hub和usbfs是对于usb接口,也就是usb功能的驱动,至于什么是usb接口,将在usb接口注册的时候再介绍 new_udriver->drvwrap.for_devices = 1; new_udriver->drvwrap.driver.name = (char *) new_udriver->name; //设置驱动的总线类型为usb new_udriver->drvwrap.driver.bus = &usb_bus_type; //在hub和usbfs中使用的probe为usb_probe_interface new_udriver->drvwrap.driver.probe = usb_probe_device; //在hub和usbfs中使用的probe为usb_unbind_interface new_udriver->drvwrap.driver.remove = usb_unbind_device; new_udriver->drvwrap.driver.owner = owner; //到了这里一个驱动的模块所使用的数据结构就组建好了,如下图
//现在将驱动挂载到usb总线上 retval = driver_register(&new_udriver->drvwrap.driver); //挂载好会在/sys/bus/usb/drivers下生成一个目录usb,数据结构如下图
//在这个总线数据结构中比较关键的就是usb_bus_type中的2个链表,klist_devices和klist_drivers,前者负责挂接设备,后者负责挂接驱动,当新增一个设备的时候,就会历遍驱动的链表,检测是否有适合的驱动进行匹配,当新增一个驱动的时候就会历遍设备链表,检测是否有合适的设备进行匹配 //可以看见usb_generic_driver->p->knode_bus是连接到了klist_drivers上 return retval; }
|
在hub的驱动注册中有一条语句
khubd_task = kthread_run(hub_thread, NULL, "khubd");
这条代码启动一个名为”khubd”的线程,这个线程的用途是啥现在先保密,= 3=
3个驱动挂载完毕后的结构图如下
usb驱动注册完成后,现在到主角登场了,PCI设备UHCI驱动的注册,为什么要强调PCI呢?因为UHCI是两面的,一面使用PCI总线连接PC,一边使用USB接口连接USB设备,现在在PC上注册UHCI,当然注册UHCI要使用PCI总线的注册函数了
uhci_hcd_init在/drivers/usb/host/uhci-hcd.c中
static int __init uhci_hcd_init(void) { int retval = -ENOMEM; printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "%s\n", ignore_oc ? ", overcurrent ignored" : ""); //检测内核是否使用usb if (usb_disabled()) return -ENODEV; //为uhci分配cache uhci_up_cachep = kmem_cache_create("uhci_urb_priv", sizeof(struct urb_priv), 0, 0, NULL); if (!uhci_up_cachep) goto up_failed; //注册uhci,详细的注册过程我不分析了 retval = pci_register_driver(&uhci_pci_driver); //注册好的结构图如下
if (retval) goto init_failed; return 0; }
|
阅读(3031) | 评论(0) | 转发(0) |