Commit 1546e6ae authored by Johan Hovold's avatar Johan Hovold

USB: serial: refactor and clean up endpoint handling

Refactor and clean up endpoint handling.

This specifically moves the endpoint-descriptor arrays of the stack.

Note that an err_free_epds label is not yet added to avoid a compilation
warning when neither CONFIG_USB_SERIAL_PL2303 or
CONFIG_USB_SERIAL_GENERIC is selected.
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parent ef88f33f
...@@ -710,6 +710,53 @@ static const struct tty_port_operations serial_port_ops = { ...@@ -710,6 +710,53 @@ static const struct tty_port_operations serial_port_ops = {
.shutdown = serial_port_shutdown, .shutdown = serial_port_shutdown,
}; };
struct usb_serial_endpoints {
unsigned char num_bulk_in;
unsigned char num_bulk_out;
unsigned char num_interrupt_in;
unsigned char num_interrupt_out;
struct usb_endpoint_descriptor *bulk_in[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *bulk_out[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *interrupt_in[MAX_NUM_PORTS];
struct usb_endpoint_descriptor *interrupt_out[MAX_NUM_PORTS];
};
static void find_endpoints(struct usb_serial *serial,
struct usb_serial_endpoints *epds)
{
struct device *dev = &serial->interface->dev;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *epd;
unsigned int i;
iface_desc = serial->interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
epd = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_in(epd)) {
dev_dbg(dev, "found bulk in on endpoint %u\n", i);
if (epds->num_bulk_in == MAX_NUM_PORTS)
continue;
epds->bulk_in[epds->num_bulk_in++] = epd;
} else if (usb_endpoint_is_bulk_out(epd)) {
dev_dbg(dev, "found bulk out on endpoint %u\n", i);
if (epds->num_bulk_out == MAX_NUM_PORTS)
continue;
epds->bulk_out[epds->num_bulk_out++] = epd;
} else if (usb_endpoint_is_int_in(epd)) {
dev_dbg(dev, "found interrupt in on endpoint %u\n", i);
if (epds->num_interrupt_in == MAX_NUM_PORTS)
continue;
epds->interrupt_in[epds->num_interrupt_in++] = epd;
} else if (usb_endpoint_is_int_out(epd)) {
dev_dbg(dev, "found interrupt out on endpoint %u\n", i);
if (epds->num_interrupt_out == MAX_NUM_PORTS)
continue;
epds->interrupt_out[epds->num_interrupt_out++] = epd;
}
}
}
static int usb_serial_probe(struct usb_interface *interface, static int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
...@@ -717,21 +764,13 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -717,21 +764,13 @@ static int usb_serial_probe(struct usb_interface *interface,
struct usb_device *dev = interface_to_usbdev(interface); struct usb_device *dev = interface_to_usbdev(interface);
struct usb_serial *serial = NULL; struct usb_serial *serial = NULL;
struct usb_serial_port *port; struct usb_serial_port *port;
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_serial_endpoints *epds;
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; struct usb_serial_driver *type = NULL;
int retval; int retval;
int buffer_size; int buffer_size;
int i; int i;
int j; int j;
unsigned char num_interrupt_in = 0;
unsigned char num_interrupt_out = 0;
unsigned char num_bulk_in = 0;
unsigned char num_bulk_out = 0;
int num_ports = 0; int num_ports = 0;
unsigned char max_endpoints; unsigned char max_endpoints;
...@@ -770,50 +809,14 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -770,50 +809,14 @@ static int usb_serial_probe(struct usb_interface *interface,
} }
/* descriptor matches, let's find the endpoints needed */ /* descriptor matches, let's find the endpoints needed */
/* check out the endpoints */ epds = kzalloc(sizeof(*epds), GFP_KERNEL);
iface_desc = interface->cur_altsetting; if (!epds) {
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { retval = -ENOMEM;
endpoint = &iface_desc->endpoint[i].desc; goto err_put_serial;
if (usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
dev_dbg(ddev, "found bulk in on endpoint %d\n", i);
if (num_bulk_in < MAX_NUM_PORTS) {
bulk_in_endpoint[num_bulk_in] = endpoint;
++num_bulk_in;
}
}
if (usb_endpoint_is_bulk_out(endpoint)) {
/* we found a bulk out endpoint */
dev_dbg(ddev, "found bulk out on endpoint %d\n", i);
if (num_bulk_out < MAX_NUM_PORTS) {
bulk_out_endpoint[num_bulk_out] = endpoint;
++num_bulk_out;
}
}
if (usb_endpoint_is_int_in(endpoint)) {
/* we found a interrupt in endpoint */
dev_dbg(ddev, "found interrupt in on endpoint %d\n", i);
if (num_interrupt_in < MAX_NUM_PORTS) {
interrupt_in_endpoint[num_interrupt_in] =
endpoint;
++num_interrupt_in;
}
}
if (usb_endpoint_is_int_out(endpoint)) {
/* we found an interrupt out endpoint */
dev_dbg(ddev, "found interrupt out on endpoint %d\n", i);
if (num_interrupt_out < MAX_NUM_PORTS) {
interrupt_out_endpoint[num_interrupt_out] =
endpoint;
++num_interrupt_out;
}
}
} }
find_endpoints(serial, epds);
#if IS_ENABLED(CONFIG_USB_SERIAL_PL2303) #if IS_ENABLED(CONFIG_USB_SERIAL_PL2303)
/* BEGIN HORRIBLE HACK FOR PL2303 */ /* BEGIN HORRIBLE HACK FOR PL2303 */
/* this is needed due to the looney way its endpoints are set up */ /* this is needed due to the looney way its endpoints are set up */
...@@ -826,6 +829,8 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -826,6 +829,8 @@ static int usb_serial_probe(struct usb_interface *interface,
((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) && ((le16_to_cpu(dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
(le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) { (le16_to_cpu(dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_EF81))) {
if (interface != dev->actconfig->interface[0]) { if (interface != dev->actconfig->interface[0]) {
struct usb_host_interface *iface_desc;
/* check out the endpoints of the other interface*/ /* check out the endpoints of the other interface*/
iface_desc = dev->actconfig->interface[0]->cur_altsetting; iface_desc = dev->actconfig->interface[0]->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
...@@ -833,10 +838,8 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -833,10 +838,8 @@ static int usb_serial_probe(struct usb_interface *interface,
if (usb_endpoint_is_int_in(endpoint)) { if (usb_endpoint_is_int_in(endpoint)) {
/* we found a interrupt in endpoint */ /* we found a interrupt in endpoint */
dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n"); dev_dbg(ddev, "found interrupt in for Prolific device on separate interface\n");
if (num_interrupt_in < MAX_NUM_PORTS) { if (epds->num_interrupt_in < ARRAY_SIZE(epds->interrupt_in))
interrupt_in_endpoint[num_interrupt_in] = endpoint; epds->interrupt_in[epds->num_interrupt_in++] = endpoint;
++num_interrupt_in;
}
} }
} }
} }
...@@ -845,9 +848,10 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -845,9 +848,10 @@ static int usb_serial_probe(struct usb_interface *interface,
* If not, give up now and hope this hack will work * If not, give up now and hope this hack will work
* properly during a later invocation of usb_serial_probe * properly during a later invocation of usb_serial_probe
*/ */
if (num_bulk_in == 0 || num_bulk_out == 0) { if (epds->num_bulk_in == 0 || epds->num_bulk_out == 0) {
dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n"); dev_info(ddev, "PL-2303 hack: descriptors matched but endpoints did not\n");
retval = -ENODEV; retval = -ENODEV;
kfree(epds);
goto err_put_serial; goto err_put_serial;
} }
} }
...@@ -856,10 +860,11 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -856,10 +860,11 @@ static int usb_serial_probe(struct usb_interface *interface,
#ifdef CONFIG_USB_SERIAL_GENERIC #ifdef CONFIG_USB_SERIAL_GENERIC
if (type == &usb_serial_generic_device) { if (type == &usb_serial_generic_device) {
num_ports = num_bulk_out; num_ports = epds->num_bulk_out;
if (num_ports == 0) { if (num_ports == 0) {
dev_err(ddev, "Generic device with no bulk out, not allowed.\n"); dev_err(ddev, "Generic device with no bulk out, not allowed.\n");
retval = -EIO; retval = -EIO;
kfree(epds);
goto err_put_serial; goto err_put_serial;
} }
dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); dev_info(ddev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n");
...@@ -880,10 +885,10 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -880,10 +885,10 @@ static int usb_serial_probe(struct usb_interface *interface,
} }
serial->num_ports = (unsigned char)num_ports; serial->num_ports = (unsigned char)num_ports;
serial->num_bulk_in = num_bulk_in; serial->num_bulk_in = epds->num_bulk_in;
serial->num_bulk_out = num_bulk_out; serial->num_bulk_out = epds->num_bulk_out;
serial->num_interrupt_in = num_interrupt_in; serial->num_interrupt_in = epds->num_interrupt_in;
serial->num_interrupt_out = num_interrupt_out; serial->num_interrupt_out = epds->num_interrupt_out;
/* found all that we need */ /* found all that we need */
dev_info(ddev, "%s converter detected\n", type->description); dev_info(ddev, "%s converter detected\n", type->description);
...@@ -891,9 +896,9 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -891,9 +896,9 @@ static int usb_serial_probe(struct usb_interface *interface,
/* 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 because some devices have more /* we don't use num_ports here because some devices have more
endpoint pairs than ports */ endpoint pairs than ports */
max_endpoints = max(num_bulk_in, num_bulk_out); max_endpoints = max(epds->num_bulk_in, epds->num_bulk_out);
max_endpoints = max(max_endpoints, num_interrupt_in); max_endpoints = max(max_endpoints, epds->num_interrupt_in);
max_endpoints = max(max_endpoints, num_interrupt_out); max_endpoints = max(max_endpoints, epds->num_interrupt_out);
max_endpoints = max(max_endpoints, serial->num_ports); max_endpoints = max(max_endpoints, serial->num_ports);
serial->num_port_pointers = max_endpoints; serial->num_port_pointers = max_endpoints;
...@@ -919,8 +924,8 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -919,8 +924,8 @@ static int usb_serial_probe(struct usb_interface *interface,
} }
/* set up the endpoint information */ /* set up the endpoint information */
for (i = 0; i < num_bulk_in; ++i) { for (i = 0; i < epds->num_bulk_in; ++i) {
endpoint = bulk_in_endpoint[i]; endpoint = epds->bulk_in[i];
port = serial->port[i]; port = serial->port[i];
buffer_size = max_t(int, serial->type->bulk_in_size, buffer_size = max_t(int, serial->type->bulk_in_size,
usb_endpoint_maxp(endpoint)); usb_endpoint_maxp(endpoint));
...@@ -948,8 +953,8 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -948,8 +953,8 @@ static int usb_serial_probe(struct usb_interface *interface,
port->bulk_in_buffer = port->bulk_in_buffers[0]; port->bulk_in_buffer = port->bulk_in_buffers[0];
} }
for (i = 0; i < num_bulk_out; ++i) { for (i = 0; i < epds->num_bulk_out; ++i) {
endpoint = bulk_out_endpoint[i]; endpoint = epds->bulk_out[i];
port = serial->port[i]; port = serial->port[i];
if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL)) if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
goto probe_error; goto probe_error;
...@@ -981,8 +986,8 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -981,8 +986,8 @@ static int usb_serial_probe(struct usb_interface *interface,
} }
if (serial->type->read_int_callback) { if (serial->type->read_int_callback) {
for (i = 0; i < num_interrupt_in; ++i) { for (i = 0; i < epds->num_interrupt_in; ++i) {
endpoint = interrupt_in_endpoint[i]; endpoint = epds->interrupt_in[i];
port = serial->port[i]; port = serial->port[i];
port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->interrupt_in_urb) if (!port->interrupt_in_urb)
...@@ -1001,13 +1006,13 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -1001,13 +1006,13 @@ static 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) { } else if (epds->num_interrupt_in) {
dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n"); dev_dbg(ddev, "The device claims to support interrupt in transfers, but read_int_callback is not defined\n");
} }
if (serial->type->write_int_callback) { if (serial->type->write_int_callback) {
for (i = 0; i < num_interrupt_out; ++i) { for (i = 0; i < epds->num_interrupt_out; ++i) {
endpoint = interrupt_out_endpoint[i]; endpoint = epds->interrupt_out[i];
port = serial->port[i]; port = serial->port[i];
port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!port->interrupt_out_urb) if (!port->interrupt_out_urb)
...@@ -1027,7 +1032,7 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -1027,7 +1032,7 @@ static int usb_serial_probe(struct usb_interface *interface,
serial->type->write_int_callback, port, serial->type->write_int_callback, port,
endpoint->bInterval); endpoint->bInterval);
} }
} else if (num_interrupt_out) { } else if (epds->num_interrupt_out) {
dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n"); dev_dbg(ddev, "The device claims to support interrupt out transfers, but write_int_callback is not defined\n");
} }
...@@ -1077,6 +1082,7 @@ static int usb_serial_probe(struct usb_interface *interface, ...@@ -1077,6 +1082,7 @@ static int usb_serial_probe(struct usb_interface *interface,
if (num_ports > 0) if (num_ports > 0)
usb_serial_console_init(serial->port[0]->minor); usb_serial_console_init(serial->port[0]->minor);
exit: exit:
kfree(epds);
module_put(type->driver.owner); module_put(type->driver.owner);
return 0; return 0;
......
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