usb-serial.c

这两周都在调GPS, 用的是usb转串口的pl2303芯片,所以涉及到了usb-serial驱动,见解如下。

int usb_serial_register(struct usb_serial_driver *driver)
{
    /* must be called with BKL held */
    int retval;

    if (usb_disabled())
        return -ENODEV;

    fixup_generic(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);

    retval = usb_serial_bus_register(driver);
    if (retval) {
        printk(KERN_ERR "usb-serial: problem %d when registering "
         "driver %s\n", retval, driver->description);
        list_del(&driver->driver_list);
    } else
        printk(KERN_INFO "USB Serial support registered for %s\n",
                        driver->description);

    return retval;
}
EXPORT_SYMBOL_GPL(usb_serial_register);


void usb_serial_deregister(struct usb_serial_driver *device)
{
    /* must be called with BKL held */
    printk(KERN_INFO "USB Serial deregistering driver %s\n",
     device->description);
    list_del(&device->driver_list);
    usb_serial_bus_deregister(device);
}
EXPORT_SYMBOL_GPL(usb_serial_deregister);

/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
static int __init usb_serial_init(void)
{
    int i;
    int result;

    usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
    if (!usb_serial_tty_driver)
        return -ENOMEM;

    /* Initialize our global data */
    for (i = 0; i < SERIAL_TTY_MINORS; ++i)
        serial_table[i] = NULL;

    result = bus_register(&usb_serial_bus_type);
    if (result) {
        printk(KERN_ERR "usb-serial: %s - registering bus driver "
         "failed\n", __func__);
        goto exit_bus;
    }

    usb_serial_tty_driver->owner = THIS_MODULE;
    usb_serial_tty_driver->driver_name = "usbserial";
    usb_serial_tty_driver->name =     "ttyUSB";
    usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
    usb_serial_tty_driver->minor_start = 0;
    usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
    usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
    usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW |
                        TTY_DRIVER_DYNAMIC_DEV;
    usb_serial_tty_driver->init_termios = tty_std_termios;
    usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD
                            | HUPCL | CLOCAL;
    usb_serial_tty_driver->init_termios.c_ispeed = 9600;
    usb_serial_tty_driver->init_termios.c_ospeed = 9600;
    tty_set_operations(usb_serial_tty_driver, &serial_ops);
    result = tty_register_driver(usb_serial_tty_driver);
    if (result) {
        printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
         __func__);
        goto exit_reg_driver;
    }

    /* register the USB driver */
    result = usb_register(&usb_serial_driver);
    if (result < 0) {
        printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
         __func__);
        goto exit_tty;
    }

    /* register the generic driver, if we should */
    result = usb_serial_generic_register(debug);
    if (result < 0) {
        printk(KERN_ERR "usb-serial: %s - registering generic "
         "driver failed\n", __func__);
        goto exit_generic;
    }

    printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");

    return result;

exit_generic:
    usb_deregister(&usb_serial_driver);

exit_tty:
    tty_unregister_driver(usb_serial_tty_driver);

exit_reg_driver:
    bus_unregister(&usb_serial_bus_type);

exit_bus:
    printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
     __func__, result);
    put_tty_driver(usb_serial_tty_driver);
    return result;
}


static void __exit usb_serial_exit(void)
{
    usb_serial_console_exit();

    usb_serial_generic_deregister();

    usb_deregister(&usb_serial_driver);
    tty_unregister_driver(usb_serial_tty_driver);
    put_tty_driver(usb_serial_tty_driver);
    bus_unregister(&usb_serial_bus_type);
}


module_init(usb_serial_init);
module_exit(usb_serial_exit);
static const struct tty_operations serial_ops = {
    .open =            serial_open,
    .close =        serial_close,
    .write =        serial_write,
    .hangup =         serial_hangup,
    .write_room =        serial_write_room,
    .ioctl =        serial_ioctl,
    .set_termios =        serial_set_termios,
    .throttle =        serial_throttle,
    .unthrottle =        serial_unthrottle,
    .break_ctl =        serial_break,
    .chars_in_buffer =    serial_chars_in_buffer,
    .tiocmget =        serial_tiocmget,
    .tiocmset =        serial_tiocmset,
    .shutdown =         serial_release,
    .install =         serial_install,
    .proc_fops =        &serial_proc_fops,
};


struct tty_driver *usb_serial_tty_driver;
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;
    unsigned 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);
    if (!type) {
        unlock_kernel();
        dbg("none matched");
        return -ENODEV;
    }

    serial = create_serial(dev, interface, type);
    if (!serial) {
        unlock_kernel();
        dev_err(&interface->dev, "%s - out of memory\n", __func__);
        return -ENOMEM;
    }

    /* if this device type has a probe function, call it */
    if (type->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;
    for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
        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;
            ++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;
            ++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;
            ++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;
            ++num_interrupt_out;
        }
    }

#if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
    /* 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)) ||
     ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
     (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
        if (interface != dev->actconfig->interface[0]) {
            /* check out the endpoints of the other interface*/
            iface_desc = dev->actconfig->interface[0]->cur_altsetting;
            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) {
            unlock_kernel();
            dev_err(&interface->dev,
             "Generic device with no bulk out, not allowed.\n");
            kfree(serial);
            return -EIO;
        }
    }
