Commit 49727834 authored by Lonnie Mendez's avatar Lonnie Mendez Committed by Greg Kroah-Hartman

[PATCH] usb-serial: add interrupt out support and improved debug messages

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.
Signed-off-by: default avatarLonnie Mendez <lmendez19@austin.rr.com>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 85ffd375
...@@ -458,6 +458,8 @@ static void destroy_serial(struct kref *kref) ...@@ -458,6 +458,8 @@ static void destroy_serial(struct kref *kref)
usb_free_urb(port->write_urb); usb_free_urb(port->write_urb);
usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
usb_free_urb(port->interrupt_out_urb);
kfree(port->bulk_in_buffer); kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer); kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer); kfree(port->interrupt_in_buffer);
...@@ -798,6 +800,8 @@ static void port_release(struct device *dev) ...@@ -798,6 +800,8 @@ static void port_release(struct device *dev)
usb_free_urb(port->write_urb); usb_free_urb(port->write_urb);
usb_kill_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb);
usb_free_urb(port->interrupt_in_urb); usb_free_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_out_urb);
usb_free_urb(port->interrupt_out_urb);
kfree(port->bulk_in_buffer); kfree(port->bulk_in_buffer);
kfree(port->bulk_out_buffer); kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer); kfree(port->interrupt_in_buffer);
...@@ -854,6 +858,7 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -854,6 +858,7 @@ int usb_serial_probe(struct usb_interface *interface,
struct usb_host_interface *iface_desc; struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS]; 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_in_endpoint[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
struct usb_serial_device_type *type = NULL; struct usb_serial_device_type *type = NULL;
...@@ -862,6 +867,7 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -862,6 +867,7 @@ int usb_serial_probe(struct usb_interface *interface,
int buffer_size; int buffer_size;
int i; int i;
int num_interrupt_in = 0; int num_interrupt_in = 0;
int num_interrupt_out = 0;
int num_bulk_in = 0; int num_bulk_in = 0;
int num_bulk_out = 0; int num_bulk_out = 0;
int num_ports = 0; int num_ports = 0;
...@@ -909,7 +915,7 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -909,7 +915,7 @@ int usb_serial_probe(struct usb_interface *interface,
if ((endpoint->bEndpointAddress & 0x80) && if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x02)) { ((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk in endpoint */ /* 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; bulk_in_endpoint[num_bulk_in] = endpoint;
++num_bulk_in; ++num_bulk_in;
} }
...@@ -917,7 +923,7 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -917,7 +923,7 @@ int usb_serial_probe(struct usb_interface *interface,
if (((endpoint->bEndpointAddress & 0x80) == 0x00) && if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
((endpoint->bmAttributes & 3) == 0x02)) { ((endpoint->bmAttributes & 3) == 0x02)) {
/* we found a bulk out endpoint */ /* 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; bulk_out_endpoint[num_bulk_out] = endpoint;
++num_bulk_out; ++num_bulk_out;
} }
...@@ -925,10 +931,18 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -925,10 +931,18 @@ int usb_serial_probe(struct usb_interface *interface,
if ((endpoint->bEndpointAddress & 0x80) && if ((endpoint->bEndpointAddress & 0x80) &&
((endpoint->bmAttributes & 3) == 0x03)) { ((endpoint->bmAttributes & 3) == 0x03)) {
/* we found a interrupt in endpoint */ /* 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; interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in; ++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) #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
...@@ -1005,11 +1019,13 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1005,11 +1019,13 @@ int usb_serial_probe(struct usb_interface *interface,
serial->num_bulk_in = num_bulk_in; serial->num_bulk_in = num_bulk_in;
serial->num_bulk_out = num_bulk_out; serial->num_bulk_out = num_bulk_out;
serial->num_interrupt_in = num_interrupt_in; 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 */ /* 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 */ /* 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(num_bulk_in, num_bulk_out);
max_endpoints = max(max_endpoints, num_interrupt_in); 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); max_endpoints = max(max_endpoints, (int)serial->num_ports);
serial->num_port_pointers = max_endpoints; serial->num_port_pointers = max_endpoints;
dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints); dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
...@@ -1073,6 +1089,7 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1073,6 +1089,7 @@ int usb_serial_probe(struct usb_interface *interface,
port); port);
} }
if (serial->type->read_int_callback) {
for (i = 0; i < num_interrupt_in; ++i) { for (i = 0; i < num_interrupt_in; ++i) {
endpoint = interrupt_in_endpoint[i]; endpoint = interrupt_in_endpoint[i];
port = serial->port[i]; port = serial->port[i];
...@@ -1095,6 +1112,37 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1095,6 +1112,37 @@ int usb_serial_probe(struct usb_interface *interface,
serial->type->read_int_callback, port, serial->type->read_int_callback, port,
endpoint->bInterval); 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 = 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 this device type has an attach function, call it */
if (type->attach) { if (type->attach) {
...@@ -1158,6 +1206,14 @@ int usb_serial_probe(struct usb_interface *interface, ...@@ -1158,6 +1206,14 @@ int usb_serial_probe(struct usb_interface *interface,
usb_free_urb (port->interrupt_in_urb); usb_free_urb (port->interrupt_in_urb);
kfree(port->interrupt_in_buffer); 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 the minor range that this device had */
return_serial (serial); return_serial (serial);
......
...@@ -74,6 +74,11 @@ ...@@ -74,6 +74,11 @@
* @interrupt_in_urb: pointer to the interrupt in struct urb for this port. * @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
* @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe * @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe
* for this port. * 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. * @bulk_in_buffer: pointer to the bulk in buffer for this port.
* @read_urb: pointer to the bulk in struct urb 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 * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
...@@ -99,6 +104,11 @@ struct usb_serial_port { ...@@ -99,6 +104,11 @@ struct usb_serial_port {
struct urb * interrupt_in_urb; struct urb * interrupt_in_urb;
__u8 interrupt_in_endpointAddress; __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; unsigned char * bulk_in_buffer;
int bulk_in_size; int bulk_in_size;
struct urb * read_urb; struct urb * read_urb;
...@@ -135,6 +145,7 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void ...@@ -135,6 +145,7 @@ static inline void usb_set_serial_port_data (struct usb_serial_port *port, void
* @minor: the starting minor number for this device * @minor: the starting minor number for this device
* @num_ports: the number of ports this device has * @num_ports: the number of ports this device has
* @num_interrupt_in: number of interrupt in endpoints we have * @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_in: number of bulk in endpoints we have
* @num_bulk_out: number of bulk out endpoints we have * @num_bulk_out: number of bulk out endpoints we have
* @vendor: vendor id of this device * @vendor: vendor id of this device
...@@ -153,6 +164,7 @@ struct usb_serial { ...@@ -153,6 +164,7 @@ struct usb_serial {
unsigned char num_ports; unsigned char num_ports;
unsigned char num_port_pointers; unsigned char num_port_pointers;
char num_interrupt_in; char num_interrupt_in;
char num_interrupt_out;
char num_bulk_in; char num_bulk_in;
char num_bulk_out; char num_bulk_out;
__u16 vendor; __u16 vendor;
...@@ -188,6 +200,8 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data) ...@@ -188,6 +200,8 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
* of the devices this structure can support. * of the devices this structure can support.
* @num_interrupt_in: the number of interrupt in endpoints this device will * @num_interrupt_in: the number of interrupt in endpoints this device will
* have. * 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_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_bulk_out: the number of bulk out endpoints this device will have.
* @num_ports: the number of different ports this device will have. * @num_ports: the number of different ports this device will have.
...@@ -220,6 +234,7 @@ struct usb_serial_device_type { ...@@ -220,6 +234,7 @@ struct usb_serial_device_type {
char *short_name; char *short_name;
const struct usb_device_id *id_table; const struct usb_device_id *id_table;
char num_interrupt_in; char num_interrupt_in;
char num_interrupt_out;
char num_bulk_in; char num_bulk_in;
char num_bulk_out; char num_bulk_out;
char num_ports; char num_ports;
...@@ -251,6 +266,7 @@ struct usb_serial_device_type { ...@@ -251,6 +266,7 @@ struct usb_serial_device_type {
int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); 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 (*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 (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs); void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment