您的位置:首页 > 其它

7.最熟悉的陌生人--probe

2013-09-16 09:17 225 查看
7.最熟悉的陌生人--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 *
4000
/  
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->hdevhdev = 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 }  

幸运的是这个函数还不是很长。894行,desc,是这个函数中定义的一个struct usb_host_ interface结构体指针,其实这就相当于struct usb_interface结构中的那个altsetting,只是换了一个名字。

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

897行到902行,这是为OTG而准备的,为了简化问题,在这里我做一个假设,即假设我们不支持OTG。在内核编译选项中有一个叫做CONFIG_USB_OTG的选项,OTG就是"On The Go"(正在进行中)的意思,随着USB传输协议的诞生,以及它的迅速走红,人们不再满足于以前那种一个设备要么就是主设备,要么就是从设备的现状,也就是说要么是Host(或者叫主设备);要么是外设(也叫Slave,或者叫从设备)。在那个年代里,只有当一台Host与一台Slave连接时才能实现数据的传输,而后来开发人员们又公布了USB
OTG规范,于是出现了OTG设备,即既可以充当Host,亦能充当Slave的设备。也就是说如果你有一台数码相机和一台打印机,它们各有一个USB接口,把这两个口连接起来,就可以把你的照片打印出来了。所以我只能假设我们不打开支持OTG的编译开关,而这里我们看到的CONFIG_USB_OTG_ BLACKLIST_HUB,其实就是CONFIG_OTG下面的子选项,不选后者根本就见不到前者。

904行到911行,这没什么可说的了,每一个USB设备它属于哪个类,以及哪个子类这都是定好的,比如Hub的子类就是0,即desc->desc这个interface描述符里边的bInterfaceSubClass就应该是0。所以这里是判断如果bInterfaceSubClass不为0那就出错了,那就不往下走了,返回值是-EIO。

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

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

如果以上几种常见的错误都没有出现,这个时候我们才开始正式地去做一些事情,让我们继续。

924行,打印调试信息。

926行,申请Hub的数据结构struct usb_hub。不过926行有一个很新的函数,kzalloc()。其实这个函数就是原来的两个函数的整合,即原来我们每次申请内存时都会这么做,先是用kmalloc()申请空间,然后用me mset()来初始化,而现在一步到位,直接调用kzalloc()函数,效果等同于原来那两个函数,所有申请的元素都被初始化为0。

其实对于写驱动的人来说,知道现在应该用kzalloc()函数代替原来的kmalloc()和me mset()函数就可以了,这是内核中内存管理部分做出的改变,确切地说是改进。负责内存管理那部分程序的目标无非就是让内核跑起来更快一些,而从kmalloc/me mset到kzalloc的改变确实也是为了实现这方面的优化。所以自从2005年底内核中引入kzalloc之后,整个内核代码的许多模块里面都先后把原来的kmalloc/me mset统统换成了kzalloc()。咱们这里就是其中一处。927行到930行不用说了,如果没申请成功那就返回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就是和Hub相关联的struct device指针;第二个,不管是Hub也好,U盘也好,移动硬盘也好,USB鼠标也好,USB Core都准备一个struct usb_device来描述,所以hdev将是与这个Hub相对应的struct
usb_device指针。

而这些在我们调用hub_probe之前就已经建立好了,都在参数struct usb_interface *intf中,具体怎么得到的,对于Root Hub来说,这涉及主机控制器的驱动程序,现在先忽略。但对于一个普通的外接的Hub,后面会看到如何得到它的struct usb_interface,因为建立并初始化一个USB设备的struct usb_interface正是Hub驱动里做的事情,其实也就是我们对Hub驱动最好奇的地方。因为找到了这个问题的答案,我们就知道了对于一个USB设备驱动,其probe指针是在什么情况下被调用的,比如这里的hub_probe对于普通Hub来说是谁调用的?比如之前的usb-storage中函数storage_probe()究竟是谁调用的?这正是我们想知道的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: