看看mct_u232_driver和mct_u232_device usb驱动是怎么关联到一起的
文章来源:http://gliethttp.cublog.cn
只有struct device_driver定义的driver才会被usb系统自动注册到总线上,它内部的kobj才会添加到bus->drivers对象集合中,driver->knode_bus被链接到bus->klist_drivers链表中,当发现新硬件或者insmod安装驱动时总线调用drv->bus->match(dev, drv),这个drv就是struct device_driver类型driver,之后使用dev->bus->probe(dev)如果dev->bus->probe==null那么使用drv->probe(dev),这里的drv也是struct device_driver类型driver,所以被底层bus总线调用的driver驱动是struct device_driver类型的驱动,当然match为bus提供的函数,probe则是bus->probe或者device_driver->probe而绝不会是mct_u232_driver->probe,mct_u232_driver内嵌了struct device_driver结构,在其内部的定义是mct_u232_driver->drvwrap.driver,而drvwrap.driver的方法在usb_register()->usb_register_driver()函数下面摘录的代码中登记(gliethttp_20071031): ... new_driver->drvwrap.driver.bus = &usb_bus_type; new_driver->drvwrap.driver.probe = usb_probe_interface; new_driver->drvwrap.driver.remove = usb_unbind_interface; ... 所以hub发现新硬件之后,会调用usb_bus_type->match()和drvwrap.driver.probe(),在drvwrap.driver.probe()代码中会调用mct_u232_driver->probe(intf, id);这个mct_u232_driver->probe才是我们用户自己写的程序了,其他的那些probe都是usb内核系统自己提供的,我们用户可以不用去理会,来看看mct_u232_driver的定义: static struct usb_driver mct_u232_driver = { .name = "mct_u232", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table_combined, .no_dynamic_id = 1, }; 当usb内核系统发现新硬件并且通过bus->match匹配和drvwrap.driver.probe()初步筛选之后,就会调用我们这个mct_u232_driver中定义的usb_serial_probe了,这个usb_serial_probe所做的工作就细致的很了,因为hub检测的硬件的所有详细信息都将在这里登记到内核中,注册到各个目录下,如/sys/devices/目录下,ports申请创建--bulk in、bulk out、int in和int out的read_urb,bulk_in_buffer数据缓冲,write_urb,bulk_out_buffer数据缓冲区,interrupt_in_urb,interrupt_in_buffer数据缓冲,相应的申请活动中会调用usb_fill_int_urb()将申请到的urb进一步初始化,比如read_int_callback、write_int_callback、read_bulk_callback和write_bulk_callback数据处理结束后的回调函数将被填充进去,在这个函数中有一个经常用到的变量type,他的类型为usb_serial_driver,这个type就是在usb_serial_driver_list总线上注册登记的所有drivers驱动中的和dev最后匹配上的一个usb_serial_driver指针,对于我们这里谈的东西,这个type就是mct_u232_device,因为mct_u232_device在usb_serial_register()时,将自己的mct_u232_device->driver_list节点添加到了usb_serial_driver_lst总线驱动链表上,当这些初始化完成之后,将注册登记hub检测到的经过以上分析出来的所有port下的dev设备们port->dev.bus = &usb_serial_bus_type;device_register(&port->dev);//将dev注册到devices_subsys这个kset集合上,这样/sys/devices/目录下也就有了这个dev设备文件了在device_register()中会调用bus_attach_device()来为这个port->dev设备寻找合适的driver驱动,对于具体到我们的分析,就是通过bus_for_each_drv()函数遍历usb_serial_bus_type总线上的klist_drivers链表,usb_serial_bus_type的原始定义如下: struct bus_type usb_serial_bus_type = { .name = "usb-serial", .match = usb_serial_device_match, .probe = usb_serial_device_probe, .remove = usb_serial_device_remove, .drv_attrs = drv_attrs, }; 所以这个bus总线提供了match和probe,因此如果驱动定义了probe,那么驱动的probe是不会调用的,不过还好usb_serial_driver->driver没有做任何定义,仅仅在我们用户自己的程序中定义了它的名字.name,具体为: static struct usb_serial_driver mct_u232_device = { .driver = { .owner = THIS_MODULE, .name = "mct_u232", }, ... }; 正如最开始提到的usb_serial_driver->driver也是struct device_driver类型结构,usb_serial_bus_type总线上的dev设备的bus指针指向port->dev.bus = &usb_serial_bus_type;所以bus_for_each_drv()最后将调用usb_serial_bus_type->match()和usb_serial_bus_type->probe()来为dev硬件自己寻找匹配的设备驱动.
流程1:insmod安装驱动函数流程[driver_attach]: //在__driver_attach()函数中会调用下面这两个函数[gliethttp_20071031]: //drv->bus->match和dev->bus->probe或者drv->probe函数 //注意:port->dev.bus = &usb_serial_bus_type; // mct_u232_device->driver.bus = &usb_serial_bus_type; 1>usb_serial_bus_type->match() --- usb_serial_device_match//内核总线提供 2>usb_serial_bus_type->probe() --- usb_serial_device_probe//内核总线提供 流程2:hub发现新硬件寻找驱动流程[device_attach]: //-----usb系统总线级----- 1>usb_bus_type->match() --- usb_device_match()//内核总线提供 //因为usb_bus_type不提供probe()函数,所以由用户驱动drvwrap.driver提供 2>mct_u232_driver->drvwrap.driver.probe() --- usb_probe_interface()//内核提供 //-----usb用户驱动自定义级----- //usb_probe_interface()会调用driver->probe()驱动,即:mct_u232_driver->probe() 3>mct_u232_driver->probe() --- usb_serial_probe()//用户自定义 //probe()会从usb_serial_driver_list总线链表上找到一个和dev匹配的usb_serial_driver指针, //并赋值给type变量,我们这里就是serial->type=&mct_u232_device;然后尝试调用type->probe() //这里就是mct_u232_device->probe(),如果找不到type,那么直接退出返回,所以这里我感觉 //可能会出现这样一种情况:必须先给usb设备安装上驱动,然后再把usb设备插到主板上,这样linux系统 //就能正常的匹配驱动和设备,否则,如果先将设备插到主板上,自匹配执行到这里之后会直接退出, //那么新插入的设备因为在bus的驱动链表上找不到匹配的driver驱动而不能登记到bus的klist_devices //设备链表上,所以新插入的设备也就失去了机会,之后insmod的驱动在bus的klist_devices //也不会找到该设备,这样insmod的驱动只是简单的把自己挂载到bus的klist_drivers驱动链表上, //要想使刚才的设备正常运行,需要重新插拔一次usb设备,所以我觉得好像必须先安装驱动, //再插入设备,否则还需要重新再插拔一次,linux的这个性质和windows不同,windows有提示界面, //当发现新插入的设备没有驱动时,会弹出提示窗,等待用户手动安装驱动[gliethttp_20071031]. 4>type->probe() --- mct_u232_device->probe()没有定义 //然后调用device_add()将port->dev注册登记到总线和系统中, //port = serial->port[i]; //port->dev.parent = &interface->dev; //port->dev.driver = NULL; //port->dev.bus = &usb_serial_bus_type; //retval = device_register(&port->dev);//将dev注册到系统 //在__device_attach()函数中会调用下面这两个函数[gliethttp_20071031]: //drv->bus->match和dev->bus->probe或者drv->probe函数 //注意:port->dev.bus = &usb_serial_bus_type; // mct_u232_device->driver.bus = &usb_serial_bus_type; 5>usb_serial_bus_type->match() --- usb_serial_device_match//内核总线提供 6>usb_serial_bus_type->probe() --- usb_serial_device_probe//内核总线提供
综述: mct_u232_device驱动位于usb_serial_bus_type总线上,mct_u232_driver驱动位于usb_bus_type总线上,当hub发现usb新硬件之后,会首先调用usb_bus_type总线上的mct_u232_driver驱动的probe(),也就是usb_serial_probe(),在usb_serial_probe()中,程序会遍历usb_serial_driver_list驱动链表的所有驱动,并尝试和发现的新硬件进行匹配,在计算匹配的过程中会调用,drv->bus->match,即:usb_serial_bus_type->match()和dev->bus->probe或者drv->probe即:usb_serial_device_probe(),这样设备就和分别处在两条独立总线上的mct_u232_driver驱动以及mct_u232_device驱动关联上了[gliethttp_20071031].
|