Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15496879
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2007-10-31 16:40:27

看看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].

阅读(2841) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~