现在的位置: 首页 > 综合 > 正文

Linux那些事儿之我是UHCI(1)开户和销户

2013年11月08日 ⁄ 综合 ⁄ 共 5029字 ⁄ 字号 评论关闭

之所以说uhci_hcd_init有技术含量,并不是说它包含多么精巧的算法,包含多么复杂的数据结构.而是因为这其中涉及了很多东西.首先924,usb_disable涉及了Linux中的内核参数的概念.928行的kmalloc936行的kmem_cache_create涉及了Linux内核中内存申请的问题,931debugfs_create_dir则涉及到了文件系统,一个虚拟的文件系统debugfs,941pci_register_driver则涉及到了Linuxpci设备驱动程序的注册.

这么多东西往这里一堆,其复杂程度立马就上来了.在这个共和国58周年的喜庆日子里,我是多么希望我们的伟大祖国繁荣昌盛啊!同时,我又是多么希望这个函数有且只有921那么一行printk语句啊!

第一,内核参数,什么是内核参数?看一下你的grub文件,

title SUSE Linux Enterprise Server 10 (kdb enabled)

    kernel (hd0,2)/boot/vmlinuz-2.6.22.1-test root=/dev/hda3 resume=/dev/hda2  splash=silent showopts

    initrd /boot/initrd-2.6.22.1-test

kernel那行的都是内核参数,比如root,比如resume,比如splash,比如showopts.其中root=代表的是你的Root文件系统的位置,resume=代表的是你用来做software suspend恢复的那个分区,usb子系统也准备了这么一个参数,其名字就叫做nousb.所以你可以往这一行后面加上nousb,这就意味着你的系统不需要支持usb,或者换一种说法,你把usb子系统给disable掉了.nousb默认为0,你设置了它就为1.usb_disabled返回的就是nousb的值.我们在drivers/usb/core/usb.c中也能看到这个函数:

    852 /*

    853  * for external read access to <nousb>

    854  */

    855 int usb_disabled(void)

    856 {

    857         return nousb;

    858 }

第二,申请内存的两个函数kmallockmem_cache_create.对于kmalloc,我们早已不陌生,kmem_cache_create,呵呵,传说中的Slab现身了.传统上,kmem_cache_createSlab分配器的接口函数,用于创建一个cache,你要是不知道什么是cache的话,你就把它当作内存池,而这里创建了一个cache之后,以后你就可以用另一个函数kmem_cache_zalloc来申请内存,使用kmem_cache_free来释放内存,而当你玩腻了之后,你可以使用kmem_cache_destroy来彻底释放这个内存池.这其中一个很重要的特点是每次你用kmem_cache_zalloc申请的内存大小是一样的,这正是你在kmem_cache_create中的第二个参数所指定的,比如这里的具体情况就是sizeof(struct urb_priv),即以后你看到你用kmem_cache_zalloc申请的内存总是这么大,而这里kmem_cache_create的返回值就是创建好的那个cache.这里返回值被赋给了uhci_up_cachep,它是一个struct kmem_cache的结构体指针.所以以后你使用kmem_cache_zalloc的时候只要把这个uhci_up_cachep作为参数即可.然后你就能得到你想要的内存.对于kmem_cache_freekmem_cache_destroy也一样.

对这些函数最简单的理解方法就是,比如你去沃尔玛超市,你需要装东西,超市里给你提供了篮子,你可以把你需要的东西装在篮子里,白痴都知道超市里的篮子数量是有限的,但是基本上你不会碰到说你去超市发现篮子不够的情况,这是因为沃尔玛在开张之前就准备了足够多的篮子,比如它订做了一个仓库的篮子,每个篮子都一样大.即一开始沃尔玛方就调用了kmem_cache_create做了一池的篮子,而你每次去就是使用kmem_cache_zalloc去拿一个篮子即可,而当你付款之后你要离开了,你又调用kmem_cache_free去归还篮子,每个人都这样做的话,你下次去了你要用篮子你又可以kmem_cache_zalloc再拿一个.而一旦哪天沃尔玛宣武门分店连续亏损,店子做不下去了,它就可以调用kmem_cache_destroy把篮子全都毁掉,当然更形象的例子是它把篮子转移到别的店去,比如知春路分店,那么从整个沃尔玛公司来看,可以供来装东西的容器总容积还是没有变.正如你的计算机总的内存是不会变的.假如公司将来又打算在国贸开一家分店,那么它可以再次调用kmem_cache_create.而对你来说,你并不需要知道一池内存到底有多少,就像你永远不用知道沃尔玛知春路店究竟有多少个篮子一样.

好了,第三个,debugfs_create_dir,传说中的debugfs也现身了.很多事情都是早已注定的,原本以为写设备驱动的只要懂一些硬件规范就可以了,后来终于在眼泪中明白,有些人一旦写代码就会越写越复杂.如今的内核代码早已不像那时候了那么单纯了,记得奶茶刘若英也在专门为此而唱了一首歌,叫做后来,歌中感叹,

