Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15531252
  • 博文数量: 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

2009-05-06 21:56:40

浅析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;

    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];
                break;
            }
        }
    }
    if ((!cp && configuration != 0))
        return -EINVAL;

    /* The USB spec says configuration 0 means unconfigured.
     * But if a device includes a configuration numbered 0,
     * we will accept it as a correctly configured state.
     * Use -1 if you really want to unconfigure the device.
     */
    if (cp && configuration == 0)
        dev_warn(&dev->dev, "config 0 descriptor??\n");

    /* Allocate memory for new interfaces before doing anything else,
     * so that if we run out then nothing will have changed. */
    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;
            }
        }

        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);
    }

    /* Wake up the device so we can send it the Set-Config request */
    ret = usb_autoresume_device(dev);
    if (ret)
        goto free_interfaces;

    /* if it's already configured, clear out old state first.
     * getting rid of old interfaces means unbinding their drivers.
     */
    if (dev->state != USB_STATE_ADDRESS)
        usb_disable_device(dev, 1);    /* Skip ep0 */

    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;
    if (!cp) {
        usb_set_device_state(dev, USB_STATE_ADDRESS);
        usb_autosuspend_device(dev);
        goto free_interfaces;
    }
    usb_set_device_state(dev, USB_STATE_CONFIGURED);

    /* Initialize the new interface structures and the
     * hc/hcd/usbcore interface/endpoint state.
     */
    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);
        intf->dev.parent = &dev->dev;
        intf->dev.driver = NULL;
        intf->dev.bus = &usb_bus_type; // 位于usb_bus_type总线
        intf->dev.type = &usb_if_device_type; // 为接口设备,这样在usb_device_match中将去和接口驱动去匹配[luther.gliethttp]
        intf->dev.dma_mask = dev->dev.dma_mask;
        device_initialize(&intf->dev);
        mark_quiesced(intf);
        sprintf(&intf->dev.bus_id[0], "%d-%s:%d.%d",
            dev->bus->busnum, dev->devpath,
            configuration, alt->desc.bInterfaceNumber);
    }
    kfree(new_interfaces);

    if (cp->string == NULL)
        cp->string = usb_cache_string(dev, cp->desc.iConfiguration);

    /* Now that all the interfaces are set up, register them
     * to trigger binding of drivers to interfaces.  probe()
     * routines may install different altsettings and may
     * claim() any interfaces not yet bound.  Many class drivers
     * need that: CDC, audio, video, etc.
     */
    for (i = 0; i < nintf; ++i) {
        struct usb_interface *intf = cp->interface[i];

        dev_dbg(&dev->dev,
            "adding %s (config #%d, interface %d)\n",
            intf->dev.bus_id, configuration,
            intf->cur_altsetting->desc.bInterfaceNumber);
        ret = device_add(&intf->dev); // 将接口设备添加bus总线上同时到sysfs系统中.
        if (ret != 0) {
            dev_err(&dev->dev, "device_add(%s) --> %d\n",
                intf->dev.bus_id, ret);
            continue;
        }
        usb_create_sysfs_intf_files(intf);
    }

    usb_autosuspend_device(dev);
    return 0;
}

如下是一个整体代码流程:
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_bus_type
==>usb_device_match
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
    /* devices and interfaces are handled separately */
    if (is_usb_device(dev)) {

        /* interface drivers never match devices */
        if (!is_usb_device_driver(drv))
            return 0;

        /* TODO: Add real matching code */
        return 1;

    } else {
        struct usb_interface *intf;
        struct usb_driver *usb_drv;
        const struct usb_device_id *id;

        /* device drivers never match interfaces */
        if (is_usb_device_driver(drv))
            return 0;

        intf = to_usb_interface(dev); // 转为接口dev设备
        usb_drv = to_usb_driver(drv); // 转为usb驱动

        id = usb_match_id(intf, usb_drv->id_table); // 接口设备与usb接口驱动的id_table值表进行匹配尝试[luther.gliethttp]
        if (id)
            return 1;

        id = usb_match_dynamic_id(intf, usb_drv);
        if (id)
            return 1;
    }

    return 0;
}
==>really_probe
static int really_probe(struct device *dev, struct device_driver *drv)
{
    int ret = 0;

    atomic_inc(&probe_count);
    pr_debug("bus: '%s': %s: probing driver %s with device %s\n",
         drv->bus->name, __FUNCTION__, drv->name, dev->bus_id);
    WARN_ON(!list_empty(&dev->devres_head));

    dev->driver = drv;  // 先假定该driver就是驱动本dev的驱动,后面讲做进一步确认[luther.gliethttp]
    if (driver_sysfs_add(dev)) {
        printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
            __FUNCTION__, dev->bus_id);
        goto probe_failed;
    }

    if (dev->bus->probe) {
        ret = dev->bus->probe(dev); // 如果bus总线提供probe,那么执行之
        if (ret)
            goto probe_failed;
    } else if (drv->probe) {
        ret = drv->probe(dev); // 如果driver提供probe,那么执行之,
                               // 我们这里就是new_driver->drvwrap.driver.probe = usb_probe_interface;
        if (ret)
            goto probe_failed;
    }

    driver_bound(dev);
    ret = 1;
    pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
         drv->bus->name, __FUNCTION__, dev->bus_id, drv->name);
    goto done;

