Chinaunix首页 | 论坛 | 博客
  • 博客访问: 271436
  • 博文数量: 46
  • 博客积分: 4125
  • 博客等级: 上校
  • 技术积分: 575
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-25 16:40
文章分类

全部博文(46)

文章存档

2011年(1)

2010年(4)

2009年(38)

2008年(3)

我的朋友

分类: LINUX

2009-03-14 16:36:10

文件: 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) |
给主人留下些什么吧!~~