`
javatome
  • 浏览: 824680 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Linux那些事儿之我是UHCI(6)来来,我是一条总线,线线线线线线

 
阅读更多

下一个函数,1577,usb_register_bus.我们说过,一个USB主机控制器就意味着一条USB总线,因为主机控制器控制的正是一条总线.古人说,猫走不走直线,完全取决于耗子,而数据走不走总线,完全取决于主机控制器.

所以这里作为主机控制器的驱动,我们必须从软件的角度来说,注册一条总线.来自drivers/usb/core/hcd.c:

712 /**

713 * usb_register_bus - registers the USB host controller with the usb core

714 * @bus: pointer to the bus to register

715 * Context: !in_interrupt()

716 *

717 * Assigns a bus number, and links the controller into usbcore data

718 * structures so that it can be seen by scanning the bus list.

719 */

720 static int usb_register_bus(struct usb_bus *bus)

721 {

722 int busnum;

723

724 mutex_lock(&usb_bus_list_lock);

725 busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);

726 if (busnum < USB_MAXBUS) {

727 set_bit (busnum, busmap.busmap);

728 bus->busnum = busnum;

729 } else {

730 printk (KERN_ERR "%s: too many buses/n", usbcore_name);

731 mutex_unlock(&usb_bus_list_lock);

732 return -E2BIG;

733 }

734

735 bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),

736 bus->controller, "usb_host%d", busnum);

737 if (IS_ERR(bus->class_dev)) {

738 clear_bit(busnum, busmap.busmap);

739 mutex_unlock(&usb_bus_list_lock);

740 return PTR_ERR(bus->class_dev);

741 }

742

743 class_set_devdata(bus->class_dev, bus);

744

745 /* Add it to the local list of buses */

746 list_add (&bus->bus_list, &usb_bus_list);

747 mutex_unlock(&usb_bus_list_lock);

748

749 usb_notify_add_bus(bus);

750

751 dev_info (bus->controller, "new USB bus registered, assigned bus number %d/n", bus->busnum);

752 return 0;

753 }

Linux中名字里带一个register的函数那是数不胜数,也许这是一种时尚,随着你对Linux内核渐渐的熟悉,你慢慢就会觉得其实叫register的函数都很简单,简单得就像90后的女生作人流一样.甚至你会发现,Linux内核中的模块没有不用register函数的,就像新闻联播里:开会没有不隆重的,闭幕没有不胜利的,讲话没有不重要的,决议没有不通过的,鼓掌没有不热烈的,人心没有不鼓舞的,领导没有不重视的,进展没有不顺利的,问题没有不解决的,完成没有不超额的,成就没有不巨大的,竣工没有不提前的,接见没有不亲切的,中日没有不友好的,中美没有不合作的,交涉没有不严正的,会谈没有不圆满的.

其实一路走来的兄弟们应该能够很容易的看懂这个函数,这个函数首先让我们想起了在hub驱动中讲的那个choose_address.当时我们有一个devicemap,而现在有一个busmap.很显然,原理是一样的.drivesr/usb/core/hcd.c中有定义:

88 /* used when allocating bus numbers */

89 #define USB_MAXBUS 64

90 struct usb_busmap {

91 unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))];

92 };

93 static struct usb_busmap busmap;

和当时我们在hub驱动中对devicemap的分析一样,当时的结论是该map一共有128,同理可知这里busmap则一共有64.也就是说一共可以有64USB总线.我想,对我们这些凡夫俗子来说,这么多条足够了吧.不够?你以为你在织十字绣?

735, class_device_create,这个函数是Linux设备模型中一个很基础的函数,我家Intel的企业文化中有六大价值观,Intel面试的时候我特逗的一点就是把那六大价值观给背了下来,然后面试的时候跟面试官一条一条说,把人家逗乐了.这六大价值观中有一个叫做Result Orientation,用中文说就是以结果为导向.那现在我想是该使用这一价值观的时候了.Linux 2.6设备模型中提供了大把大把的基础函数,它们都在drivers/base目录下面,这下面的函数你如果有兴趣当然可以看一看,不过我不推荐你这么做,除非你的目的就是要彻底研究这个设备模型是如何实现的.对这些基础函数,我觉得比较好的认识方法就是以结果为导向,看看它们执行之后具体有什么效果,用直观的效果来体现它们的作用.

那好,那么这里class_device_create的效果是什么?我们知道设备模型和sysfs结合相当紧密,最能反映设备模型的效果的就是sysfs.所以凭一种男人的直觉,我们应该到/sysfs下面去看效果.不过我现在更愿意给你提供更多的背景,

首先,什么是class?C++的高手们一定不会不知道class,虽说哥们儿从未写过C++程序,可是好歹也看过两遍那本Thinking in C++的第一卷,所以class还是知道的.class就是类,设备模型中引入类的意义在于让一些模糊的东西变得更加清晰,更加直观,比如同样是scsi设备,可能你是磁盘她是磁带,但你们都属于一类,这一类就是scsi_device.于是就可以在/sys/class下面建立一个文件夹,从这里来体现同一个类别的各种设备.比如,偶的某台机器里/sys/class下面可以看到这些类,此时此刻还没有加载usbcore.

localhost:~ # ls /sys/class/

backlight graphics mem net spi_master vc

dma input misc pci_bus tty vtconsole

而咱们这里的class_device_create的第一个参数是usb_host_class,它是什么东西呢?

让我们把镜头切给usbcore的初始化函数,usb_init().我们在hub driver中已经说过,usb_initLinux中整个usb子系统的起点.一切的一切都从这里开始.而这个函数中有这么一段:

877 retval = usb_host_init();

878 if (retval)

879 goto host_init_failed;

我们来看它具体做了什么事情,usb_host_init来自drivers/usb/core/hcd.c:

671 static struct class *usb_host_class;

672

673 int usb_host_init(void)

674 {

675 int retval = 0;

676

677 usb_host_class = class_create(THIS_MODULE, "usb_host");

678 if (IS_ERR(usb_host_class))

679 retval = PTR_ERR(usb_host_class);

680 return retval;

681 }

让我们在上面提到的那台机器机器中加载usbcore,看看在/sys/class/下面会发生点什么.

localhost:~ # modprobe usbcore

localhost:~ # ls /sys/class/

backlight dma graphics input mem misc net pci_bus spi_master tty usb_device usb_host vc vtconsole

看出区别了么?多了两个目录,usb_hostusb_device,换言之,多了两个类.所以我们不难知道,这里class_create函数的效果就是在/sys/class/下面创建一个叫做usb_host的目录.usb_device是在另一个函数中创建的,usb_devio_init.方法是一样的,也是调用class_create函数.关于usb_device我们就不去多说了,继续看我们这个usb_host.我们这里调用class_create然后返回值赋给了usb_host_class,而这正是我们传递给class_device_create的第一个参数,所以你不看代码也应该知道我们的目标是在/sys/class/usb_host/下面建立一个文件或者是一个目录,那么结合代码来看,你就不难发现我们要建立的是一个叫做usb_hostn的文件或者是目录,具体是什么,让我们用结果来说话, 首先我们没有加载uhci-hcd,这时候可以看出这个目录是空的.

localhost:~ # ls /sys/class/usb_host/

然后我们把这个模块加载,再来看看效果.

localhost:~ # modprobe uhci-hcd

localhost:~ # ls -l /sys/class/usb_host/

total 0

drwxr-xr-x 2 root root 0 Oct 4 22:26 usb_host1

drwxr-xr-x 2 root root 0 Oct 4 22:26 usb_host2

drwxr-xr-x 2 root root 0 Oct 4 22:26 usb_host3

drwxr-xr-x 2 root root 0 Oct 4 22:26 usb_host4

因为我这台机器有4uhci主机控制器,所以我们可以看出,分别为每个主机控制器建立了一个目录.usb_host后面的这个1,2,3,4就是刚才说的busnum,即总线编号,因为一个主机控制器控制着一条总线.同时我们把class_device_create的返回值赋给了bus->class_dev.struct usb_bus中有一个成员struct class_device *class_dev,这个成员被称作class device,这个结构体对写驱动的人来说意义不大,但是从设备模型的角度来说是必要的,实际上对写驱动的人来说,你完全可以不理睬设备模型中class这个部分,你可以我行我素,你可以尽可能少的支持设备模型,因为这对你访问设备没有太多影响.你甚至可以让你的设备根本就不在/sysfs下面体现出来,你有权这么做,因为你是叛逆的80.但是一个聪明的人,你应该知道,有些东西是相互的,你用代码去支持设备模型,将来你使用设备的时候就能享受到设备模型为你提供的方便.相反,如果你为了省事不去支持设备模型,那么将来你会遭报应的,因为你使用设备的时候会发现有很多不便.这道理就像我们中华民族广大妇女的传统美德善待婆婆一样!虽然是今非昔比,已没有了主仆之分,但亦应该在互相尊重人格平等的基础上,更加地善待婆婆,才是最聪明的选择.因为每一个女人都有可能成为将来的婆婆.如果世上的女人都能为后人作出榜样,这个社会就会变的和谐起来,请做一个善良的聪明女人吧!

所以这里有743行这么一个举动,调用class_set_devdata,这就算是写代码的人对设备模型的支持,因为struct class_device中也有一个成员void *class_data,被称为class-specific data,而在include/linux/device.h中定义了class_set_devdata和一个与之对应的函数class_get_devdata.

279 static inline void *

280 class_get_devdata (struct class_device *dev)

281 {

282 return dev->class_data;

283 }

284

285 static inline void

286 class_set_devdata (struct class_device *dev, void *data)

287 {

288 dev->class_data = data;

289 }

结合我们这里具体对这个函数调用的代码可知,最终咱们这个host对应的class_deviceclass_data被赋值为bus.这样有朝一日我们要通过class_device找到对应的bus的时候我们只要调用class_get_devdata即可.设备模型的精髓就在于把一个设备相关联的种种元素都给联系起来,设备模型提供了大量建立这种纽带的函数,我们要做的就是调用这些函数.

,继续,746,很显然又是队列操作. usb_bus_list是一个全局队列,drivers/usb/core/hcd.c中定义:

84 /* host controllers we manage */

85 LIST_HEAD (usb_bus_list);

86 EXPORT_SYMBOL_GPL (usb_bus_list);

每次注册一条总线就是往这个队列里添加一个元素.struct usb_bus中有一个成员struct list_head bus_list.所以这里直接调用list_add即可.

749,usb_notify_add_bus,看到这个函数我几乎晕阙.因为细讲这个函数意味着我得少打两盘麻将而你却未必会更能理解usb子系统.真的,时间有限,生命有限,你别天真的以为挤时间就真的像挤乳沟一样容易.我只想用一句话来解释这个函数,按我们Intel以结果为导向的理论来说,这个函数在此情此景执行的结果是/proc/bus/usb下面会多一些文件,比如,

localhost:~ # ls /proc/bus/usb/

001 002 003 004 devices

这几个文件都是刚才这个函数执行之后的效果.

好了,usb_register_bus算是看完了,再一次回到usb_add_hcd中来.1580,usb_alloc_dev被调用,这个函数我们可不陌生.不过我们下节再看吧.这节剩下的时间我们为usb_notify_add_bus再多说两句话,这个函数牵涉到Linux中的notify机制,这是Linux内核中一种常用的事件回调处理机制.传说中的那个神奇的内核调试工具kdb中就是利用了这种机制进入kdb.这种机制在网络设备驱动中的应用,那就像成都小吃在北京的分布一样,满大街都是.而在usb子系统中,以前并没有使用这种机制,只是Greg同学在2005年底提出来要加进来的.其实我个人觉得,usb中不使用这种机制也能照样转.只不过GregLinuxUSB掌门人,就算地球不转了大家还是要围着他转.

分享到:
评论

相关推荐

    Linux那些事儿之我是UHCI

    写一下UHCI吧,也顺便怀念一下...虽然离开 Intel一年多了,但我总觉得也许有一天我还会回到 Intel.所 以关于 Intel的东西,我多少会关注一下.我挺怀念 Intel的,虽然钱也不多,但是那时候毕竟刚毕 业,对钱的问题也没想太多.

    Linux那些事儿

    Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 Linux那些事儿之我是Sysfs 今天本人将9个单独的文档整理出来,做成了一...

    Linux那些事儿1-9合集

    由复旦fudan_abc写的,风趣的文笔,深入浅...linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Block层 linux那些事儿之我是Sysfs

    Linux那些事儿系列.rar

    》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...

    linux那些事儿(EHCI Block SCSI Sysfs PCI USB U 盘 UHCI Hub)

    Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Block层.pdf Linux那些事儿之我是SCSI硬盘.pdf Linux那些事儿之我是Sysfs.pdf Linux那些事儿之我是PCI.pdf ...Linux那些事儿之我是UHCI.pdf

    linux的那些事儿全集

    Linux那些事儿之我是Block层 Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI ...Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之我是U盘

    linux那些事全集

    Linux那些事儿之我是UHCI Linux那些事儿之我是Sysfs Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是PCI Linux那些事儿之我是Hub Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Block层

    Linux那些事儿.rar

    Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是UHCI,...

    Linux那些事儿系列

    本人整理的fudan_abc的专栏中以完结的文章,在此向原作者表示感谢,给...内容包括:linux那些事儿之我是U盘,linux那些事儿之我是USB,linux那些事儿之我是HUB,linux那些事儿之我是UHCI,linux那些事儿之我是Sysfs。

    Linux那些事儿之我是XXX全集.rar

    Linux那些事儿之我是XXX全集 包含USB core U盘 UHCI PCI SCSI硬盘 Block Hub EHCI 。 想学驱动的童鞋,不妨看看。该书主要是进行源代码的分析

    Linux那些事儿 系列之2 Block+EHCI+PCI+SCSI

    Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是PCI.pdf Linux那些事儿之我是SCSI硬盘.pdf 注: 之前有人已经上传了《Linux那些事儿 系列》,其已经包含了:hub,sysfs...

    linux那些事儿之我是USB.zip

    里面包含Linux那些事的九个文档,Block层,ECHI主机控制,HUB,PCI,SCSI硬盘,Sysfs,UHCI,USB+core,U盘等九个文档,内容详细,而且全面都有书签,适合系统学习!

    Linux那些事系列

    Linux那些事儿之我是Hub Linux那些事儿之我是Sysfs Linux那些事儿之我是UHCI Linux那些事儿之我是USB core Linux那些事儿之我是U盘 Linux那些事之我是HUB1

    微信生活缴费商业项目标准版

    Linux那些Linux那些事儿之我是SCSI硬盘,Linux那些事儿之我是Block层,Linux那些事儿之我是EHCI主机控制器,Linux那些事儿之我是HUB,Linux那些事儿之我是PCI,Linux那些事儿之我是Sysfs,Linux那些事儿之我是UHCI,...

    usb那些事的全集

    usb那些事的全集,包含: 1 Linux那些事儿之我是Block层 2 Linux那些事儿之我是EHCI主机控制器 ...6 Linux那些事儿之我是Sysfs 7 Linux那些事儿之我是UHCI 8 Linux那些事儿之我是USB+core 9 Linux那些事儿之我是U盘

    Linux那些事儿[完整版]自己整理

    我是U盘 说的是2.6.10的内核 我是Sysfs 说的是2.6.10的内核 戏说USB 说的是2.6.22的内核 我是Hub/UHCI/EHCI 说的是2.6.22.1的内核

    LINUX那些事儿 linux经典之作

    我是Hub/UHCI/EHCI 说的是2.6.22.1的内核 其中我是U盘属于基础性的.这一阶段会遇到一些问题.比如urb提交之后究竟怎么处理的?用户空间究竟是如何访问U盘的?DMA究竟怎么回事. 这之后可以开始看Hub.这一阶段你会明白一...

    linux那些事儿.rar

    linux那些事儿,Block层,EHCI主机控制器,Hub,PCI,SCSI硬盘,Sysfs,UHCI,USB core,U盘等文档。

    Linux那些事儿(包括Hub, Sysfs, UHCI, USB, U盘5个部分)

    一个很经典的东东,里面的很多东西都很有启发性,值得看看

Global site tag (gtag.js) - Google Analytics