probe_failed:
    devres_release_all(dev);
    driver_sysfs_remove(dev);
    dev->driver = NULL;

    if (ret != -ENODEV && ret != -ENXIO) {
        /* driver matched but the probe failed */
        printk(KERN_WARNING
               "%s: probe of %s failed with error %d\n",
               drv->name, dev->bus_id, ret);
    }
    /*
     * Ignore errors returned by ->probe so that the next driver can try
     * its luck.
     */
    ret = 0;
done:
    atomic_dec(&probe_count);
    wake_up(&probe_waitqueue);
    return ret;
}
==>usb_probe_interface 即:new_driver->drvwrap.driver.probe = usb_probe_interface;
/* called from driver core with dev locked */
static int usb_probe_interface(struct device *dev)
{
    struct usb_driver *driver = to_usb_driver(dev->driver);
    struct usb_interface *intf;
    struct usb_device *udev;
    const struct usb_device_id *id;
    int error = -ENODEV;

    dev_dbg(dev, "%s\n", __FUNCTION__);

    if (is_usb_device(dev))        /* Sanity check */
        return error;

    intf = to_usb_interface(dev);
    udev = interface_to_usbdev(intf);

    if (udev->authorized == 0) {
        dev_err(&intf->dev, "Device is not authorized for usage\n");
        return -ENODEV;
    }

    id = usb_match_id(intf, driver->id_table);
    if (!id)
        id = usb_match_dynamic_id(intf, driver);
    if (id) {
        dev_dbg(dev, "%s - got id\n", __FUNCTION__);

        error = usb_autoresume_device(udev);
        if (error)
            return error;

        /* Interface "power state" doesn't correspond to any hardware
         * state whatsoever.  We use it to record when it's bound to
         * a driver that may start I/0:  it's not frozen/quiesced.
         */
        mark_active(intf);
        intf->condition = USB_INTERFACE_BINDING;

        /* The interface should always appear to be in use
         * unless the driver suports autosuspend.
         */
        intf->pm_usage_cnt = !(driver->supports_autosuspend);

        error = driver->probe(intf, id); // 调用usb_driver驱动定义的probe函数,我们这里就是usb_serial_probe即:mct_u232_driver.probe
        if (error) {
            mark_quiesced(intf);
            intf->needs_remote_wakeup = 0;
            intf->condition = USB_INTERFACE_UNBOUND;
        } else
            intf->condition = USB_INTERFACE_BOUND;

        usb_autosuspend_device(udev);
    }

    return error;
}
==>usb_serial_probe即:mct_u232_driver.probe函数
int usb_serial_probe(struct usb_interface *interface,
                   const struct usb_device_id *id)
{
    struct usb_device *dev = interface_to_usbdev (interface);
    struct usb_serial *serial = NULL;
    struct usb_serial_port *port;
    struct usb_host_interface *iface_desc;
    struct usb_endpoint_descriptor *endpoint;
    struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS];
    struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
    struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
    struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
    struct usb_serial_driver *type = NULL;
    int retval;
    int minor;
    int buffer_size;
    int i;
    int num_interrupt_in = 0;
    int num_interrupt_out = 0;
    int num_bulk_in = 0;
    int num_bulk_out = 0;
    int num_ports = 0;
    int max_endpoints;

    lock_kernel(); /* guard against unloading a serial driver module */
    type = search_serial_device(interface); // 遍历usb_serial_driver_list链表,搜索与该interface匹配上的串口驱动,
                                            // usb_serial_driver_list链表元素由函数usb_serial_driver_list添加
                                            // 我们这里将返回type = &mct_u232_device;[luther.gliethtp]
    /*
    static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
    {
        const struct usb_device_id *id;
        struct usb_serial_driver *drv;

        list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
            id = get_iface_id(drv, iface);
            if (id)
                return drv;
        }
        return NULL;
    }
==>usb_serial_register // 添加serial驱动到usb_serial_driver_list链表上[luther.gliethttp]
    static struct usb_serial_driver mct_u232_device = {...};
    usb_serial_register(&mct_u232_device); // 注册mct_u232串口驱动到usb_serial_driver_list链表上
    int usb_serial_register(struct usb_serial_driver *driver)
    {
        int retval;

        fixup_generic(driver); // 填入driver没有定义的默认方法

        if (!driver->description)
            driver->description = driver->driver.name;

        // Add this device to our list of devices
        list_add(&driver->driver_list, &usb_serial_driver_list); // 将mct_u232_device添加到usb_serial_driver_list链表上

        retval = usb_serial_bus_register(driver);
        if (retval) {
            err("problem %d when registering driver %s", retval, driver->description);
            list_del(&driver->driver_list);
        }
        else
            info("USB Serial support registered for %s", driver->description);

        return retval;
    }
    int usb_serial_bus_register(struct usb_serial_driver *driver)
    {
        int retval;

        driver->driver.bus = &usb_serial_bus_type;
        spin_lock_init(&driver->dynids.lock);
        INIT_LIST_HEAD(&driver->dynids.list);

        retval = driver_register(&driver->driver);

        return retval;
    }
    */
    if (!type) {
        unlock_kernel();
        dbg("none matched");
        return -ENODEV;
    }

    serial = create_serial (dev, interface, type); // 创建serial串口设备
/*
static struct usb_serial * create_serial (struct usb_device *dev,
                      struct usb_interface *interface,
                      struct usb_serial_driver *driver)
{
    struct usb_serial *serial;

    serial = kzalloc(sizeof(*serial), GFP_KERNEL); // 全0空间
    if (!serial) {
        dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
        return NULL;
    }
    serial->dev = usb_get_dev(dev); // 该serial对应的usb设备描述符对应的设备结构体[luther.gliethttp]
    serial->type = driver; // 该serial对应的driver
    serial->interface = interface; // 该serial对应的interface
    kref_init(&serial->kref);
    mutex_init(&serial->disc_mutex);

    return serial;
}
*/
    if (!serial) {
        unlock_kernel();
        dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
        return -ENOMEM;
    }

    /* if this device type has a probe function, call it */
    if (type->probe) { // mct_u232_device串口驱动没有probe函数
        const struct usb_device_id *id;

        if (!try_module_get(type->driver.owner)) {
            unlock_kernel();
            dev_err(&interface->dev, "module get failed, exiting\n");
            kfree (serial);
            return -EIO;
        }

        id = get_iface_id(type, interface);
        retval = type->probe(serial, id);
        module_put(type->driver.owner);

        if (retval) {
            unlock_kernel();
            dbg ("sub driver rejected device");
            kfree (serial);
            return retval;
        }
    }

    /* descriptor matches, let's find the endpoints needed */
    /* check out the endpoints */
    iface_desc = interface->cur_altsetting; // 当前接口对应的接口描述符信息[luther.gliethttp]
    for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { // 为该接口dev设备收集端点通信管道
        endpoint = &iface_desc->endpoint[i].desc;

        if (usb_endpoint_is_bulk_in(endpoint)) {
            /* we found a bulk in endpoint */
            dbg("found bulk in on endpoint %d", i);
            bulk_in_endpoint[num_bulk_in] = endpoint; // 批量IN端点
            ++num_bulk_in;
        }

        if (usb_endpoint_is_bulk_out(endpoint)) {
            /* we found a bulk out endpoint */
            dbg("found bulk out on endpoint %d", i);
            bulk_out_endpoint[num_bulk_out] = endpoint; // 批量OUT端点
            ++num_bulk_out;
        }

        if (usb_endpoint_is_int_in(endpoint)) {
            /* we found a interrupt in endpoint */
            dbg("found interrupt in on endpoint %d", i);
            interrupt_in_endpoint[num_interrupt_in] = endpoint; // 中断IN端点
            ++num_interrupt_in;
        }

        if (usb_endpoint_is_int_out(endpoint)) {
            /* we found an interrupt out endpoint */
            dbg("found interrupt out on endpoint %d", i);
            interrupt_out_endpoint[num_interrupt_out] = endpoint; // 中断OUT端点
            ++num_interrupt_out;
        }
    }

