Chinaunix首页 | 论坛 | 博客
  • 博客访问: 569378
  • 博文数量: 70
  • 博客积分: 3736
  • 博客等级: 中校
  • 技术积分: 1728
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-08 09:15
文章分类
文章存档

2014年(1)

2012年(21)

2011年(7)

2010年(28)

2009年(13)

分类: LINUX

2012-07-13 17:55:48

usb接口驱动加载流程分析
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,
};

struct bus_type usb_bus_type = {
    .name =        "usb",
    .match =    usb_device_match,
    .uevent =    usb_uevent,
};
系统初始化时usb core会调用:
retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
此动作会:
usb_generic_driver.drvwrap.driver.bus = &usb_bus_type;
当USB设备(只有设备先被注册之后才会分析接口,才会注册接口) 被探测并被注册到系统后(用device_add),会调用usb_bus_type.mach()(只要是usb设备,都会跟 usb_generic_driver匹配上),之后会调用usb_probe_device(),从而引发usb_generic_driver的 probe()调用.

note:
usb设备首先以设备的身份与usb_generic_driver匹配,成功之后,会分裂出接口,当对接口调用device_add()后,会引起接口 和接口驱动的匹配,这个匹配还是用usb_bus_type.mach()函数。因为接口的device->bus=& usb_bus_type, 这跟usb设备是一样的,所以,都会调用到usb_bus_type.mach(),但设备和接口的处理流程是不一样的


static int generic_probe(struct usb_device *udev)
{
    int err, c;

    if (udev->authorized == 0)
        dev_err(&udev->dev, "Device is not authorized for usage\n");
    else {
        c = usb_choose_configuration(udev);
        if (c >= 0) {
            err = usb_set_configuration(udev, c);
            if (err) {
                dev_err(&udev->dev, "can't set config #%d, error %d\n",
                    c, err);
                /* This need not be fatal.  The user can try to
                 * set other configurations. */
            }
        }
    }
    usb_notify_add_device(udev);
    return 0;
}
generic_probe所做的工作:
从设备可能的众多配置中选择一个合适的,然后去配置设备,从而让设备进入期待已久的Configured状态。

