diff options
| author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-27 17:40:30 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-27 17:40:30 -0400 |
| commit | 1f9bd4c96a8e918a86e083706e0d3eb7f030b9a3 (patch) | |
| tree | a840b35ca8c193cb0ec5579de3fac4e4e7f47f11 /drivers/usb/core/message.c | |
| parent | 00463c1633b6d6a2178d2dc794c0a70ac2f9ce6b (diff) | |
| parent | 7f38aa0f04259d37f26e1e906607f1ebb39c0c5c (diff) | |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (129 commits)
[PATCH] USB Storage: fix Rio Karma eject support build error
USB: Airprime driver improvements to allow full speed EvDO transfers
USB: remove OTG build warning
USB: EHCI update VIA workaround
USB: force root hub resume after power loss
USB: ohci_usb can oops on shutdown
USB: Dealias -110 code (more complete)
USB: Remove unneeded void * casts in core files
USB: u132-hcd: host controller driver for ELAN U132 adapter
USB: ftdi-elan: client driver for ELAN Uxxx adapters
usb serial: support Alcor Micro Corp. USB 2.0 TO RS-232 through pl2303 driver
USB: Moschip 7840 USB-Serial Driver
USB: add PlayStation 2 Trance Vibrator driver
USB: Add ADU support for Ontrak ADU devices
aircable: fix printk format warnings
Add AIRcable USB Bluetooth Dongle Driver
cypress_m8: implement graceful failure handling
cypress_m8: improve control endpoint error handling
cypress_m8: use usb_fill_int_urb where appropriate
cypress_m8: use appropriate URB polling interval
...
Diffstat (limited to 'drivers/usb/core/message.c')
| -rw-r--r-- | drivers/usb/core/message.c | 148 |
1 files changed, 98 insertions, 50 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 4cc8d3e67db7..85b1cd18336f 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
| @@ -23,59 +23,44 @@ static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs) | |||
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | static void timeout_kill(unsigned long data) | 26 | /* |
| 27 | { | 27 | * Starts urb and waits for completion or timeout. Note that this call |
| 28 | struct urb *urb = (struct urb *) data; | 28 | * is NOT interruptible. Many device driver i/o requests should be |
| 29 | 29 | * interruptible and therefore these drivers should implement their | |
| 30 | usb_unlink_urb(urb); | 30 | * own interruptible routines. |
| 31 | } | 31 | */ |
| 32 | 32 | static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length) | |
| 33 | // Starts urb and waits for completion or timeout | ||
| 34 | // note that this call is NOT interruptible, while | ||
| 35 | // many device driver i/o requests should be interruptible | ||
| 36 | static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) | ||
| 37 | { | 33 | { |
| 38 | struct completion done; | 34 | struct completion done; |
| 39 | struct timer_list timer; | 35 | unsigned long expire; |
| 40 | int status; | 36 | int status; |
| 41 | 37 | ||
| 42 | init_completion(&done); | 38 | init_completion(&done); |
| 43 | urb->context = &done; | 39 | urb->context = &done; |
| 44 | urb->actual_length = 0; | 40 | urb->actual_length = 0; |
| 45 | status = usb_submit_urb(urb, GFP_NOIO); | 41 | status = usb_submit_urb(urb, GFP_NOIO); |
| 46 | 42 | if (unlikely(status)) | |
| 47 | if (status == 0) { | 43 | goto out; |
| 48 | if (timeout > 0) { | 44 | |
| 49 | init_timer(&timer); | 45 | expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; |
| 50 | timer.expires = jiffies + msecs_to_jiffies(timeout); | 46 | if (!wait_for_completion_timeout(&done, expire)) { |
| 51 | timer.data = (unsigned long)urb; | 47 | |
| 52 | timer.function = timeout_kill; | 48 | dev_dbg(&urb->dev->dev, |
| 53 | /* grr. timeout _should_ include submit delays. */ | 49 | "%s timed out on ep%d%s len=%d/%d\n", |
| 54 | add_timer(&timer); | 50 | current->comm, |
| 55 | } | 51 | usb_pipeendpoint(urb->pipe), |
| 56 | wait_for_completion(&done); | 52 | usb_pipein(urb->pipe) ? "in" : "out", |
| 53 | urb->actual_length, | ||
| 54 | urb->transfer_buffer_length); | ||
| 55 | |||
| 56 | usb_kill_urb(urb); | ||
| 57 | status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status; | ||
| 58 | } else | ||
| 57 | status = urb->status; | 59 | status = urb->status; |
| 58 | /* note: HCDs return ETIMEDOUT for other reasons too */ | 60 | out: |
| 59 | if (status == -ECONNRESET) { | ||
| 60 | dev_dbg(&urb->dev->dev, | ||
| 61 | "%s timed out on ep%d%s len=%d/%d\n", | ||
| 62 | current->comm, | ||
| 63 | usb_pipeendpoint(urb->pipe), | ||
| 64 | usb_pipein(urb->pipe) ? "in" : "out", | ||
| 65 | urb->actual_length, | ||
| 66 | urb->transfer_buffer_length | ||
| 67 | ); | ||
| 68 | if (urb->actual_length > 0) | ||
| 69 | status = 0; | ||
| 70 | else | ||
| 71 | status = -ETIMEDOUT; | ||
| 72 | } | ||
| 73 | if (timeout > 0) | ||
| 74 | del_timer_sync(&timer); | ||
| 75 | } | ||
| 76 | |||
| 77 | if (actual_length) | 61 | if (actual_length) |
| 78 | *actual_length = urb->actual_length; | 62 | *actual_length = urb->actual_length; |
| 63 | |||
| 79 | usb_free_urb(urb); | 64 | usb_free_urb(urb); |
| 80 | return status; | 65 | return status; |
| 81 | } | 66 | } |
| @@ -263,7 +248,7 @@ static void sg_clean (struct usb_sg_request *io) | |||
| 263 | 248 | ||
| 264 | static void sg_complete (struct urb *urb, struct pt_regs *regs) | 249 | static void sg_complete (struct urb *urb, struct pt_regs *regs) |
| 265 | { | 250 | { |
| 266 | struct usb_sg_request *io = (struct usb_sg_request *) urb->context; | 251 | struct usb_sg_request *io = urb->context; |
| 267 | 252 | ||
| 268 | spin_lock (&io->lock); | 253 | spin_lock (&io->lock); |
| 269 | 254 | ||
| @@ -999,8 +984,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr) | |||
| 999 | ep = dev->ep_in[epnum]; | 984 | ep = dev->ep_in[epnum]; |
| 1000 | dev->ep_in[epnum] = NULL; | 985 | dev->ep_in[epnum] = NULL; |
| 1001 | } | 986 | } |
| 1002 | if (ep && dev->bus && dev->bus->op && dev->bus->op->disable) | 987 | if (ep && dev->bus) |
| 1003 | dev->bus->op->disable(dev, ep); | 988 | usb_hcd_endpoint_disable(dev, ep); |
| 1004 | } | 989 | } |
| 1005 | 990 | ||
| 1006 | /** | 991 | /** |
| @@ -1381,9 +1366,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) | |||
| 1381 | if (cp && configuration == 0) | 1366 | if (cp && configuration == 0) |
| 1382 | dev_warn(&dev->dev, "config 0 descriptor??\n"); | 1367 | dev_warn(&dev->dev, "config 0 descriptor??\n"); |
| 1383 | 1368 | ||
| 1384 | if (dev->state == USB_STATE_SUSPENDED) | ||
| 1385 | return -EHOSTUNREACH; | ||
| 1386 | |||
| 1387 | /* Allocate memory for new interfaces before doing anything else, | 1369 | /* Allocate memory for new interfaces before doing anything else, |
| 1388 | * so that if we run out then nothing will have changed. */ | 1370 | * so that if we run out then nothing will have changed. */ |
| 1389 | n = nintf = 0; | 1371 | n = nintf = 0; |
| @@ -1418,6 +1400,11 @@ free_interfaces: | |||
| 1418 | configuration, -i); | 1400 | configuration, -i); |
| 1419 | } | 1401 | } |
| 1420 | 1402 | ||
| 1403 | /* Wake up the device so we can send it the Set-Config request */ | ||
| 1404 | ret = usb_autoresume_device(dev, 1); | ||
| 1405 | if (ret) | ||
| 1406 | goto free_interfaces; | ||
| 1407 | |||
| 1421 | /* if it's already configured, clear out old state first. | 1408 | /* if it's already configured, clear out old state first. |
| 1422 | * getting rid of old interfaces means unbinding their drivers. | 1409 | * getting rid of old interfaces means unbinding their drivers. |
| 1423 | */ | 1410 | */ |
| @@ -1437,6 +1424,7 @@ free_interfaces: | |||
| 1437 | dev->actconfig = cp; | 1424 | dev->actconfig = cp; |
| 1438 | if (!cp) { | 1425 | if (!cp) { |
| 1439 | usb_set_device_state(dev, USB_STATE_ADDRESS); | 1426 | usb_set_device_state(dev, USB_STATE_ADDRESS); |
| 1427 | usb_autosuspend_device(dev, 1); | ||
| 1440 | goto free_interfaces; | 1428 | goto free_interfaces; |
| 1441 | } | 1429 | } |
| 1442 | usb_set_device_state(dev, USB_STATE_CONFIGURED); | 1430 | usb_set_device_state(dev, USB_STATE_CONFIGURED); |
| @@ -1505,8 +1493,68 @@ free_interfaces: | |||
| 1505 | usb_create_sysfs_intf_files (intf); | 1493 | usb_create_sysfs_intf_files (intf); |
| 1506 | } | 1494 | } |
| 1507 | 1495 | ||
| 1496 | usb_autosuspend_device(dev, 1); | ||
| 1497 | return 0; | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | struct set_config_request { | ||
| 1501 | struct usb_device *udev; | ||
| 1502 | int config; | ||
| 1503 | struct work_struct work; | ||
| 1504 | }; | ||
| 1505 | |||
| 1506 | /* Worker routine for usb_driver_set_configuration() */ | ||
| 1507 | static void driver_set_config_work(void *_req) | ||
| 1508 | { | ||
| 1509 | struct set_config_request *req = _req; | ||
| 1510 | |||
| 1511 | usb_lock_device(req->udev); | ||
| 1512 | usb_set_configuration(req->udev, req->config); | ||
| 1513 | usb_unlock_device(req->udev); | ||
| 1514 | usb_put_dev(req->udev); | ||
| 1515 | kfree(req); | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | /** | ||
| 1519 | * usb_driver_set_configuration - Provide a way for drivers to change device configurations | ||
| 1520 | * @udev: the device whose configuration is being updated | ||
| 1521 | * @config: the configuration being chosen. | ||
| 1522 | * Context: In process context, must be able to sleep | ||
| 1523 | * | ||
| 1524 | * Device interface drivers are not allowed to change device configurations. | ||
| 1525 | * This is because changing configurations will destroy the interface the | ||
| 1526 | * driver is bound to and create new ones; it would be like a floppy-disk | ||
| 1527 | * driver telling the computer to replace the floppy-disk drive with a | ||
| 1528 | * tape drive! | ||
| 1529 | * | ||
| 1530 | * Still, in certain specialized circumstances the need may arise. This | ||
| 1531 | * routine gets around the normal restrictions by using a work thread to | ||
| 1532 | * submit the change-config request. | ||
| 1533 | * | ||
| 1534 | * Returns 0 if the request was succesfully queued, error code otherwise. | ||
| 1535 | * The caller has no way to know whether the queued request will eventually | ||
| 1536 | * succeed. | ||
| 1537 | */ | ||
| 1538 | int usb_driver_set_configuration(struct usb_device *udev, int config) | ||
| 1539 | { | ||
| 1540 | struct set_config_request *req; | ||
| 1541 | |||
| 1542 | req = kmalloc(sizeof(*req), GFP_KERNEL); | ||
| 1543 | if (!req) | ||
| 1544 | return -ENOMEM; | ||
| 1545 | req->udev = udev; | ||
| 1546 | req->config = config; | ||
| 1547 | INIT_WORK(&req->work, driver_set_config_work, req); | ||
| 1548 | |||
| 1549 | usb_get_dev(udev); | ||
| 1550 | if (!schedule_work(&req->work)) { | ||
| 1551 | usb_put_dev(udev); | ||
| 1552 | kfree(req); | ||
| 1553 | return -EINVAL; | ||
| 1554 | } | ||
| 1508 | return 0; | 1555 | return 0; |
| 1509 | } | 1556 | } |
| 1557 | EXPORT_SYMBOL_GPL(usb_driver_set_configuration); | ||
| 1510 | 1558 | ||
| 1511 | // synchronous request completion model | 1559 | // synchronous request completion model |
| 1512 | EXPORT_SYMBOL(usb_control_msg); | 1560 | EXPORT_SYMBOL(usb_control_msg); |