#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
    // 执行PL2303 usb转串口设备的IN端点信息特殊处理[luther.gliethttp]
    /* BEGIN HORRIBLE HACK FOR PL2303 */
    /* this is needed due to the looney way its endpoints are set up */
    if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
         (le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
        ((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
         (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
        ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
         (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
        if (interface != dev->actconfig->interface[0]) { // 如果当前PL2303 usb转串口不等于0接口,dev->actconfig->interface[0]
            /* check out the endpoints of the other interface*/
            iface_desc = dev->actconfig->interface[0]->cur_altsetting; // 那么将0接口中的中断IN端点添加到该serial设备中
            for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
                if (usb_endpoint_is_int_in(endpoint)) {
                    /* we found a interrupt in endpoint */
                    dbg("found interrupt in for Prolific device on separate interface");
                    interrupt_in_endpoint[num_interrupt_in] = endpoint;
                    ++num_interrupt_in;
                }
            }
        }

        /* Now make sure the PL-2303 is configured correctly.
         * If not, give up now and hope this hack will work
         * properly during a later invocation of usb_serial_probe
         */
        if (num_bulk_in == 0 || num_bulk_out == 0) {
            unlock_kernel();
            dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
            kfree (serial);
            return -ENODEV;
        }
    }
    /* END HORRIBLE HACK FOR PL2303 */
#endif

#ifdef CONFIG_USB_SERIAL_GENERIC
    if (type == &usb_serial_generic_device) {
        num_ports = num_bulk_out;
        if (num_ports == 0) { // 如果是usb_serial_generic_device驱动,那么批量OUT端点务必要存在,并且可用端点个数就是批量OUT端点个数.
            unlock_kernel();
            dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
            kfree (serial);
            return -EIO;
        }
    }
#endif
    if (!num_ports) { // 好,不是usb_serial_generic_device驱动
        /* if this device type has a calc_num_ports function, call it */
        if (type->calc_num_ports) { // 是否需要调用计算函数计算端点个数
            if (!try_module_get(type->driver.owner)) {
                unlock_kernel();
                dev_err(&interface->dev, "module get failed, exiting\n");
                kfree (serial);
                return -EIO;
            }
            num_ports = type->calc_num_ports (serial);
            module_put(type->driver.owner);
        }
        if (!num_ports)
            num_ports = type->num_ports; // 由usb转串口接口驱动定义端点个数:mct_u232_device定义num_ports为1
    }

    serial->num_ports = num_ports; // 端点个数
    serial->num_bulk_in = num_bulk_in; // 批量IN端点个数
    serial->num_bulk_out = num_bulk_out; // 批量OUT端点个数
    serial->num_interrupt_in = num_interrupt_in; // 中断IN端点个数
    serial->num_interrupt_out = num_interrupt_out; // 中断OUT端点个数

#if 0
    /* check that the device meets the driver's requirements */
    if ((type->num_interrupt_in != NUM_DONT_CARE &&
                type->num_interrupt_in != num_interrupt_in)
            || (type->num_interrupt_out != NUM_DONT_CARE &&
                type->num_interrupt_out != num_interrupt_out)
            || (type->num_bulk_in != NUM_DONT_CARE &&
                type->num_bulk_in != num_bulk_in)
            || (type->num_bulk_out != NUM_DONT_CARE &&
                type->num_bulk_out != num_bulk_out)) {
        dbg("wrong number of endpoints");
        kfree(serial);
        return -EIO;
    }
#endif

    /* found all that we need */
    dev_info(&interface->dev, "%s converter detected\n",
            type->description);

    /* create our ports, we need as many as the max endpoints */
    /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
    max_endpoints = max(num_bulk_in, num_bulk_out);
    max_endpoints = max(max_endpoints, num_interrupt_in);
    max_endpoints = max(max_endpoints, num_interrupt_out);
    max_endpoints = max(max_endpoints, (int)serial->num_ports);
    serial->num_port_pointers = max_endpoints;
    unlock_kernel();

    dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
    for (i = 0; i < max_endpoints; ++i) {
        port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL); // 申请4种端点集合结构体struct usb_serial_port
        if (!port)
            goto probe_error;
        port->serial = serial;
        spin_lock_init(&port->lock);
        mutex_init(&port->mutex);
        INIT_WORK(&port->work, usb_serial_port_work); // 设置工作队列work_queue
        serial->port[i] = port;
    }

    /* set up the endpoint information */
    for (i = 0; i < num_bulk_in; ++i) {
        endpoint = bulk_in_endpoint[i];
        port = serial->port[i];
        port->read_urb = usb_alloc_urb (0, GFP_KERNEL); // 申请URB控制结构体
        if (!port->read_urb) {
            dev_err(&interface->dev, "No free urbs available\n");
            goto probe_error;
        }
        buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
        port->bulk_in_size = buffer_size; // 端点大小
        port->bulk_in_endpointAddress = endpoint->bEndpointAddress; // 端点地址
        port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL); // 端点管道数据缓冲区
        if (!port->bulk_in_buffer) {
            dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n");
            goto probe_error;
        }
        // 填充上面申请到的read_urb URB控制结构体
        usb_fill_bulk_urb (port->read_urb, dev,
                   usb_rcvbulkpipe (dev,
                               endpoint->bEndpointAddress),
                   port->bulk_in_buffer, buffer_size,
                   serial->type->read_bulk_callback, // 在mct_u232_device中定义的批量读回调函数
                   port);
    }

    for (i = 0; i < num_bulk_out; ++i) {
        endpoint = bulk_out_endpoint[i];
        port = serial->port[i];
        port->write_urb = usb_alloc_urb(0, GFP_KERNEL);// 申请URB控制结构体
        if (!port->write_urb) {
            dev_err(&interface->dev, "No free urbs available\n");
            goto probe_error;
        }
        buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
        port->bulk_out_size = buffer_size;
        port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
        port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
        if (!port->bulk_out_buffer) {
            dev_err(&interface->dev, "Couldn't allocate bulk_out_buffer\n");
            goto probe_error;
        }
        // 填充上面申请到的write_urb URB控制结构体
        usb_fill_bulk_urb (port->write_urb, dev,
                   usb_sndbulkpipe (dev,
                            endpoint->bEndpointAddress),
                   port->bulk_out_buffer, buffer_size,
                   serial->type->write_bulk_callback,// 在mct_u232_device中定义的批量写回调函数
                   port);
    }

    if (serial->type->read_int_callback) {
        for (i = 0; i < num_interrupt_in; ++i) {
            endpoint = interrupt_in_endpoint[i];
            port = serial->port[i];
            port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);// 申请URB控制结构体
            if (!port->interrupt_in_urb) {
                dev_err(&interface->dev, "No free urbs available\n");
                goto probe_error;
            }
            buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
            port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
            port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
            if (!port->interrupt_in_buffer) {
                dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
                goto probe_error;
            }
            // 填充上面申请到的interrupt_in_urb URB控制结构体
            usb_fill_int_urb (port->interrupt_in_urb, dev,
                      usb_rcvintpipe (dev,
                              endpoint->bEndpointAddress),
                      port->interrupt_in_buffer, buffer_size,
                      serial->type->read_int_callback, port, // 在mct_u232_device中定义的INT中断读回调函数
                      endpoint->bInterval);
        }
    } else if (num_interrupt_in) {
        dbg("the device claims to support interrupt in transfers, but read_int_callback is not defined");
    }
   
    if (serial->type->write_int_callback) {
        for (i = 0; i < num_interrupt_out; ++i) {
            endpoint = interrupt_out_endpoint[i];
            port = serial->port[i];
            port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);// 申请URB控制结构体
            if (!port->interrupt_out_urb) {
                dev_err(&interface->dev, "No free urbs available\n");
                goto probe_error;
            }
            buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
            port->interrupt_out_size = buffer_size;
            port->interrupt_out_endpointAddress = endpoint->bEndpointAddress;
            port->interrupt_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
            if (!port->interrupt_out_buffer) {
                dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n");
                goto probe_error;
            }
            // 填充上面申请到的interrupt_out_urb URB控制结构体
            usb_fill_int_urb (port->interrupt_out_urb, dev,
                      usb_sndintpipe (dev,
                              endpoint->bEndpointAddress),
                      port->interrupt_out_buffer, buffer_size,
                      serial->type->write_int_callback, port,// 在mct_u232_device中定义的INT中断写回调函数
                      endpoint->bInterval);
        }
    } else if (num_interrupt_out) {
        dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
    }
   
    /* if this device type has an attach function, call it */
    if (type->attach) { // mct_u232_device定义了attach方法的实现mct_u232_startup
        if (!try_module_get(type->driver.owner)) {
            dev_err(&interface->dev, "module get failed, exiting\n");
            goto probe_error;
        }
        retval = type->attach (serial);
        module_put(type->driver.owner);
        if (retval < 0)
            goto probe_error;
        if (retval > 0) {
            /* quietly accept this device, but don't bind to a serial port
             * as it's about to disappear */
            goto exit;
        }
    }

    if (get_free_serial (serial, num_ports, &minor) == NULL) { // 申请次设备号,同时:serial->port[j++]->number = i;
        dev_err(&interface->dev, "No more free serial devices\n");
        goto probe_error;
    }
    serial->minor = minor; // 该serial的次设备号为minor

    /* register all of the individual ports with the driver core */
    for (i = 0; i < num_ports; ++i) {
        port = serial->port[i];
        port->dev.parent = &interface->dev; // 接口当然为端点端口的父object
        port->dev.driver = NULL;
        port->dev.bus = &usb_serial_bus_type; // port位于usb_serial_bus_type总线
        port->dev.release = &port_release;

        snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
        dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
        retval = device_register(&port->dev); // 登记注册该port对应的dev设备信息,同样在bus总线usb_serial_bus_type上执行match动作.
        if (retval)
            dev_err(&port->dev, "Error registering port device, "
                "continuing\n");
    }

    usb_serial_console_init (debug, minor);

exit:
    /* success */
    usb_set_intfdata (interface, serial);
    return 0;

probe_error:
    for (i = 0; i < num_bulk_in; ++i) {
        port = serial->port[i];
        if (!port)
            continue;
        usb_free_urb(port->read_urb);
        kfree(port->bulk_in_buffer);
    }
    for (i = 0; i < num_bulk_out; ++i) {
        port = serial->port[i];
        if (!port)
            continue;
        usb_free_urb(port->write_urb);
        kfree(port->bulk_out_buffer);
    }
    for (i = 0; i < num_interrupt_in; ++i) {
        port = serial->port[i];
        if (!port)
            continue;
        usb_free_urb(port->interrupt_in_urb);
        kfree(port->interrupt_in_buffer);
    }
    for (i = 0; i < num_interrupt_out; ++i) {
        port = serial->port[i];
        if (!port)
            continue;
        usb_free_urb(port->interrupt_out_urb);
        kfree(port->interrupt_out_buffer);
    }

    /* free up any memory that we allocated */
    for (i = 0; i < serial->num_port_pointers; ++i)
        kfree(serial->port[i]);
    kfree (serial);
    return -EIO;
}
==>usb_serial_bus_type总线驱动port各种端点端口组合结构体
   device_register(&port->dev); // 登记注册该port对应的dev设备信息,同样在bus总线usb_serial_bus_type上执行match动作.
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,
};
==>usb_serial_device_match
static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
{
    struct usb_serial_driver *driver;
    const struct usb_serial_port *port;

    /*
     * drivers are already assigned to ports in serial_probe so it's
     * a simple check here.
     */
    port = to_usb_serial_port(dev);
    if (!port)
        return 0;

    driver = to_usb_serial_driver(drv);

    if (driver == port->serial->type) // 等于mct_u232_device驱动,那么返回1
    // port->serial在serial = create_serial (dev, interface, type); 中创建.
    // serial->type = driver; // 该serial对应的driver
        return 1;

    return 0;
}
==>usb_serial_device_probe
static int usb_serial_device_probe (struct device *dev)
{
    struct usb_serial_driver *driver;
    struct usb_serial_port *port;
    int retval = 0;
    int minor;

    port = to_usb_serial_port(dev);
    if (!port) {
        retval = -ENODEV;
        goto exit;
    }

    driver = port->serial->type;
    if (driver->port_probe) { // mct_u232_device没有port_probe
        if (!try_module_get(driver->driver.owner)) {
            dev_err(dev, "module get failed, exiting\n");
            retval = -EIO;
            goto exit;
        }
        retval = driver->port_probe (port);
        module_put(driver->driver.owner);
        if (retval)
            goto exit;
    }

    retval = device_create_file(dev, &dev_attr_port_number); // 创建sysfs文件系统中对应的文件[luther.gliethttp]
    if (retval)
        goto exit;

    minor = port->number; // 在上面的get_free_serial函数中执行了serial->port[j++]->number = i;赋值操作,所以可以为ttyUSB0,ttyUSB1,...
                          // port->number就是serial_table[port->number]数组索引号
    tty_register_device (usb_serial_tty_driver, minor, dev); // 注册次设备号为minor的tty设备,该/dev/ttyUSBx设备由usb_serial_tty_driver驱动程序管理
    dev_info(&port->serial->dev->dev,
         "%s converter now attached to ttyUSB%d\n",
         driver->description, minor);

exit:
    return retval;
}
==>tty_register_device(usb_serial_tty_driver, minor, dev);
// usb_serial_tty_driver在usb_serial_init,即:module_init(usb_serial_init);
// usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
// tty_set_operations(usb_serial_tty_driver, &serial_ops);
// tty_register_driver(usb_serial_tty_driver);==>list_add(&driver->tty_drivers, &tty_drivers);将自己添加到tty_drivers链表中
struct device *tty_register_device(struct tty_driver *driver, unsigned index,
                   struct device *device)
{
    char name[64];
    dev_t dev = MKDEV(driver->major, driver->minor_start) + index;

