This patch adds equal support for interrupt out transfers to the usb-serial core to match the current interrupt in support. It also improves a few debug messages, nothing major. This is necessary for the cypress_m8 driver being released 9/30/04.
Signed-off-by: Lonnie Mendez <[EMAIL PROTECTED]>
--- a/drivers/usb/serial/usb-serial.c 2004-09-30 16:18:43.146802216 -0500 +++ b/drivers/usb/serial/usb-serial.c 2004-09-30 16:19:50.229604080 -0500 @@ -466,9 +466,14 @@ usb_unlink_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_in_urb); } + if (port->interrupt_out_urb) { + usb_unlink_urb(port->interrupt_out_urb); + usb_free_urb(port->interrupt_out_urb); + } kfree(port->bulk_in_buffer); kfree(port->bulk_out_buffer); kfree(port->interrupt_in_buffer); + kfree(port->interrupt_out_buffer); } } @@ -825,9 +830,14 @@ usb_unlink_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_in_urb); } + if (port->interrupt_out_urb) { + usb_unlink_urb(port->interrupt_out_urb); + usb_free_urb(port->interrupt_out_urb); + } kfree(port->bulk_in_buffer); kfree(port->bulk_out_buffer); kfree(port->interrupt_in_buffer); + kfree(port->interrupt_out_buffer); kfree(port); } @@ -862,6 +872,7 @@ 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_device_type *type = NULL; @@ -872,6 +883,7 @@ 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; @@ -928,7 +940,7 @@ if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk in endpoint */ - dbg("found bulk in"); + dbg("found bulk in on endpoint %d", i); bulk_in_endpoint[num_bulk_in] = endpoint; ++num_bulk_in; } @@ -936,7 +948,7 @@ if (((endpoint->bEndpointAddress & 0x80) == 0x00) && ((endpoint->bmAttributes & 3) == 0x02)) { /* we found a bulk out endpoint */ - dbg("found bulk out"); + dbg("found bulk out on endpoint %d", i); bulk_out_endpoint[num_bulk_out] = endpoint; ++num_bulk_out; } @@ -944,10 +956,18 @@ if ((endpoint->bEndpointAddress & 0x80) && ((endpoint->bmAttributes & 3) == 0x03)) { /* we found a interrupt in endpoint */ - dbg("found interrupt in"); + dbg("found interrupt in on endpoint %d", i); interrupt_in_endpoint[num_interrupt_in] = endpoint; ++num_interrupt_in; } + + if (((endpoint->bEndpointAddress & 0x80) == 0x00) && + ((endpoint->bmAttributes & 3) == 0x03)) { + /* 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) @@ -1024,11 +1044,13 @@ 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; /* 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; dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); @@ -1091,29 +1113,61 @@ 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) { - dev_err(&interface->dev, "No free urbs available\n"); - goto probe_error; + 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 = 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); } - buffer_size = 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; + } 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 = 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); } - 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_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->owner)) { @@ -1176,6 +1230,14 @@ 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; + if (port->interrupt_out_urb) + usb_free_urb (port->interrupt_out_urb); + kfree(port->interrupt_out_buffer); + } /* return the minor range that this device had */ return_serial (serial); --- a/drivers/usb/serial/usb-serial.h 2004-08-14 05:56:25.000000000 -0500 +++ b/drivers/usb/serial/usb-serial.h 2004-09-30 16:19:50.242602104 -0500 @@ -74,6 +74,11 @@ * @interrupt_in_urb: pointer to the interrupt in struct urb for this port. * @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe * for this port. + * @interrupt_out_buffer: pointer to the interrupt out buffer for this port. + * @interrupt_out_size: the size of the interrupt_out_buffer, in bytes. + * @interrupt_out_urb: pointer to the interrupt out struct urb for this port. + * @interrupt_out_endpointAddress: endpoint address for the interrupt out pipe + * for this port. * @bulk_in_buffer: pointer to the bulk in buffer for this port. * @read_urb: pointer to the bulk in struct urb for this port. * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this @@ -99,6 +104,11 @@ struct urb * interrupt_in_urb; __u8 interrupt_in_endpointAddress; + unsigned char * interrupt_out_buffer; + int interrupt_out_size; + struct urb * interrupt_out_urb; + __u8 interrupt_out_endpointAddress; + unsigned char * bulk_in_buffer; struct urb * read_urb; __u8 bulk_in_endpointAddress; @@ -134,6 +144,7 @@ * @minor: the starting minor number for this device * @num_ports: the number of ports this device has * @num_interrupt_in: number of interrupt in endpoints we have + * @num_interrupt_out: number of interrupt out endpoints we have * @num_bulk_in: number of bulk in endpoints we have * @num_bulk_out: number of bulk out endpoints we have * @vendor: vendor id of this device @@ -152,6 +163,7 @@ unsigned char num_ports; unsigned char num_port_pointers; char num_interrupt_in; + char num_interrupt_out; char num_bulk_in; char num_bulk_out; __u16 vendor; @@ -187,6 +199,8 @@ * of the devices this structure can support. * @num_interrupt_in: the number of interrupt in endpoints this device will * have. + * @num_interrupt_out: the number of interrupt out endpoints this device will + * have. * @num_bulk_in: the number of bulk in endpoints this device will have. * @num_bulk_out: the number of bulk out endpoints this device will have. * @num_ports: the number of different ports this device will have. @@ -219,6 +233,7 @@ char *short_name; const struct usb_device_id *id_table; char num_interrupt_in; + char num_interrupt_out; char num_bulk_in; char num_bulk_out; char num_ports; @@ -250,6 +265,7 @@ int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); void (*read_int_callback)(struct urb *urb, struct pt_regs *regs); + void (*write_int_callback)(struct urb *urb, struct pt_regs *regs); void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs); void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs); };