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

话说因为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()究竟是谁调用的?这正是我们想知道的.

 

你可能感兴趣的:(Linux那些事儿之我是Hub(6)probe,又见probe!)