    if (index >= driver->num) {
        printk(KERN_ERR "Attempt to register invalid tty line number "
               " (%d).\n", index);
        return ERR_PTR(-EINVAL);
    }

    if (driver->type == TTY_DRIVER_TYPE_PTY)
        pty_line_name(driver, index, name);
    else
        tty_line_name(driver, index, name); // 非pty设备

    return device_create(tty_class, device, dev, name);
    // 创建sysfs文件系统下的文件,同时uevent到用户空间,创建/dev/ttyUSB0...等
    // 对/dev/ttyUSB0...等操作方法为tty_fops
    // /dev/ttyUSB0...等在SERIAL_TTY_MAJOR ~ SERIAL_TTY_MAJOR + SERIAL_TTY_MINORS之间的设备号读写操作均由tty_fops
    // 方法集提供,
    // tty_register_driver(usb_serial_tty_driver);
    // 比如open
    // tty_open==>tty->driver->open即:serial_ops.serial_open
}
==>tty_register_driver(usb_serial_tty_driver); // 注册驱动/dev/xxx字符设备的tty驱动程序
    dev = MKDEV(driver->major, driver->minor_start);
    error = register_chrdev_region(dev, driver->num, driver->name); // 设备号从dev到dev+driver->num个字符设备都将由该driver驱动
    cdev_init(&driver->cdev, &tty_fops); // 注册该MAJOR到MINOR之间的/dev/xxx字符设备节点对应的操作函数集为tty_fops
    cdev_add(&driver->cdev, dev, driver->num); // 添加到字符管理数值中
static const struct file_operations tty_fops = {
    .llseek        = no_llseek,
    .read        = tty_read,
    .write        = tty_write,
    .poll        = tty_poll,
    .ioctl        = tty_ioctl,
    .compat_ioctl    = tty_compat_ioctl,
    .open        = tty_open,
    .release    = tty_release,
    .fasync        = tty_fasync,
};
==>cdev_add
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
    p->dev = dev;
    p->count = count;
    return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); // 将&driver->cdev添加到cdev_map字符设备驱动管理数组中,以备下面sys_open时kobj_lookup使用[luther.gliethttp]
}

看看系统调用open函数
open("/dev/ttyUSB0")
==>chrdev_open // sys_open将调用字符设备驱动函数集中open函数chrdev_open
const struct file_operations def_chr_fops = {
    .open = chrdev_open,
};
==>kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); // 搜索上面cdev_add登记的usb_serial_tty_driver驱动 调用exact_match返回&driver->cdev.kobj
   new = container_of(kobj, struct cdev, kobj);
   inode->i_cdev = p = new; // 由上面cdev_init(&driver->cdev, &tty_fops); 初始化cdev->ops = &tty_fops
   filp->f_op = fops_get(p->ops); // 获取驱动方法集
   filp->f_op->open(inode,filp);
==>tty_open同时在tty_drivers链表上调用get_tty_driver函数搜索,
  "/dev/ttyUSB0"设备节点号对应的tty_drivers,比如搜索到usb_serial_tty_driver驱动,
  那么它就是tty->driver了.同时生成tty:init_dev(driver, index, &tty);其中index表示该字符设备为驱动管理的第index索引处设备.
  之后init_dev==>tty = alloc_tty_struct();
              ==>initialize_tty_struct(tty); // 初始化该tty的ldisc等于tty_ldisc_N_TTY即tty->ldisc = &tty_ldisc_N_TTY;
              tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));为tty->ldisc绑定线路规程
              console_init==>注册tty_ldisc_N_TTY线路规程
              tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
              struct tty_ldisc tty_ldisc_N_TTY = {
                  .magic           = TTY_LDISC_MAGIC,
                  .name            = "n_tty",
                  .open            = n_tty_open,
                  .close           = n_tty_close,
                  .flush_buffer    = n_tty_flush_buffer,
                  .chars_in_buffer = n_tty_chars_in_buffer,
                  .read            = read_chan,
                  .write           = write_chan,
                  .ioctl           = n_tty_ioctl,
                  .set_termios     = n_tty_set_termios,
                  .poll            = normal_poll,
                  .receive_buf     = n_tty_receive_buf,
                  .write_wakeup    = n_tty_write_wakeup
              };
              ==>tty->driver = driver;
              ==>tty->index = idx; // 该tty在driver中的索引值
              ==>tty_line_name(driver, idx, tty->name);
              ==>driver->ttys[idx] = tty; // dirver管理的第index个设备指针[luther.gliethttp]
              ==>(tty->ldisc.open)(tty); // 调用tty_ldisc_N_TTY.open即n_tty_open函数
  之后filp->private_data = tty;
  之后tty->driver->open
==>tty->driver->open就是usb_serial_tty_driver.open即:serial_ops.serial_open
==>serial_open // 执行设备实际打开操作
static int serial_open (struct tty_struct *tty, struct file * filp)
{
    struct usb_serial *serial;
    struct usb_serial_port *port;
    unsigned int portNumber;
    int retval;
   
    dbg("%s", __FUNCTION__);

    /* get the serial object associated with this tty pointer */
    serial = usb_serial_get_by_index(tty->index); // 就是 return serial_table[index];因为driver的串口索引就等于serial_table数组的索引.
    if (!serial) {
        tty->driver_data = NULL;
        return -ENODEV;
    }

    portNumber = tty->index - serial->minor; // 端口号为当前dev设备的串口索引index减去该serial设备登记的起始索引值,比如一个
    // serial设备可以有多个port,比如有3个,那么portNumber就可能等于0,1或者2.[luther.gliethttp]
    port = serial->port[portNumber]; // 获取'/dev/ttyUSBx'对应的port
    if (!port) {
        retval = -ENODEV;
        goto bailout_kref_put;
    }

    if (mutex_lock_interruptible(&port->mutex)) {
        retval = -ERESTARTSYS;
        goto bailout_kref_put;
    }
     
    ++port->open_count;

    /* set up our port structure making the tty driver
     * remember our port object, and us it */
    tty->driver_data = port; // 驱动driver_data似有数据为port
    port->tty = tty; // 该port服务于该tty

    if (port->open_count == 1) { // 第1次打开

        /* lock this module before we call it
         * this may fail, which means we must bail out,
         * safe because we are called with BKL held */
        if (!try_module_get(serial->type->driver.owner)) {
            retval = -ENODEV;
            goto bailout_mutex_unlock;
        }

        retval = usb_autopm_get_interface(serial->interface);
        if (retval)
            goto bailout_module_put;
        /* only call the device specific open if this
         * is the first time the port is opened */
        retval = serial->type->open(port, filp); // 执行mct_u232_device.open即:mct_u232_open
        if (retval)
            goto bailout_interface_put;
    }

    mutex_unlock(&port->mutex);
    return 0; // ok,至此sys_open工作就算彻底完成了[luther.gliethttp]

bailout_interface_put:
    usb_autopm_put_interface(serial->interface);
bailout_module_put:
    module_put(serial->type->driver.owner);
bailout_mutex_unlock:
    port->open_count = 0;
    tty->driver_data = NULL;
    port->tty = NULL;
    mutex_unlock(&port->mutex);
bailout_kref_put:
    usb_serial_put(serial);
    return retval;
}

