📄 usbserial.c
字号:
static int generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count){ struct usb_serial *serial = port->serial; int result; dbg(__FUNCTION__ " - port %d", port->number); if (count == 0) { dbg(__FUNCTION__ " - write request of 0 bytes"); return (0); } /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) { dbg (__FUNCTION__ " - already writing"); return (0); } count = (count > port->bulk_out_size) ? port->bulk_out_size : count; if (from_user) { if (copy_from_user(port->write_urb->transfer_buffer, buf, count)) return -EFAULT; } else { memcpy (port->write_urb->transfer_buffer, buf, count); } usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); /* set up our urb */ usb_fill_bulk_urb (port->write_urb, serial->dev, usb_sndbulkpipe (serial->dev, port->bulk_out_endpointAddress), port->write_urb->transfer_buffer, count, ((serial->type->write_bulk_callback) ? serial->type->write_bulk_callback : generic_write_bulk_callback), port); /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed submitting write urb, error %d", result); else result = count; return result; } /* no bulk out, so return 0 bytes written */ return (0);}static int generic_write_room (struct usb_serial_port *port){ struct usb_serial *serial = port->serial; int room = 0; dbg(__FUNCTION__ " - port %d", port->number); if (serial->num_bulk_out) { if (port->write_urb->status != -EINPROGRESS) room = port->bulk_out_size; } dbg(__FUNCTION__ " - returns %d", room); return (room);}static int generic_chars_in_buffer (struct usb_serial_port *port){ struct usb_serial *serial = port->serial; int chars = 0; dbg(__FUNCTION__ " - port %d", port->number); if (serial->num_bulk_out) { if (port->write_urb->status == -EINPROGRESS) chars = port->write_urb->transfer_buffer_length; } dbg (__FUNCTION__ " - returns %d", chars); return (chars);}static void generic_read_bulk_callback (struct urb *urb){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int i; int result; dbg(__FUNCTION__ " - port %d", port->number); if (!serial) { dbg(__FUNCTION__ " - bad serial pointer, exiting"); return; } if (urb->status) { dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); return; } usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); tty = port->tty; if (tty && urb->actual_length) { for (i = 0; i < urb->actual_length ; ++i) { /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ if(tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } /* this doesn't actually push the data through unless tty->low_latency is set */ tty_insert_flip_char(tty, data[i], 0); } tty_flip_buffer_push(tty); } /* Continue trying to always read */ usb_fill_bulk_urb (port->read_urb, serial->dev, usb_rcvbulkpipe (serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ((serial->type->read_bulk_callback) ? serial->type->read_bulk_callback : generic_read_bulk_callback), port); result = usb_submit_urb(port->read_urb, GFP_ATOMIC); if (result) err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);}static void generic_write_bulk_callback (struct urb *urb){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); dbg(__FUNCTION__ " - port %d", port->number); if (!serial) { dbg(__FUNCTION__ " - bad serial pointer, exiting"); return; } if (urb->status) { dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status); return; } queue_task(&port->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); return;}static void generic_shutdown (struct usb_serial *serial){ int i; dbg (__FUNCTION__); /* stop reads and writes on all ports */ for (i=0; i < serial->num_ports; ++i) { generic_cleanup (&serial->port[i]); }}static void port_softint(void *private){ struct usb_serial_port *port = (struct usb_serial_port *)private; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); struct tty_struct *tty; dbg(__FUNCTION__ " - port %d", port->number); if (!serial) return; tty = port->tty; if (!tty) return; if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { dbg(__FUNCTION__ " - write wakeup call."); (tty->ldisc.write_wakeup)(tty); } wake_up_interruptible(&tty->write_wait);}static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ struct usb_serial *serial = NULL; struct usb_serial_port *port; struct usb_interface *interface; struct usb_interface_descriptor *iface_desc; struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *interrupt_in_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_device_type *type = NULL; struct list_head *tmp; int retval; int found; int minor; int buffer_size; int i; int num_interrupt_in = 0; int num_bulk_in = 0; int num_bulk_out = 0; int num_ports; int max_endpoints; const struct usb_device_id *id_pattern = NULL; /* loop through our list of known serial converters, and see if this device matches. */ found = 0; interface = &dev->actconfig->interface[ifnum]; list_for_each (tmp, &usb_serial_driver_list) { type = list_entry(tmp, struct usb_serial_device_type, driver_list); id_pattern = usb_match_id(dev, interface, type->id_table); if (id_pattern != NULL) { dbg("descriptor matches"); found = 1; break; } } if (!found) { /* no match */ dbg("none matched"); return(NULL); } /* descriptor matches, let's find the endpoints needed */ /* check out the endpoints */ iface_desc = &interface->altsetting[0]; for (i = 0; i < iface_desc->bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i]; if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk in endpoint */ dbg("found bulk in"); bulk_in_endpoint[num_bulk_in] = endpoint; ++num_bulk_in; } if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk out endpoint */ dbg("found bulk out"); bulk_out_endpoint[num_bulk_out] = endpoint; ++num_bulk_out; } if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x03)) { /* we found a interrupt in endpoint */ dbg("found interrupt in"); interrupt_in_endpoint[num_interrupt_in] = endpoint; ++num_interrupt_in; } }#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 (ifnum == 1) { if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) && (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) || ((dev->descriptor.idVendor == ATEN_VENDOR_ID) && (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) { /* check out the endpoints of the other interface*/ interface = &dev->actconfig->interface[ifnum ^ 1]; iface_desc = &interface->altsetting[0]; for (i = 0; i < iface_desc->bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i]; if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x03)) { /* 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; } } } } /* END HORRIBLE HACK FOR PL2303 */#endif /* 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; serial->vendor = dev->descriptor.idVendor; serial->product = dev->descriptor.idProduct; /* if this device type has a startup function, call it */ if (type->startup) { if (type->owner) __MOD_INC_USE_COUNT(type->owner); retval = type->startup (serial); if (type->owner) __MOD_DEC_USE_COUNT(type->owner); if (retval) 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, GFP_KERNEL); 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; } usb_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, GFP_KERNEL); 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; } usb_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, GFP_KERNEL); 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; } 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); } /* 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); max_endpoints = max(max_endpoints, (int)serial->num_ports); 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; init_MUTEX (&port->sem); } /* 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); }#ifdef CONFIG_USB_SERIAL_CONSOLE if (minor == 0) { /* * Call register_console() if this is the first device plugged * in. If we call it earlier, then the callback to * console_setup() will fail, as there is not a device seen by * the USB subsystem yet. */ /* * Register console. * NOTES: * console_setup() is called (back) immediately (from register_console). * console_write() is called immediately from register_console iff * CON_PRINTBUFFER is set in flags. */ dbg ("registering the USB serial console."); register_console(&usbcons); }#endif 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -