热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linux那些事儿之我是Hub(6)probe,又见probe!

话说因为hub驱动无所事事,所以hub_thread()进入了睡眠,直到某一天,hub_probe被调用.所以我们来看hub_probe().这个函数来自driversusbhub.c,其作

话说因为hub驱动无所事事,所以hub_thread()进入了睡眠,直到某一天,hub_probe被调用.所以我们来看hub_probe().这个函数来自drivers/usb/hub.c,其作用就如同当初我们在usb-storage中的那个storage_probe()一样.

    887 static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)

    888 {

    889         struct usb_host_interface *desc;

    890         struct usb_endpoint_descriptor *endpoint;

    891         struct usb_device *hdev;

    892         struct usb_hub *hub;

    893

    894         desc = intf->cur_altsetting;

    895         hdev = interface_to_usbdev(intf);

    896

    897 #ifdef  CONFIG_USB_OTG_BLACKLIST_HUB

    898         if (hdev->parent) {

    899                 dev_warn(&intf->dev, "ignoring external hub/n");

    900                 return -ENODEV;

    901         }

    902 #endif

    903

    904         /* Some hubs have a subclass of 1, which AFAICT according to the */

    905         /*  specs is not defined, but it works */

    906         if ((desc->desc.bInterfaceSubClass != 0) &&

    907             (desc->desc.bInterfaceSubClass != 1)) {

    908 descriptor_error:

    909                 dev_err (&intf->dev, "bad descriptor, ignoring hub/n");

    910                 return -EIO;

    911         }

    912

    913         /* Multiple endpoints? What kind of mutant ninja-hub is this? */

    914         if (desc->desc.bNumEndpoints != 1)

    915                 goto descriptor_error;

    916

    917         endpoint = &desc->endpoint[0].desc;

    918

    919         /* If it's not an interrupt in endpoint, we'd better punt! */

    920         if (!usb_endpoint_is_int_in(endpoint))

    921                 goto descriptor_error;

    922

    923         /* We found a hub */

    924         dev_info (&intf->dev, "USB hub found/n");

    925

    926         hub = kzalloc(sizeof(*hub), GFP_KERNEL);

    927         if (!hub) {

    928                 dev_dbg (&intf->dev, "couldn't kmalloc hub struct/n");

929                 return -ENOMEM;

    930         }

    931

    932         INIT_LIST_HEAD(&hub->event_list);

    933         hub->intfdev = &intf->dev;

    934         hub->hdev = hdev;

    935         INIT_DELAYED_WORK(&hub->leds, led_work);

    936

    937         usb_set_intfdata (intf, hub);

    938         intf->needs_remote_wakeup = 1;

    939

    940         if (hdev->speed == USB_SPEED_HIGH)

    941                 highspeed_hubs++;

    942

    943         if (hub_configure(hub, endpoint) >= 0)

    944                 return 0;

    945

    946         hub_disconnect (intf);

    947         return -ENODEV;

    948 }

幸运的是这个函数还不是很长.看过usb-storage的兄弟姐妹们应该不难看懂这个函数.尤其是894,895这几行经典的赋值.尽管当年我们看的usb-storage2.6.10的内核,而斗转星移,如今我们看的是2.6.22.1的内核,但是江山会变,四季会变,有些经典并不会改变.894,desc,是这个函数里定义的一个struct usb_host_interface结构体指针,其实这就相当于当年的那个altsetting,只是换了个名字,别以为披上马夹咱就不认识它了.struct usb_host_interface结构体的定义依然还是当初那样,鉴于子曾经曰过温故而知新,我们这里再贴一次这个结构体吧,来自include/linux/usb.h:

     69 /* host-side wrapper for one interface setting's parsed descriptors */

     70 struct usb_host_interface {

     71         struct usb_interface_descriptor desc;

     72

     73         /* array of desc.bNumEndpoint endpoints associated with this

     74          * interface setting.  these will be in no particular order.

     75          */

     76         struct usb_host_endpoint *endpoint;

     77

     78         char *string;           /* iInterface string, if present */

     79         unsigned char *extra;   /* Extra descriptors */

     80         int extralen;

     81 };

需要注意的是,71,这里有一个成员,对应接口描述符的结构体,struct usb_interface_descriptor desc,刚才我们的那个指针也叫做desc,所以一会我们就会看到,desc->desc这样的用法.

同样895行这个赋值我们也是很眼熟, interface_to_usbdev()这个宏就是为了从一个struct usb_interface的结构体指针得到那个与它相关的struct usb_device结构体指针.这里等号右边的intf自不必说,而左边的hdev正是我们这里为了hub而定义的一个struct usb_device结构体指针.

897902,这是为OTG而准备的,为了简化问题,在这里我做一个伟大的假设,即假设我们不支持OTG.在内核编译选项中有一个叫做CONFIG_USB_OTG的选项,OTG就是On The Go的意思,正在进行中的意思,随着USB传输协议的诞生以及它的迅速走红,人们不再满足于以前那种一个设备要么就是主设备,要么就是从设备的现状,也就是说要么是Host,或者叫主设备,要么是外设,也叫Slave,或者叫从设备.那个年代里,只有当一台Host与一台Slave连接时才能实现数据的传输,而后来善良的开发者们又公布了USB OTG规范,于是出现了OTG设备,即既可以充当Host,亦能充当Slave的设备.就是说你有一个数码相机,你有一台打印机,它们各有一个USB接口,把这两个口连接起来,然后就可以把你偷拍的美女照片打印出来了.不过我们为了省事,还是别玩这种高科技了吧,省点时间玩几盘CS不是挺好么?所以我只能假设我们不打开支持OTG的编译开关,而这里我们看到的CONFIG_USB_OTG_BLACKLIST_HUB,其实就是一CONFIG_OTG下面的子选项,不选后者根本就见不到前者,因此咱们也不用看.

904911,这我真是无话可说了,每一个USB设备它属于哪个类,以及哪个子类,这都是上天注定的,自打盘古开天地那会儿就已经确定下来了,比如hub的子类就是0,desc->desc这个interface描述符里边的bInterfaceSubClass就该是0.所以这里本是判断如果bInterfaceSubClass不为0那就出错了,那就甭往下走了,返回吧,返回值是-EIO.就像一个人如果连自己是哪一类物种都能弄错,那还活个什么劲呢?不过我真正来气的是偏偏有些没事找抽型的企业愣是把自己家生产的hub里边的描述符中的bInterfaceSubClass这一位弄成了1,完了实践证明该hub也还能工作,别的方面都还正常,你说你要是调试设备驱动程序老是碰上这样的设备是不是非得急死你?

914,915,其实干的事情是差不多的,针对接口描述符再做一次判断,这次是判断这个hub有几个端点,或者说Endpoint.spec规定了hub就是一个endpoint,中断endpoint,因为hub的传输是中断传输.当然还有控制传输,但是因为控制传输是每一个设备都必须支持的,即每一个usb设备都会有一个控制端点,所以在desc->desc.bNumEndpoints中是不包含那个大家都有的控制端点的.因此如果这个值不为1,那么就说明又出错了,仍然只能是返回.

917,就是得到这个唯一的端点所对应的端点描述符,920921行就是判断这个端点是不是中断端点,如果不是那还是一样,返回报错吧.

如果以上几种常见的错误都没有出现,那这时候我们才开始正式的去做一些事情,让我们继续,向前进,向前进,战士的责任重,妇女的冤仇深.

924,打印调试信息.

926,申请hub的数据结构struct usb_hub.早些时候我们已经贴出来这个结构体的定义了,不记得的回去看看.不过926行有一个很新潮的函数,kzalloc().其实这个函数就是原来的两个函数的整合,即原来我们每次申请内存的时候都会这么做,先是用kmalloc()申请空间,然后用memset()来初始化,而现在省事了,一步到位,直接调用kzalloc(),效果等同于原来那两个函数,所有申请的元素都被初始化为0.其实对写驱动的来说,知道现在应该用kzalloc()代替原来的kmalloc()memset()就可以了,这是内核中内存管理部分做出的改变,确切的说是改进,负责内存管理那部分的兄弟们的目标无非就是让内核跑起来更快一些,而从kmalloc/memsetkzalloc的改变确实也是为了实现这方面的优化.所以自从2005年底内核中引入kzalloc之后,忽如一夜春风来,整个内核代码的许多模块里面都先后把原来的kmalloc/memset统统换成了kzalloc().咱们这里就是其中一处.927930行不用说了,如果没申请成功那就挂了,返回ENOMEM.

932,还记得咱们之前说了什么吗,总分的想法,一个总的事件队列,hub_event_list,然后各个hub都有一个分的事件队列,就是这里的hub->event_list,前面咱们初始化了全局的那个hub_event_list,而这里咱们针对单个hub就得为其初始化一个event_list.

933行和934,struct usb_hub中的两个成员,struct device *intfdev, struct usb_device *hdev,干嘛用的想必不用多说了吧,第一个,甭管你是usb设备也好,pci设备也好,scsi设备也好,Linux内核中都为你准备一个struct device结构体来描述,所以intfdev就是和咱们这usb hub相关联的struct device指针,第二个,甭管你是hub也好,u盘也好,移动硬盘也好,usb鼠标也好,usb core都为你准备一个struct usb_device来描述,所以hdev就将是与咱们这个hub相对应的struct usb_device指针.而这些,在我们调用hub_probe之前就已经建立好了,都在那个参数struct usb_interface *intf,具体怎么得到的,对于root hub来说,这涉及到host controller的驱动程序,咱们先不去理睬.但对于一个普通的外接的hub,那咱们一会儿会看到如何得到它的struct usb_interface,因为建立并初始化一个usb设备的struct usb_interface正是hub驱动里做的事情.其实也就是我们对hub驱动最好奇的地方.因为找到了这个问题的答案,我们就知道了对于一个usb设备驱动,probe指针是在什么情况下被调用的,比如咱们这里的hub_probe对于普通hub来说是谁调用的?比如咱们之前那个usb-storage中最有意思的函数storage_probe()究竟是谁调用的?这正是我们想知道的.

 

推荐阅读
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了使用C++Builder实现获取USB优盘序列号的方法,包括相关的代码和说明。通过该方法,可以获取指定盘符的USB优盘序列号,并将其存放在缓冲中。该方法可以在Windows系统中有效地获取USB优盘序列号,并且适用于C++Builder开发环境。 ... [详细]
  • 新增和更新价目表行--目的:在已有的价目表头基础上,增加行信息--限制:该api有些问题,如果强制增加头信息,会有很多问题,所以该例子只是在已有头信息基础上,增加行信息 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 设计模式六大原则(四):接口隔离原则(Interface Segregation Principle)
    接口隔离原则(ISP)定义:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和 ... [详细]
  • 由于工作需要,接手别人用bpel写的工作流程序,一点都不懂就到网上找到一篇入门的文章,觉得这篇不错,就copy下来并添加了读书笔计以红字标记,感激写此文章的人.许多开发人员觉得BPEL很神秘,不知道 ... [详细]
  • 背景1.结构体1.1depSet和finalCloserdepSet:记录db与conn之间的依赖关系,维持连接池以及关闭时使用finalCloser:TododepSetisaf ... [详细]
  • 长话短说,尝试利用Google的良好做法。我为Di计划使用Dagger2犯了一个错误。现在我被 ... [详细]
author-avatar
白色的睡
这个家伙很懒,什么也没留下!
RankList | 热门文章