#endif
    if (!num_ports) {
        /* 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;
    }

    serial->num_ports = num_ports;
    serial->num_bulk_in = num_bulk_in;
    serial->num_bulk_out = num_bulk_out;
    serial->num_interrupt_in = num_interrupt_in;
    serial->num_interrupt_out = num_interrupt_out;

    /* 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 because 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",
                        __func__, max_endpoints);
    for (i = 0; i < max_endpoints; ++i) {
        port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
        if (!port)
            goto probe_error;
        tty_port_init(&port->port);
        port->port.ops = &serial_port_ops;
        port->serial = serial;
        spin_lock_init(&port->lock);
        mutex_init(&port->mutex);
        INIT_WORK(&port->work, usb_serial_port_work);
        serial->port[i] = port;
        port->dev.parent = &interface->dev;
        port->dev.driver = NULL;
        port->dev.bus = &usb_serial_bus_type;
        port->dev.release = &port_release;
        device_initialize(&port->dev);
    }

    /* 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);
        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;
        }
        usb_fill_bulk_urb(port->read_urb, dev,
                usb_rcvbulkpipe(dev,
                        endpoint->bEndpointAddress),
                port->bulk_in_buffer, buffer_size,
                serial->type->read_bulk_callback, 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);
        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;
        }
        usb_fill_bulk_urb(port->write_urb, dev,
                usb_sndbulkpipe(dev,
                    endpoint->bEndpointAddress),
                port->bulk_out_buffer, buffer_size,
                serial->type->write_bulk_callback, 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);
            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;
            }
            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,
                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);
            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;
            }
            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,
                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) {
        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 */
            serial->num_ports = 0;
            goto exit;
        }
    }

    if (get_free_serial(serial, num_ports, &minor) == NULL) {
        dev_err(&interface->dev, "No more free serial devices\n");
        goto probe_error;
    }
    serial->minor = minor;

    /* register all of the individual ports with the driver core */
    for (i = 0; i < num_ports; ++i) {
        port = serial->port[i];
        dev_set_name(&port->dev, "ttyUSB%d", port->number);
        dbg ("%s - registering %s", __func__, dev_name(&port->dev));
        port->dev_state = PORT_REGISTERING;
        retval = device_add(&port->dev);
        if (retval) {
            dev_err(&port->dev, "Error registering port device, "
                "continuing\n");
            port->dev_state = PORT_UNREGISTERED;
        } else {
            port->dev_state = PORT_REGISTERED;
        }
    }

    usb_serial_console_init(debug, minor);

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

probe_error:
    usb_serial_put(serial);
    return -EIO;
}
EXPORT_SYMBOL_GPL(usb_serial_probe);

void usb_serial_disconnect(struct usb_interface *interface)
{
    int i;
    struct usb_serial *serial = usb_get_intfdata(interface);
    struct device *dev = &interface->dev;
    struct usb_serial_port *port;

    usb_serial_console_disconnect(serial);
    dbg("%s", __func__);

    mutex_lock(&serial->disc_mutex);
    usb_set_intfdata(interface, NULL);
    /* must set a flag, to signal subdrivers */
    serial->disconnected = 1;
    mutex_unlock(&serial->disc_mutex);

    for (i = 0; i < serial->num_ports; ++i) {
        port = serial->port[i];
        if (port) {
            struct tty_struct *tty = tty_port_tty_get(&port->port);
            if (tty) {
                tty_vhangup(tty);
                tty_kref_put(tty);
            }
            kill_traffic(port);
            cancel_work_sync(&port->work);
            if (port->dev_state == PORT_REGISTERED) {

                /* Make sure the port is bound so that the
                 * driver's port_remove method is called.
                 */
                if (!port->dev.driver) {
                    int rc;

                    port->dev.driver =
                            &serial->type->driver;
                    rc = device_bind_driver(&port->dev);
                }
                port->dev_state = PORT_UNREGISTERING;
                device_del(&port->dev);
                port->dev_state = PORT_UNREGISTERED;
            }
        }
    }
    serial->type->disconnect(serial);

    /* let the last holder of this object cause it to be cleaned up */
    usb_serial_put(serial);
    dev_info(dev, "device disconnected\n");
}
EXPORT_SYMBOL_GPL(usb_serial_disconnect);

int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
{
    struct usb_serial *serial = usb_get_intfdata(intf);
    struct usb_serial_port *port;
    int i, r = 0;

    serial->suspending = 1;

    for (i = 0; i < serial->num_ports; ++i) {
        port = serial->port[i];
        if (port)
            kill_traffic(port);
    }

    if (serial->type->suspend)
        r = serial->type->suspend(serial, message);

    return r;
}
EXPORT_SYMBOL(usb_serial_suspend);

int usb_serial_resume(struct usb_interface *intf)
{
    struct usb_serial *serial = usb_get_intfdata(intf);
    int rv;

    serial->suspending = 0;
    if (serial->type->resume)
        rv = serial->type->resume(serial);
    else
        rv = usb_serial_generic_resume(serial);

    return rv;
}
EXPORT_SYMBOL(usb_serial_resume);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值