后来我总算学会了如何去看代码,

可惜那简单的代码早已远去消失在人海,

后来终于在眼泪中明白,

有些代码一旦错过就不再.

那时候的代码,为什么就能那样简单,

而又是为什么,人年少时,没有好好的看代码,

在这相似的深夜里你是否一样也在静静追悔感伤,

如果当时我们能不那么贪玩,现在也不那么遗憾.

遗憾归遗憾,代码还是要看.以前我一直以为,LinuxPCI子系统和USB子系统的掌门人Greg同志只是一个花拳绣腿的家伙,只是每天忙着到处演讲,开会,而不干正经事,后来我发现,其实不是的,Greg其实还是干了很多有意义的事情,我不得不承认,Greg是条汉子!debugfs就是他开发的,这是一个虚拟的文件系统,Greg同志在2.6.11中把它引入的,专门用于输出调试信息,这个文件系统默认是被挂载在/sys/kernel/debug下面,比如

localhost:~ # mount

/dev/hda3 on / type reiserfs (rw,acl,user_xattr)

proc on /proc type proc (rw)

sysfs on /sys type sysfs (rw)

debugfs on /sys/kernel/debug type debugfs (rw)

udev on /dev type tmpfs (rw)

devpts on /dev/pts type devpts (rw,mode=0620,gid=5)

这个文件系统是专门为开发者准备的,在配置内核的时候可以选择编译进去也可以选择不编译进去.其对应的Kconfig文件是lib/Kconfig.debug.

     50 config DEBUG_FS

     51         bool "Debug Filesystem"

     52         depends on SYSFS

     53         help

     54           debugfs is a virtual file system that kernel developers use to put

     55           debugging files into.  Enable this option to be able to read and

     56           write to these files.

     57

     58           If unsure, say N.

很有意思的是这个文件系统居然依赖于另一个文件系统,sysfs.如果你用make menuconfig命令编译内核的话,你可以在Kernel hacking下面找到它,就叫DEBUG_FS.我们不去深入研究这个文件系统,但是对于它的接口函数是有必要了解一下的.

首先第一个就是这里这个debugfs_create_dir,这很简单,就是创建一个目录.像这里这么一行的作用就是在/sys/kernel/debug下面创建一个叫做uhci的目录,比如你加载了uhci-hcd这个模块的话你就能像我一样看到uhci这么一个目录:

localhost:/usr/src/linux-2.6.22.1 # ls /sys/kernel/debug/

kprobes  uhci

这个函数的返回值是文件系统里最经典的一个结构体指针,struct dentry的指针,而这里我们把返回值赋给了uhci_debugfs_root,后者正是一个struct dentry指针,它被定义于drivers/usb/host/uhci-debug.c,

     20 static struct dentry *uhci_debugfs_root;

显然这个指针对我们uhci-hcd这个模块来说是到处都可以引用的.而从此之后要在uhci目录下创建文件就是用debugfs_create_file这个函数,我们将会在uhci_start函数中见到,到时候再说.而以后删除这个目录的任务就在uhci_hcd_cleanup,它只要调用debugfs_remove函数即可.至于在这个目录下创建什么文件,具体有什么用,只能到时候再来看,现在时机尚未成熟,很多术语尚未交待.

现在剩下第四个问题,pci_register_driver,其实一路走来的兄弟们应该多少有点感觉,虽然我们没见过这个函数,但是我们能感觉出它和我们当初的那个usb_register_driver是一个性质的,一个是注册usb驱动,一个是注册pci驱动.这里的参数uhci_pci_driver是我们要关注的.

    894 static const struct pci_device_id uhci_pci_ids[] = { {

    895         /* handle any USB UHCI controller */

    896         PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0),

    897         .driver_data =  (unsigned long) &uhci_driver,

    898         }, { /* end: all zeroes */ }

    899 };

    900

    901 MODULE_DEVICE_TABLE(pci, uhci_pci_ids);

    902

    903 static struct pci_driver uhci_pci_driver = {

    904         .name =         (char *)hcd_name,

    905         .id_table =     uhci_pci_ids,

    906

    907         .probe =        usb_hcd_pci_probe,

    908         .remove =       usb_hcd_pci_remove,

    909         .shutdown =     uhci_shutdown,

    910

    911 #ifdef  CONFIG_PM

    912         .suspend =      usb_hcd_pci_suspend,

    913         .resume =       usb_hcd_pci_resume,

    914 #endif  /* PM */

    915 };

跟我们走过usb-storage的同志们应该是一看就知道怎么回事了吧?尤其是那个uhci_pci_ids,这张表怎么看怎么觉得似曾相识.没错,它的作用正如我们当初那张storage_usb_ids.所以我就不多说了.这里PCI_CLASS_SERIAL_USB_UHCI0x0c0300,03表示类别为03,这代表USB,00代表UHCI,如果是OHCI,就是0x0c0310,EHCI

抱歉!评论已关闭.