绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
LINUX下USB1.1设备学习小记(4)_uhci(1)
2020-06-03 11:22:57

现在开始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), , , NULL);
if (!uhci_up_cachep)
goto up_failed;
//注册uhci,详细的注册过程我不分析了
retval = pci_register_driver(&uhci_pci_driver);
//注册好的结构图如下


if (retval)
goto init_failed;
return ;
}

文章来源CU社区:LINUX下USB1.1设备学习小记(4)_uhci(1)

分享好友

分享这个小栈给你的朋友们,一起进步吧。

内核源码
创建时间:2020-05-18 13:36:55
内核源码精华帖内容汇总
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 飘絮絮絮丶
    专家
戳我,来吐槽~