int usb_choose_configuration(struct usb_device *udev);
从udev->descriptor.bNumConfigurations个配置里选择一个合适的配置(struct usb_host_config),并返回该配置的索引值
例如:我机器上的的 usb 驱动加载时,输出:
usb 1-1: configuration #1 chosen from 3 choices
表示:此设备有3个配置,而驱动最终选择了索引号为1的配置,至于选择策略是怎样的,请看usb_choose_configuration()函数

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;

    if (dev->authorized == 0 || configuration == -1)
        configuration = 0;
    else {
        for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
            if (dev->config[i].desc.bConfigurationValue ==
                    configuration) {
                cp = &dev->config[i];            //取得索引号为configuration的配置的结构体
                break;
            }
        }
    }
    if ((!cp && configuration != 0))
        return -EINVAL;

    if (cp && configuration == 0)
        dev_warn(&dev->dev, "config 0 descriptor??\n");        //假如配置的索引号为0,打出警告

    n = nintf = 0;
    if (cp) {
        nintf = cp->desc.bNumInterfaces;
        new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
                GFP_KERNEL);
        if (!new_interfaces) {
            dev_err(&dev->dev, "Out of memory\n");
            return -ENOMEM;
        }

        for (; n < nintf; ++n) {
            new_interfaces[n] = kzalloc(
                    sizeof(struct usb_interface),
                    GFP_KERNEL);
            if (!new_interfaces[n]) {
                dev_err(&dev->dev, "Out of memory\n");
                ret = -ENOMEM;
free_interfaces:
                while (--n >= 0)
                    kfree(new_interfaces[n]);
                kfree(new_interfaces);
                return ret;
            }
        }
                                //以上代码为配置的bNumInterfaces个接口分配空间
        i = dev->bus_mA - cp->desc.bMaxPower * 2;
        if (i < 0)
            dev_warn(&dev->dev, "new config #%d exceeds power "
                    "limit by %dmA\n",
                    configuration, -i);
    }

    ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                  USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
                  NULL, 0, USB_CTRL_SET_TIMEOUT);
    if (ret < 0) {
        /* All the old state is gone, so what else can we do?
         * The device is probably useless now anyway.
         */
        cp = NULL;
    }

    dev->actconfig = cp;                    //发送USB_REQ_SET_CONFIGURATION的urb信息来设置设备的配置为cp,同时记录在dev->actconfig里

    usb_set_device_state(dev, USB_STATE_CONFIGURED);    //设置设备的status 为USB_STATE_CONFIGURED

    for (i = 0; i < nintf; ++i) {
        struct usb_interface_cache *intfc;
        struct usb_interface *intf;
        struct usb_host_interface *alt;

        cp->interface[i] = intf = new_interfaces[i];
        intfc = cp->intf_cache[i];
        intf->altsetting = intfc->altsetting;
        intf->num_altsetting = intfc->num_altsetting;
        intf->intf_assoc = find_iad(dev, cp, i);
        kref_get(&intfc->ref);

        alt = usb_altnum_to_altsetting(intf, 0);

        /* No altsetting 0?  We'll assume the first altsetting.
         * We could use a GetInterface call, but if a device is
         * so non-compliant that it doesn't have altsetting 0
         * then I wouldn't trust its reply anyway.
         */
        if (!alt)
            alt = &intf->altsetting[0];

        intf->cur_altsetting = alt;
        usb_enable_interface(dev, intf, true);
        intf->dev.parent = &dev->dev;
        intf->dev.driver = NULL;
        intf->dev.bus = &usb_bus_type;
        intf->dev.type = &usb_if_device_type;
        intf->dev.groups = usb_interface_groups;
        intf->dev.dma_mask = dev->dev.dma_mask;
        INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
        device_initialize(&intf->dev);
        mark_quiesced(intf);
        dev_set_name(&intf->dev, "%d-%s:%d.%d",
            dev->bus->busnum, dev->devpath,
            configuration, alt->desc.bInterfaceNumber);    //初始化各个接口struct以及接口的dev结构
    }
    kfree(new_interfaces);

    for (i = 0; i < nintf; ++i) {
        struct usb_interface *intf = cp->interface[i];

        dev_dbg(&dev->dev,
            "adding %s (config #%d, interface %d)\n",
            dev_name(&intf->dev), configuration,
            intf->cur_altsetting->desc.bInterfaceNumber);
        ret = device_add(&intf->dev);                //将接口所对应的设备添加到系统,此动作将引发接口设备和接口驱动的匹配,从而引发接口设备驱动你的probe函数
        if (ret != 0) {
            dev_err(&dev->dev, "device_add(%s) --> %d\n",
                dev_name(&intf->dev), ret);
            continue;
        }
        create_intf_ep_devs(intf);
    }

    usb_autosuspend_device(dev);
    return 0;
}

阅读(8332) | 评论(1) | 转发(9) |
0

上一篇:arm linux 启动

下一篇:usb热插拔实现机制

给主人留下些什么吧!~~

jinxinxin1632012-07-16 09:48:03

下面拿linux里的USB鼠标驱动做个列子.在完成了枚举之后,驱动程序和USB鼠标之间通过endpoint1进行通信。驱动调用usb_submit_urb(mouse->irq,GFP_KERNEL)
mouse->irq是一个URB,简单得可以理解为要发送给鼠标的数据。
usb_submit_urb也就是把数据包提交给host control,让其把数据包发送出去。
而在usb_submit_urb之前,
usb_fill_int_urb(mouse->irq,dev,pipe,mouse->data,(maxp > 8 ? 8 : maxp),usb_mouse_irq, mouse,
endpoint->bInterval),其中乱七八糟的参数暂时不要关心,要关心的是usb_mouse_irq。这是一个函数地址,起到回调作用。也就是驱动通过usb_submit_urb把数据发送出去。当收到鼠标的正确回应之后,linux会自动去调用usb_mouse_irq来读取鼠标传回来的值