tty_write
==>do_tty_write(ld->write, tty, file, buf, count);调用线路规程tty_ldisc_N_TTY的write函数write_chan
==>write_chan
==>tty->driver->write(tty, b, nr);就是上面的usb_serial_tty_driver.write即:serial_ops.serial_write
==>serial_write将调用port->serial->type->write(port, buf, count);就是mct_u232_device的write函数
   在usb_serial_register(&mct_u232_device);中将使用fixup_generic(driver);函数填充mct_u232_device未定义的操作函数集.
   所以mct_u232_device的write函数为usb_serial_generic_write
==>mct_u232_device.write即:usb_serial_generic_write
==>usb_serial_generic_write
==>usb_submit_urb(port->write_urb, GFP_ATOMIC); // 提交一个URB
==>usb_hcd_submit_urb(urb, mem_flags);
==>hcd->driver->urb_enqueue(hcd, urb, mem_flags);

tty_read
==>(ld->read)(tty, file, buf, count);调用线路规程tty_ldisc_N_TTY的read函数read_chan
==>read_chan
在mct_u232_device中定义了mct_u232_read_int_callback,即中断IN回调函数,当usb转串口设备从usb接口接收到数据之后,
它将执行mct_u232_read_int_callback回调函数,
static void mct_u232_read_int_callback (struct urb *urb)
{
    struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
    struct mct_u232_private *priv = usb_get_serial_port_data(port);
    struct usb_serial *serial = port->serial;
    struct tty_struct *tty;
    unsigned char *data = urb->transfer_buffer;
    int retval;
    int status = urb->status;
    unsigned long flags;

    switch (status) {
    case 0:
        /* success */
        break;
    case -ECONNRESET:
    case -ENOENT:
    case -ESHUTDOWN:
        /* this urb is terminated, clean up */
        dbg("%s - urb shutting down with status: %d",
            __FUNCTION__, status);
        return;
    default:
        dbg("%s - nonzero urb status received: %d",
            __FUNCTION__, status);
        goto exit;
    }

    if (!serial) {
        dbg("%s - bad serial pointer, exiting", __FUNCTION__);
        return;
    }

        dbg("%s - port %d", __FUNCTION__, port->number);
    usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);

    /*
     * Work-a-round: handle the 'usual' bulk-in pipe here
     */
    if (urb->transfer_buffer_length > 2) {
        int i;
        tty = port->tty;
        if (urb->actual_length) {
            for (i = 0; i < urb->actual_length ; ++i) {
                tty_insert_flip_char(tty, data[i], 0); // 将从usb接收到的数据放入tty缓冲区中[luther.gliethttp]
            }
            tty_flip_buffer_push(tty); // 唤醒pending着的read_chan函数,这样tty就收到数据了
        }
        goto exit;
    }
   
    /*
     * The interrupt-in pipe signals exceptional conditions (modem line
     * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
     */
    spin_lock_irqsave(&priv->lock, flags);
    priv->last_msr = data[MCT_U232_MSR_INDEX];
   
    /* Record Control Line states */
    mct_u232_msr_to_state(&priv->control_state, priv->last_msr);

#if 0
    /* Not yet handled. See belin_sa.c for further information */
    /* Now to report any errors */
    priv->last_lsr = data[MCT_U232_LSR_INDEX];
    /*
     * fill in the flip buffer here, but I do not know the relation
     * to the current/next receive buffer or characters.  I need
     * to look in to this before committing any code.
     */
    if (priv->last_lsr & MCT_U232_LSR_ERR) {
        tty = port->tty;
        /* Overrun Error */
        if (priv->last_lsr & MCT_U232_LSR_OE) {
        }
        /* Parity Error */
        if (priv->last_lsr & MCT_U232_LSR_PE) {
        }
        /* Framing Error */
        if (priv->last_lsr & MCT_U232_LSR_FE) {
        }
        /* Break Indicator */
        if (priv->last_lsr & MCT_U232_LSR_BI) {
        }
    }
#endif
    spin_unlock_irqrestore(&priv->lock, flags);
exit:
    retval = usb_submit_urb (urb, GFP_ATOMIC);
    if (retval)
        err ("%s - usb_submit_urb failed with result %d",
             __FUNCTION__, retval);
}

todo ...

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驱动链表的所有驱动,并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_20090430].
阅读(3331) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~