aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorRainer Weikusat <rainer.weikusat@sncag.com>2007-01-03 09:36:25 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2007-02-07 18:44:38 -0500
commitfdcba53e2d58272bcdb5f1fad694602ccf02ad46 (patch)
tree425383841722e8bcf20a7926c4b54180fc8667b7 /drivers/usb/serial
parent3ede760f0e46317c6716ead8facff88f6a924a49 (diff)
fix for bugzilla #7544 (keyspan USB-to-serial converter)
At least the Keyspan USA-19HS USB-to-serial converter supports two different configurations, one where the input endpoints have interrupt transfer type and one where they are bulk endpoints. The default UHCI configuration uses the interrupt input endpoints. The keyspan driver, OTOH, assumes that the device has only bulk endpoints (all URBs are initialized by calling usb_fill_bulk_urb in keyspan.c/ keyspan_setup_urb). This causes the interval field of the input URBs to have a value of zero instead of one, which 'accidentally' worked with Linux at least up to 2.6.17.11 but stopped to with 2.6.18, which changed the UHCI support code handling URBs for interrupt endpoints. The patch below modifies to driver to initialize its input URBs either as interrupt or as bulk URBs, depending on the transfertype contained in the associated endpoint descriptor (only tested with the default configuration) enabling the driver to again receive data from the serial converter. Greg K-H reworked the patch. Signed-off-by: Rainer Weikusat <rweikusat@sncag.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/keyspan.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 9d2fdfd6865f..e6966f12ed5a 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial)
1275} 1275}
1276 1276
1277/* Helper functions used by keyspan_setup_urbs */ 1277/* Helper functions used by keyspan_setup_urbs */
1278static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
1279 int endpoint)
1280{
1281 struct usb_host_interface *iface_desc;
1282 struct usb_endpoint_descriptor *ep;
1283 int i;
1284
1285 iface_desc = serial->interface->cur_altsetting;
1286 for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
1287 ep = &iface_desc->endpoint[i].desc;
1288 if (ep->bEndpointAddress == endpoint)
1289 return ep;
1290 }
1291 dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
1292 "endpoint %x\n", endpoint);
1293 return NULL;
1294}
1295
1278static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint, 1296static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
1279 int dir, void *ctx, char *buf, int len, 1297 int dir, void *ctx, char *buf, int len,
1280 void (*callback)(struct urb *)) 1298 void (*callback)(struct urb *))
1281{ 1299{
1282 struct urb *urb; 1300 struct urb *urb;
1301 struct usb_endpoint_descriptor const *ep_desc;
1302 char const *ep_type_name;
1283 1303
1284 if (endpoint == -1) 1304 if (endpoint == -1)
1285 return NULL; /* endpoint not needed */ 1305 return NULL; /* endpoint not needed */
@@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
1291 return NULL; 1311 return NULL;
1292 } 1312 }
1293 1313
1294 /* Fill URB using supplied data. */ 1314 ep_desc = find_ep(serial, endpoint);
1295 usb_fill_bulk_urb(urb, serial->dev, 1315 if (!ep_desc) {
1296 usb_sndbulkpipe(serial->dev, endpoint) | dir, 1316 /* leak the urb, something's wrong and the callers don't care */
1297 buf, len, callback, ctx); 1317 return urb;
1318 }
1319 if (usb_endpoint_xfer_int(ep_desc)) {
1320 ep_type_name = "INT";
1321 usb_fill_int_urb(urb, serial->dev,
1322 usb_sndintpipe(serial->dev, endpoint) | dir,
1323 buf, len, callback, ctx,
1324 ep_desc->bInterval);
1325 } else if (usb_endpoint_xfer_bulk(ep_desc)) {
1326 ep_type_name = "BULK";
1327 usb_fill_bulk_urb(urb, serial->dev,
1328 usb_sndbulkpipe(serial->dev, endpoint) | dir,
1329 buf, len, callback, ctx);
1330 } else {
1331 dev_warn(&serial->interface->dev,
1332 "unsupported endpoint type %x\n",
1333 ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
1334 usb_free_urb(urb);
1335 return NULL;
1336 }
1298 1337
1338 dbg("%s - using urb %p for %s endpoint %x",
1339 __func__, urb, ep_type_name, endpoint);
1299 return urb; 1340 return urb;
1300} 1341}
1301 1342