Chinaunix首页 | 论坛 | 博客
  • 博客访问: 76038
  • 博文数量: 19
  • 博客积分: 760
  • 博客等级: 军士长
  • 技术积分: 231
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-07 20:18
文章分类

全部博文(19)

文章存档

2011年(2)

2010年(17)

我的朋友

分类: LINUX

2010-05-19 17:05:03

浅析usb转serial串口设备在linux内核中枚举创建及生成tty设备的全过程

1.usb_register和usb_register_driver用来注册一个interface接口驱动for_devices = 0;
2.usb_register_device_driver用来注册一个usb设备驱动,for_devices = 1;用来解析设备描述符,
  进而生成配置描述符下的功能接口,尝试匹配usb_register_driver注册的接口驱动来驱动该usb设备的功能接口.[luther.gliethttp]

在整个kernel中,只有usb_init即[subsys_initcall(usb_init)]一处调用了usb_register_device_driver函数,
usb_register_device_driver(&usb_generic_driver, THIS_MODULE);所以所有通过hub_thread检测到插入的usb设备也都将调用到
generic_probe设备枚举函数,我们这里需要提到一些usb通信方面的知识,以便我们能够透彻理解kernel中usb代码,
一个插入到HUB上的usb设备使用4种描述符来描述自己,
(1) 设备描述符
(2) 配置描述符
(3) 接口描述符
(4) 端点描述符
一个usb设备只能有1个设备描述符,1个设备描述符可以有多个配置描述符,然后每个配置描述符下面又可以有多个接口描述符用来
具体描述一个设备在该配置下的一个或多个独立功能,每个接口下面又由端点描述符来具体声明该功能接口在usb物理通信中使用哪几个
端点管道来执行usb物理信道的实际收发工作[luther.gliethttp].
所以一个usb设备的具体功能是由接口描述符来描述的,因此我们开发的usb driver也就几乎99.9%都在使用usb_register函数来实现一个
接口对应的驱动,进而驱动usb设备上该接口对应的具体功能,比如UMS.[luther.gliethttp]
当kernel使用generic_probe()函数完成插入到HUB上的usb设备的合法检验之后,将调用设置配置描述符操作usb_set_configuration,
生成该配置描述符下面若干个接口描述符对应的dev设备,
usb_set_configuration
==>device_add(&intf->dev);
// 这样该接口dev将扫描usb_bus_type总线上的所有drivers驱动,kernel尝试为该接口dev找到驱动它的driver.[luther.gliethttp]
如下几个函数中都会调用到usb_set_configuration
usb_authorize_device    // 以sysfs中attr性质存在,这样用户空间的程序就可以通过attr属性文件来强制控制接口驱动的关联.
usb_deauthorize_device
driver_set_config_work
proc_setconfig
set_bConfigurationValue
generic_disconnect
generic_probe

usb设备的检测工作是通过内核线程hub_thread完成的.
usb_hub_init==>khubd_task = kthread_run(hub_thread, NULL, "khubd"); // 创建内核线程hub_thread,监控hub上usb设备的插拔情况
hub_thread
==>hub_events
==>hub_port_connect_change==>udev =usb_alloc_dev // 添加usb设备
==>hub_port_connect_change==>usb_new_device(udev)==>device_add(&udev->dev); // 将检测到的usb设备添加到usb_bus_type总线上,
// 该dev的type值为usb_device_type,最后函数执行device_add==>bus_add_device实现具体添加操作[luther.gliethttp]
// bus_add_device将调用上面usb_register_device_driver(&usb_generic_driver, THIS_MODULE);注册的唯一一个设备描述符解析驱动
// usb_generic_driver==>generic_probe来完成接口设备生成和相应的接口设备驱动关联动作[luther.gliethttp].
usb_add_hcd==>usb_alloc_dev // 添加HCD
usb_alloc_dev
==>dev->dev.bus = &usb_bus_type;设置dev为usb总线上的设备
==>dev->dev.type = &usb_device_type;设置该dev为usb设备而非接口

driver_register或者device_register
调用driver_attach或者bus_attach_device==>device_attach
来为设备尝试匹配驱动或者为驱动尝试添加设备,不论是哪一种情况,都将
执行到:driver_probe_device函数.
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    int ret = 0;

    if (!device_is_registered(dev)) // 1.设备已经完成了注册到bus总线工作
        return -ENODEV;
    if (drv->bus->match && !drv->bus->match(dev, drv)) // 2.执行bus提供的match操作usb_device_match
        goto done;

    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
         drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);

    ret = really_probe(dev, drv); // bus的match通过检验,这里做进一步的probe检验,
    // 如果bus提供了probe,那么执行bus->probe(dev);
    // 否则执行driver提供的probe函数drv->probe(dev);

done:
    return ret;
}

usb_register(&mct_u232_driver);
==>usb_register_driver
    new_driver->drvwrap.for_devices = 0; // 仅仅用来驱动interface接口,所以上面hub_port_connect_change由usb_alloc_dev生成的usb设备不会调用该usb接口驱动
    new_driver->drvwrap.driver.bus = &usb_bus_type;
    new_driver->drvwrap.driver.probe = usb_probe_interface; // 当检测到usb设备插入后,将调用usb_probe_interface进行细致处理
    // 提供为device_driver提供probe处理函数,因为bus总线usb_bus_type不提供probe操作[luther.gliethttp]
==>driver_register(&new_driver->drvwrap.driver); // 将驱动添加到usb bus总线管理的driver驱动链表上

usb_device_match==>is_usb_device
static inline int is_usb_device(const struct device *dev)
{
    return dev->type == &usb_device_type;
}

开看看驱动hub_thread==>usb_alloc_dev创建的插入到HUB上的usb设备的probe函数generic_probe.[luther.gliethttp]
subsys_initcall(usb_init);
==>usb_init
==>usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
struct usb_device_driver usb_generic_driver = {
    .name =    "usb",
    .probe = generic_probe,
    .disconnect = generic_disconnect,
#ifdef    CONFIG_PM
    .suspend = generic_suspend,
    .resume = generic_resume,
#endif
    .supports_autosuspend = 1,
};
==>generic_probe
==>usb_set_configuration // 生成该设置配置描述下的所有接口描述符所描述的接口dev对象
==>ret = device_add(&intf->dev);

int usb_set_configuration(struct usb_device *dev, int configuration)
{
    int i, ret;
    struct usb_host_config *cp = NULL;
    struct usb_interface **new_interfaces = NULL;
    int n, nintf;

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