📄 usbserial.c
字号:
) {
/* nope, they don't match what we expected */
info("descriptors matched, but endpoints did not");
return NULL;
}
/* found all that we need */
info("%s converter detected", type->name);
#ifdef CONFIG_USB_SERIAL_GENERIC
if(type == &generic_device) {
num_ports = num_bulk_out;
if(num_ports == 0) {
err("Generic device with no bulk out, not allowed.");
return NULL;
}
}
else
#endif
num_ports = type->num_ports;
serial = get_free_serial(num_ports, &minor);
if(serial == NULL) {
err("No more free serial devices");
return NULL;
}
serial->dev = dev;
serial->type = type;
serial->interface = interface;
serial->minor = minor;
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;
/* if this device type has a startup function, call it */
if(type->startup) {
if(type->startup(serial)) {
goto probe_error;
}
}
/* 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);
if(!port->read_urb) {
err("No free urbs available");
goto probe_error;
}
buffer_size = endpoint->wMaxPacketSize;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if(!port->bulk_in_buffer) {
err("Couldn't allocate bulk_in_buffer");
goto probe_error;
}
FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress), port->bulk_in_buffer,
buffer_size,
((serial->type->read_bulk_callback) ? serial->type->read_bulk_callback : generic_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);
if(!port->write_urb) {
err("No free urbs available");
goto probe_error;
}
buffer_size = 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) {
err("Couldn't allocate bulk_out_buffer");
goto probe_error;
}
FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe(dev, endpoint->bEndpointAddress), port->bulk_out_buffer,
buffer_size,
((serial->type->write_bulk_callback) ? serial->type->write_bulk_callback : generic_write_bulk_callback),
port);
}
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);
if(!port->interrupt_in_urb) {
err("No free urbs available");
goto probe_error;
}
buffer_size = endpoint->wMaxPacketSize;
port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if(!port->interrupt_in_buffer) {
err("Couldn't allocate interrupt_in_buffer");
goto probe_error;
}
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);
}
/* initialize some parts of the port structures */
/* 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);
dbg(__FUNCTION__ " - setting up %d port structures for this device", max_endpoints);
for(i = 0; i < max_endpoints; ++i) {
port = &serial->port[i];
port->number = i + serial->minor;
port->serial = serial;
port->magic = USB_SERIAL_PORT_MAGIC;
port->tqueue.routine = port_softint;
port->tqueue.data = port;
spin_lock_init(&port->port_lock);
}
/* initialize the devfs nodes for this device and let the user know what ports we are bound to */
for(i = 0; i < serial->num_ports; ++i) {
tty_register_devfs(&serial_tty_driver, 0, serial->port[i].number);
info("%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)", type->name, serial->port[i].number,
serial->port[i].number);
}
return serial; /* success */
probe_error:
for(i = 0; i < num_bulk_in; ++i) {
port = &serial->port[i];
if(port->read_urb)
usb_free_urb(port->read_urb);
if(port->bulk_in_buffer)
kfree(port->bulk_in_buffer);
}
for(i = 0; i < num_bulk_out; ++i) {
port = &serial->port[i];
if(port->write_urb)
usb_free_urb(port->write_urb);
if(port->bulk_out_buffer)
kfree(port->bulk_out_buffer);
}
for(i = 0; i < num_interrupt_in; ++i) {
port = &serial->port[i];
if(port->interrupt_in_urb)
usb_free_urb(port->interrupt_in_urb);
if(port->interrupt_in_buffer)
kfree(port->interrupt_in_buffer);
}
/* return the minor range that this device had */
return_serial(serial);
/* free up any memory that we allocated */
kfree(serial);
return NULL;
}
static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
{
struct usb_serial *serial = (struct usb_serial *)ptr;
struct usb_serial_port *port;
int i;
if(serial) {
/* fail all future close/read/write/ioctl/etc calls */
for(i = 0; i < serial->num_ports; ++i) {
if(serial->port[i].tty != NULL)
serial->port[i].tty->driver_data = NULL;
}
if(serial->type->shutdown)
serial->type->shutdown(serial);
for(i = 0; i < serial->num_ports; ++i)
serial->port[i].active = 0;
for(i = 0; i < serial->num_bulk_in; ++i) {
port = &serial->port[i];
if(port->read_urb) {
usb_unlink_urb(port->read_urb);
usb_free_urb(port->read_urb);
}
if(port->bulk_in_buffer)
kfree(port->bulk_in_buffer);
}
for(i = 0; i < serial->num_bulk_out; ++i) {
port = &serial->port[i];
if(port->write_urb) {
usb_unlink_urb(port->write_urb);
usb_free_urb(port->write_urb);
}
if(port->bulk_out_buffer)
kfree(port->bulk_out_buffer);
}
for(i = 0; i < serial->num_interrupt_in; ++i) {
port = &serial->port[i];
if(port->interrupt_in_urb) {
usb_unlink_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb);
}
if(port->interrupt_in_buffer)
kfree(port->interrupt_in_buffer);
}
for(i = 0; i < serial->num_ports; ++i) {
tty_unregister_devfs(&serial_tty_driver, serial->port[i].number);
info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->port[i].number);
}
/* return the minor range that this device had */
return_serial(serial);
/* free up any memory that we allocated */
kfree(serial);
}
else {
info("device disconnected");
}
}
static struct tty_driver serial_tty_driver =
{
magic:
TTY_DRIVER_MAGIC,
driver_name : "usb-serial",
name : "usb/tts/%d",
major : SERIAL_TTY_MAJOR,
minor_start : 0,
num : SERIAL_TTY_MINORS,
type : TTY_DRIVER_TYPE_SERIAL,
subtype : SERIAL_TYPE_NORMAL,
flags : TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
refcount : &serial_refcount,
table : serial_tty,
termios : serial_termios,
termios_locked : serial_termios_locked,
open : serial_open,
close : serial_close,
write : serial_write,
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,
};
int usb_serial_init(void)
{
int i;
int result;
/* Initalize our global data */
for(i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
/* register the tty driver */
serial_tty_driver.init_termios = tty_std_termios;
serial_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
if(tty_register_driver(&serial_tty_driver)) {
err(__FUNCTION__ " - failed to register tty driver");
return -1;
}
#ifdef CONFIG_USB_SERIAL_GENERIC
generic_device_ids[0].idVendor = vendor;
generic_device_ids[0].idProduct = product;
generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
/* register our generic driver with ourselves */
usb_serial_register(&generic_device);
#endif
/* register the USB driver */
result = usb_register(&usb_serial_driver);
if(result < 0) {
tty_unregister_driver(&serial_tty_driver);
err("usb_register failed for the usb-serial driver. Error number %d", result);
return -1;
}
return 0;
}
void usb_serial_exit(void)
{
#ifdef CONFIG_USB_SERIAL_GENERIC
/* remove our generic driver */
usb_serial_deregister(&generic_device);
#endif
usb_deregister(&usb_serial_driver);
tty_unregister_driver(&serial_tty_driver);
}
module_init(usb_serial_init);
module_exit(usb_serial_exit);
int usb_serial_register(struct usb_serial_device_type *new_device)
{
/* Add this device to our list of devices */
list_add(&new_device->driver_list, &usb_serial_driver_list);
info("USB Serial support registered for %s", new_device->name);
usb_scan_devices();
return 0;
}
void usb_serial_deregister(struct usb_serial_device_type *device)
{
struct usb_serial *serial;
int i;
info("USB Serial deregistering driver %s", device->name);
/* clear out the serial_table if the device is attached to a port */
for(i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial = serial_table[i];
if((serial != NULL) && (serial->type == device)) {
usb_driver_release_interface(&usb_serial_driver, serial->interface);
usb_serial_disconnect(NULL, serial);
}
}
list_del(&device->driver_list);
}
/* If the usb-serial core is build into the core, the usb-serial drivers
need these symbols to load properly as modules. */
EXPORT_SYMBOL(usb_serial_register);
EXPORT_SYMBOL(usb_serial_deregister);
#ifdef USES_EZUSB_FUNCTIONS
EXPORT_SYMBOL(ezusb_writememory);
EXPORT_SYMBOL(ezusb_set_reset);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -