diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2009-04-15 21:35:14 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-04-15 21:35:14 -0700 |
| commit | 4cc7aece738b4f3c8ab49a170297f871e1c5a804 (patch) | |
| tree | b29d5cb0e2021992e2a07b22858cf1f4d618130a /usb.current | |
| parent | 98dc1382efb52ca1423870b2b0673eac399857c1 (diff) | |
| download | patches-4cc7aece738b4f3c8ab49a170297f871e1c5a804.tar.gz | |
usb patches
Diffstat (limited to 'usb.current')
7 files changed, 878 insertions, 0 deletions
diff --git a/usb.current/usb-add-reset-endpoint-operations.patch b/usb.current/usb-add-reset-endpoint-operations.patch new file mode 100644 index 00000000000000..6f1fb8654577dc --- /dev/null +++ b/usb.current/usb-add-reset-endpoint-operations.patch @@ -0,0 +1,398 @@ +From dvrabel@hera.kernel.org Wed Apr 15 20:47:43 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Wed, 8 Apr 2009 17:36:28 +0000 +Subject: USB: add reset endpoint operations +To: Greg KH <gregkh@suse.de> +Cc: David Vrabel <david.vrabel@csr.com> +Message-ID: <1239212193-27618-2-git-send-email-david.vrabel@csr.com> + + +Wireless USB endpoint state has a sequence number and a current +window and not just a single toggle bit. So allow HCDs to provide a +endpoint_reset method and call this or clear the software toggles as +required (after a clear halt, set configuration etc.). + +usb_settoggle() and friends are then HCD internal and are moved into +core/hcd.h and all device drivers call usb_reset_endpoint() instead. + +If the device endpoint state has been reset (with a clear halt) but +the host endpoint state has not then subsequent data transfers will +not complete. The device will only work again after it is reset or +disconnected. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/block/ub.c | 20 ++++------ + drivers/isdn/hisax/st5481_usb.c | 9 ---- + drivers/media/video/pvrusb2/pvrusb2-hdw.c | 1 + drivers/usb/core/devio.c | 2 - + drivers/usb/core/hcd.c | 26 +++++++++++++ + drivers/usb/core/hcd.h | 14 +++++++ + drivers/usb/core/message.c | 58 +++++++++++++++++++----------- + drivers/usb/core/usb.c | 2 - + drivers/usb/storage/transport.c | 4 -- + include/linux/usb.h | 9 ---- + 10 files changed, 91 insertions(+), 54 deletions(-) + +--- a/drivers/block/ub.c ++++ b/drivers/block/ub.c +@@ -1025,6 +1025,7 @@ static void ub_scsi_urb_compl(struct ub_ + { + struct urb *urb = &sc->work_urb; + struct bulk_cs_wrap *bcs; ++ int endp; + int len; + int rc; + +@@ -1033,6 +1034,10 @@ static void ub_scsi_urb_compl(struct ub_ + return; + } + ++ endp = usb_pipeendpoint(sc->last_pipe); ++ if (usb_pipein(sc->last_pipe)) ++ endp |= USB_DIR_IN; ++ + if (cmd->state == UB_CMDST_CLEAR) { + if (urb->status == -EPIPE) { + /* +@@ -1048,9 +1053,7 @@ static void ub_scsi_urb_compl(struct ub_ + * We ignore the result for the halt clear. + */ + +- /* reset the endpoint toggle */ +- usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), +- usb_pipeout(sc->last_pipe), 0); ++ usb_reset_endpoint(sc->dev, endp); + + ub_state_sense(sc, cmd); + +@@ -1065,9 +1068,7 @@ static void ub_scsi_urb_compl(struct ub_ + * We ignore the result for the halt clear. + */ + +- /* reset the endpoint toggle */ +- usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), +- usb_pipeout(sc->last_pipe), 0); ++ usb_reset_endpoint(sc->dev, endp); + + ub_state_stat(sc, cmd); + +@@ -1082,9 +1083,7 @@ static void ub_scsi_urb_compl(struct ub_ + * We ignore the result for the halt clear. + */ + +- /* reset the endpoint toggle */ +- usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), +- usb_pipeout(sc->last_pipe), 0); ++ usb_reset_endpoint(sc->dev, endp); + + ub_state_stat_counted(sc, cmd); + +@@ -2119,8 +2118,7 @@ static int ub_probe_clear_stall(struct u + del_timer_sync(&timer); + usb_kill_urb(&sc->work_urb); + +- /* reset the endpoint toggle */ +- usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0); ++ usb_reset_endpoint(sc->dev, endp); + + return 0; + } +--- a/drivers/isdn/hisax/st5481_usb.c ++++ b/drivers/isdn/hisax/st5481_usb.c +@@ -149,14 +149,7 @@ static void usb_ctrl_complete(struct urb + if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { + /* Special case handling for pipe reset */ + le16_to_cpus(&ctrl_msg->dr.wIndex); +- +- /* toggle is reset on clear */ +- usb_settoggle(adapter->usb_dev, +- ctrl_msg->dr.wIndex & ~USB_DIR_IN, +- (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0, +- 0); +- +- ++ usb_reset_endpoint(adapter->usb_dev, ctrl_msg->dr.wIndex); + } + + if (ctrl_msg->complete) +--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c ++++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c +@@ -1461,7 +1461,6 @@ static int pvr2_upload_firmware1(struct + return ret; + } + +- usb_settoggle(hdw->usb_dev, 0 & 0xf, !(0 & USB_DIR_IN), 0); + usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f)); + + pipe = usb_sndctrlpipe(hdw->usb_dev, 0); +--- a/drivers/usb/core/devio.c ++++ b/drivers/usb/core/devio.c +@@ -841,7 +841,7 @@ static int proc_resetep(struct dev_state + ret = checkintf(ps, ret); + if (ret) + return ret; +- usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0); ++ usb_reset_endpoint(ps->dev, ep); + return 0; + } + +--- a/drivers/usb/core/hcd.c ++++ b/drivers/usb/core/hcd.c +@@ -1539,6 +1539,32 @@ void usb_hcd_disable_endpoint(struct usb + hcd->driver->endpoint_disable(hcd, ep); + } + ++/** ++ * usb_hcd_reset_endpoint - reset host endpoint state ++ * @udev: USB device. ++ * @ep: the endpoint to reset. ++ * ++ * Resets any host endpoint state such as the toggle bit, sequence ++ * number and current window. ++ */ ++void usb_hcd_reset_endpoint(struct usb_device *udev, ++ struct usb_host_endpoint *ep) ++{ ++ struct usb_hcd *hcd = bus_to_hcd(udev->bus); ++ ++ if (hcd->driver->endpoint_reset) ++ hcd->driver->endpoint_reset(hcd, ep); ++ else { ++ int epnum = usb_endpoint_num(&ep->desc); ++ int is_out = usb_endpoint_dir_out(&ep->desc); ++ int is_control = usb_endpoint_xfer_control(&ep->desc); ++ ++ usb_settoggle(udev, epnum, is_out, 0); ++ if (is_control) ++ usb_settoggle(udev, epnum, !is_out, 0); ++ } ++} ++ + /* Protect against drivers that try to unlink URBs after the device + * is gone, by waiting until all unlinks for @udev are finished. + * Since we don't currently track URBs by device, simply wait until +--- a/drivers/usb/core/hcd.h ++++ b/drivers/usb/core/hcd.h +@@ -206,6 +206,11 @@ struct hc_driver { + void (*endpoint_disable)(struct usb_hcd *hcd, + struct usb_host_endpoint *ep); + ++ /* (optional) reset any endpoint state such as sequence number ++ and current window */ ++ void (*endpoint_reset)(struct usb_hcd *hcd, ++ struct usb_host_endpoint *ep); ++ + /* root hub support */ + int (*hub_status_data) (struct usb_hcd *hcd, char *buf); + int (*hub_control) (struct usb_hcd *hcd, +@@ -234,6 +239,8 @@ extern void usb_hcd_flush_endpoint(struc + struct usb_host_endpoint *ep); + extern void usb_hcd_disable_endpoint(struct usb_device *udev, + struct usb_host_endpoint *ep); ++extern void usb_hcd_reset_endpoint(struct usb_device *udev, ++ struct usb_host_endpoint *ep); + extern void usb_hcd_synchronize_unlinks(struct usb_device *udev); + extern int usb_hcd_get_frame_number(struct usb_device *udev); + +@@ -279,6 +286,13 @@ extern irqreturn_t usb_hcd_irq(int irq, + extern void usb_hc_died(struct usb_hcd *hcd); + extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); + ++/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ ++#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) ++#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) ++#define usb_settoggle(dev, ep, out, bit) \ ++ ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \ ++ ((bit) << (ep))) ++ + /* -------------------------------------------------------------------------- */ + + /* Enumeration is only for the hub driver, or HCD virtual root hubs */ +--- a/drivers/usb/core/message.c ++++ b/drivers/usb/core/message.c +@@ -1002,8 +1002,7 @@ int usb_clear_halt(struct usb_device *de + * the copy in usb-storage, for as long as we need two copies. + */ + +- /* toggle was reset by the clear */ +- usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); ++ usb_reset_endpoint(dev, endp); + + return 0; + } +@@ -1076,6 +1075,30 @@ void usb_disable_endpoint(struct usb_dev + } + + /** ++ * usb_reset_endpoint - Reset an endpoint's state. ++ * @dev: the device whose endpoint is to be reset ++ * @epaddr: the endpoint's address. Endpoint number for output, ++ * endpoint number + USB_DIR_IN for input ++ * ++ * Resets any host-side endpoint state such as the toggle bit, ++ * sequence number or current window. ++ */ ++void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr) ++{ ++ unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK; ++ struct usb_host_endpoint *ep; ++ ++ if (usb_endpoint_out(epaddr)) ++ ep = dev->ep_out[epnum]; ++ else ++ ep = dev->ep_in[epnum]; ++ if (ep) ++ usb_hcd_reset_endpoint(dev, ep); ++} ++EXPORT_SYMBOL_GPL(usb_reset_endpoint); ++ ++ ++/** + * usb_disable_interface -- Disable all endpoints for an interface + * @dev: the device whose interface is being disabled + * @intf: pointer to the interface descriptor +@@ -1117,7 +1140,6 @@ void usb_disable_device(struct usb_devic + usb_disable_endpoint(dev, i, true); + usb_disable_endpoint(dev, i + USB_DIR_IN, true); + } +- dev->toggle[0] = dev->toggle[1] = 0; + + /* getting rid of interfaces will disconnect + * any drivers bound to them (a key side effect) +@@ -1154,28 +1176,24 @@ void usb_disable_device(struct usb_devic + * usb_enable_endpoint - Enable an endpoint for USB communications + * @dev: the device whose interface is being enabled + * @ep: the endpoint +- * @reset_toggle: flag to set the endpoint's toggle back to 0 ++ * @reset_ep: flag to reset the endpoint state + * +- * Resets the endpoint toggle if asked, and sets dev->ep_{in,out} pointers. ++ * Resets the endpoint state if asked, and sets dev->ep_{in,out} pointers. + * For control endpoints, both the input and output sides are handled. + */ + void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep, +- bool reset_toggle) ++ bool reset_ep) + { + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + int is_control = usb_endpoint_xfer_control(&ep->desc); + +- if (is_out || is_control) { +- if (reset_toggle) +- usb_settoggle(dev, epnum, 1, 0); ++ if (reset_ep) ++ usb_hcd_reset_endpoint(dev, ep); ++ if (is_out || is_control) + dev->ep_out[epnum] = ep; +- } +- if (!is_out || is_control) { +- if (reset_toggle) +- usb_settoggle(dev, epnum, 0, 0); ++ if (!is_out || is_control) + dev->ep_in[epnum] = ep; +- } + ep->enabled = 1; + } + +@@ -1183,18 +1201,18 @@ void usb_enable_endpoint(struct usb_devi + * usb_enable_interface - Enable all the endpoints for an interface + * @dev: the device whose interface is being enabled + * @intf: pointer to the interface descriptor +- * @reset_toggles: flag to set the endpoints' toggles back to 0 ++ * @reset_eps: flag to reset the endpoints' state + * + * Enables all the endpoints for the interface's current altsetting. + */ + void usb_enable_interface(struct usb_device *dev, +- struct usb_interface *intf, bool reset_toggles) ++ struct usb_interface *intf, bool reset_eps) + { + struct usb_host_interface *alt = intf->cur_altsetting; + int i; + + for (i = 0; i < alt->desc.bNumEndpoints; ++i) +- usb_enable_endpoint(dev, &alt->endpoint[i], reset_toggles); ++ usb_enable_endpoint(dev, &alt->endpoint[i], reset_eps); + } + + /** +@@ -1335,7 +1353,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface); + * This issues a standard SET_CONFIGURATION request to the device using + * the current configuration. The effect is to reset most USB-related + * state in the device, including interface altsettings (reset to zero), +- * endpoint halts (cleared), and data toggle (only for bulk and interrupt ++ * endpoint halts (cleared), and endpoint state (only for bulk and interrupt + * endpoints). Other usbcore state is unchanged, including bindings of + * usb device drivers to interfaces. + * +@@ -1343,7 +1361,7 @@ EXPORT_SYMBOL_GPL(usb_set_interface); + * (multi-interface) devices. Instead, the driver for each interface may + * use usb_set_interface() on the interfaces it claims. Be careful though; + * some devices don't support the SET_INTERFACE request, and others won't +- * reset all the interface state (notably data toggles). Resetting the whole ++ * reset all the interface state (notably endpoint state). Resetting the whole + * configuration would affect other drivers' interfaces. + * + * The caller must own the device lock. +@@ -1376,8 +1394,6 @@ int usb_reset_configuration(struct usb_d + if (retval < 0) + return retval; + +- dev->toggle[0] = dev->toggle[1] = 0; +- + /* re-init hc/hcd interface/endpoint state */ + for (i = 0; i < config->desc.bNumInterfaces; i++) { + struct usb_interface *intf = config->interface[i]; +--- a/drivers/usb/core/usb.c ++++ b/drivers/usb/core/usb.c +@@ -362,7 +362,7 @@ struct usb_device *usb_alloc_dev(struct + dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; + dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; + /* ep0 maxpacket comes later, from device descriptor */ +- usb_enable_endpoint(dev, &dev->ep0, true); ++ usb_enable_endpoint(dev, &dev->ep0, false); + dev->can_submit = 1; + + /* Save readable and stable topology id, distinguishing devices +--- a/drivers/usb/storage/transport.c ++++ b/drivers/usb/storage/transport.c +@@ -247,10 +247,8 @@ int usb_stor_clear_halt(struct us_data * + USB_ENDPOINT_HALT, endp, + NULL, 0, 3*HZ); + +- /* reset the endpoint toggle */ + if (result >= 0) +- usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), +- usb_pipeout(pipe), 0); ++ usb_reset_endpoint(us->pusb_dev, endp); + + US_DEBUGP("%s: result = %d\n", __func__, result); + return result; +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -1387,6 +1387,7 @@ extern int usb_string(struct usb_device + extern int usb_clear_halt(struct usb_device *dev, int pipe); + extern int usb_reset_configuration(struct usb_device *dev); + extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); ++extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr); + + /* this request isn't really synchronous, but it belongs with the others */ + extern int usb_driver_set_configuration(struct usb_device *udev, int config); +@@ -1491,14 +1492,6 @@ void usb_sg_wait(struct usb_sg_request * + #define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == PIPE_CONTROL) + #define usb_pipebulk(pipe) (usb_pipetype((pipe)) == PIPE_BULK) + +-/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */ +-#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1) +-#define usb_dotoggle(dev, ep, out) ((dev)->toggle[out] ^= (1 << (ep))) +-#define usb_settoggle(dev, ep, out, bit) \ +- ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \ +- ((bit) << (ep))) +- +- + static inline unsigned int __create_pipe(struct usb_device *dev, + unsigned int endpoint) + { diff --git a/usb.current/usb-serial-ti_usb_3410_5052.c-ti_usb-returns-eio-when-reopening-the-device.patch b/usb.current/usb-serial-ti_usb_3410_5052.c-ti_usb-returns-eio-when-reopening-the-device.patch new file mode 100644 index 00000000000000..77f7bcde8b53b0 --- /dev/null +++ b/usb.current/usb-serial-ti_usb_3410_5052.c-ti_usb-returns-eio-when-reopening-the-device.patch @@ -0,0 +1,39 @@ +From akpm@linux-foundation.org Wed Apr 15 21:31:15 2009 +From: Christoph Mair <christoph.mair@gmail.com> +Date: Wed, 15 Apr 2009 16:41:32 -0700 +Subject: USB: serial: ti_usb_3410_5052.c: ti_usb returns EIO when reopening the device +To: mm-commits@vger.kernel.org +Cc: christoph.mair@gmail.com, alan@lxorguk.ukuu.org.uk, greg@kroah.com, stable@kernel.org +Message-ID: <200904152341.n3FNfWj2010587@imap1.linux-foundation.org> + +From: Christoph Mair <christoph.mair@gmail.com> + +Fix regression introduced by 4a90f09b20f4622dcbff1f0e1e6bae1704f8ad8c +("tty: usb-serial krefs"). + +The driver works as expected until you close the device and try to reopen +it. All you get from now on, is an I/O error. It seems that something +isn't released correctly, because the refcount of the usbserial module +does not drop to zero, even when unloading all dependent drivers. + +Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> +Cc: <stable@kernel.org> +Signed-off-by: Andrew Morton <akpm@linux-foundation.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/serial/ti_usb_3410_5052.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/serial/ti_usb_3410_5052.c ++++ b/drivers/usb/serial/ti_usb_3410_5052.c +@@ -1231,8 +1231,8 @@ static void ti_bulk_in_callback(struct u + tport->tp_icount.rx += urb->actual_length; + spin_unlock(&tport->tp_lock); + } +- tty_kref_put(tty); + } ++ tty_kref_put(tty); + + exit: + /* continue to read unless stopping */ diff --git a/usb.current/usb-whci-hcd-check-return-value-of-usb_hcd_link_urb_to_ep.patch b/usb.current/usb-whci-hcd-check-return-value-of-usb_hcd_link_urb_to_ep.patch new file mode 100644 index 00000000000000..d14e9083ef77a0 --- /dev/null +++ b/usb.current/usb-whci-hcd-check-return-value-of-usb_hcd_link_urb_to_ep.patch @@ -0,0 +1,94 @@ +From dvrabel@hera.kernel.org Wed Apr 15 21:02:24 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Wed, 8 Apr 2009 17:36:31 +0000 +Subject: USB: whci-hcd: check return value of usb_hcd_link_urb_to_ep() +To: Greg KH <gregkh@suse.de> +Cc: David Vrabel <david.vrabel@csr.com> +Message-ID: <1239212193-27618-5-git-send-email-david.vrabel@csr.com> + + +Check the return value of usb_hcd_link_urb_to_ep() and do not add the +urb to the ASL/PZL if it returns an error. + +Omitting the check results in urbs that appear to be submitted +successfully but then cannot be unliked (because +usb_hcd_check_unlink_urb() returns an error). This can cause khubd (for +example) to block forever in usb_kill_urb(). + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/host/whci/asl.c | 12 +++++++++--- + drivers/usb/host/whci/pzl.c | 12 +++++++++--- + 2 files changed, 18 insertions(+), 6 deletions(-) + +--- a/drivers/usb/host/whci/asl.c ++++ b/drivers/usb/host/whci/asl.c +@@ -255,23 +255,29 @@ int asl_urb_enqueue(struct whc *whc, str + + spin_lock_irqsave(&whc->lock, flags); + ++ err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); ++ if (err < 0) { ++ spin_unlock_irqrestore(&whc->lock, flags); ++ return err; ++ } ++ + qset = get_qset(whc, urb, GFP_ATOMIC); + if (qset == NULL) + err = -ENOMEM; + else + err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); + if (!err) { +- usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); + if (!qset->in_sw_list) + asl_qset_insert_begin(whc, qset); +- } ++ } else ++ usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); + + spin_unlock_irqrestore(&whc->lock, flags); + + if (!err) + queue_work(whc->workqueue, &whc->async_work); + +- return 0; ++ return err; + } + + /** +--- a/drivers/usb/host/whci/pzl.c ++++ b/drivers/usb/host/whci/pzl.c +@@ -283,23 +283,29 @@ int pzl_urb_enqueue(struct whc *whc, str + + spin_lock_irqsave(&whc->lock, flags); + ++ err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); ++ if (err < 0) { ++ spin_unlock_irqrestore(&whc->lock, flags); ++ return err; ++ } ++ + qset = get_qset(whc, urb, GFP_ATOMIC); + if (qset == NULL) + err = -ENOMEM; + else + err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); + if (!err) { +- usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); + if (!qset->in_sw_list) + qset_insert_in_sw_list(whc, qset); +- } ++ } else ++ usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); + + spin_unlock_irqrestore(&whc->lock, flags); + + if (!err) + queue_work(whc->workqueue, &whc->periodic_work); + +- return 0; ++ return err; + } + + /** diff --git a/usb.current/usb-whci-hcd-provide-a-endpoint_reset-method.patch b/usb.current/usb-whci-hcd-provide-a-endpoint_reset-method.patch new file mode 100644 index 00000000000000..07384f3ba9d568 --- /dev/null +++ b/usb.current/usb-whci-hcd-provide-a-endpoint_reset-method.patch @@ -0,0 +1,167 @@ +From dvrabel@hera.kernel.org Wed Apr 15 21:01:59 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Wed, 8 Apr 2009 17:36:29 +0000 +Subject: USB: whci-hcd: provide a endpoint_reset method +To: Greg KH <gregkh@suse.de> +Cc: David Vrabel <david.vrabel@csr.com> +Message-ID: <1239212193-27618-3-git-send-email-david.vrabel@csr.com> + + +Provide a endpoint_reset method to reset sequence number and current +window. This QHead information can only be changed while the qset is +not in a schedule. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> +--- + drivers/usb/host/whci/asl.c | 3 ++- + drivers/usb/host/whci/hcd.c | 23 +++++++++++++++++++++++ + drivers/usb/host/whci/pzl.c | 4 ++-- + drivers/usb/host/whci/qset.c | 24 +++++++++++++++++++++--- + drivers/usb/host/whci/whcd.h | 1 + + drivers/usb/host/whci/whci-hc.h | 1 + + 6 files changed, 50 insertions(+), 6 deletions(-) + +--- a/drivers/usb/host/whci/asl.c ++++ b/drivers/usb/host/whci/asl.c +@@ -122,7 +122,8 @@ static uint32_t process_qset(struct whc + process_inactive_qtd(whc, qset, td); + } + +- update |= qset_add_qtds(whc, qset); ++ if (!qset->remove) ++ update |= qset_add_qtds(whc, qset); + + done: + /* +--- a/drivers/usb/host/whci/hcd.c ++++ b/drivers/usb/host/whci/hcd.c +@@ -186,6 +186,28 @@ static void whc_endpoint_disable(struct + } + } + ++static void whc_endpoint_reset(struct usb_hcd *usb_hcd, ++ struct usb_host_endpoint *ep) ++{ ++ struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); ++ struct whc *whc = wusbhc_to_whc(wusbhc); ++ struct whc_qset *qset; ++ ++ qset = ep->hcpriv; ++ if (qset) { ++ qset->remove = 1; ++ ++ if (usb_endpoint_xfer_bulk(&ep->desc) ++ || usb_endpoint_xfer_control(&ep->desc)) ++ queue_work(whc->workqueue, &whc->async_work); ++ else ++ queue_work(whc->workqueue, &whc->periodic_work); ++ ++ qset_reset(whc, qset); ++ } ++} ++ ++ + static struct hc_driver whc_hc_driver = { + .description = "whci-hcd", + .product_desc = "Wireless host controller", +@@ -200,6 +222,7 @@ static struct hc_driver whc_hc_driver = + .urb_enqueue = whc_urb_enqueue, + .urb_dequeue = whc_urb_dequeue, + .endpoint_disable = whc_endpoint_disable, ++ .endpoint_reset = whc_endpoint_reset, + + .hub_status_data = wusbhc_rh_status_data, + .hub_control = wusbhc_rh_control, +--- a/drivers/usb/host/whci/pzl.c ++++ b/drivers/usb/host/whci/pzl.c +@@ -128,7 +128,8 @@ static enum whc_update pzl_process_qset( + process_inactive_qtd(whc, qset, td); + } + +- update |= qset_add_qtds(whc, qset); ++ if (!qset->remove) ++ update |= qset_add_qtds(whc, qset); + + done: + /* +@@ -353,7 +354,6 @@ void pzl_qset_delete(struct whc *whc, st + qset_delete(whc, qset); + } + +- + /** + * pzl_init - initialize the periodic zone list + * @whc: the WHCI host controller +--- a/drivers/usb/host/whci/qset.c ++++ b/drivers/usb/host/whci/qset.c +@@ -89,11 +89,16 @@ static void qset_fill_qh(struct whc_qset + QH_INFO3_TX_RATE_53_3 + | QH_INFO3_TX_PWR(0) /* 0 == max power */ + ); ++ ++ qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); + } + + /** + * qset_clear - clear fields in a qset so it may be reinserted into a +- * schedule ++ * schedule. ++ * ++ * The sequence number and current window are not cleared (see ++ * qset_reset()). + */ + void qset_clear(struct whc *whc, struct whc_qset *qset) + { +@@ -101,9 +106,8 @@ void qset_clear(struct whc *whc, struct + qset->remove = 0; + + qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); +- qset->qh.status = cpu_to_le16(QH_STATUS_ICUR(qset->td_start)); ++ qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; + qset->qh.err_count = 0; +- qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); + qset->qh.scratch[0] = 0; + qset->qh.scratch[1] = 0; + qset->qh.scratch[2] = 0; +@@ -114,6 +118,20 @@ void qset_clear(struct whc *whc, struct + } + + /** ++ * qset_reset - reset endpoint state in a qset. ++ * ++ * Clears the sequence number and current window. This qset must not ++ * be in the ASL or PZL. ++ */ ++void qset_reset(struct whc *whc, struct whc_qset *qset) ++{ ++ wait_for_completion(&qset->remove_complete); ++ ++ qset->qh.status &= ~QH_STATUS_SEQ_MASK; ++ qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); ++} ++ ++/** + * get_qset - get the qset for an async endpoint + * + * A new qset is created if one does not already exist. +--- a/drivers/usb/host/whci/whcd.h ++++ b/drivers/usb/host/whci/whcd.h +@@ -184,6 +184,7 @@ void qset_free(struct whc *whc, struct w + struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags); + void qset_delete(struct whc *whc, struct whc_qset *qset); + void qset_clear(struct whc *whc, struct whc_qset *qset); ++void qset_reset(struct whc *whc, struct whc_qset *qset); + int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, + gfp_t mem_flags); + void qset_free_std(struct whc *whc, struct whc_std *std); +--- a/drivers/usb/host/whci/whci-hc.h ++++ b/drivers/usb/host/whci/whci-hc.h +@@ -185,6 +185,7 @@ struct whc_qhead { + #define QH_STATUS_FLOW_CTRL (1 << 15) + #define QH_STATUS_ICUR(i) ((i) << 5) + #define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7) ++#define QH_STATUS_SEQ_MASK 0x1f + + /** + * usb_pipe_to_qh_type - USB core pipe type to QH transfer type diff --git a/usb.current/wusb-correct-format-of-wusb_chid-sysfs-file.patch b/usb.current/wusb-correct-format-of-wusb_chid-sysfs-file.patch new file mode 100644 index 00000000000000..d87cee2c2b2d58 --- /dev/null +++ b/usb.current/wusb-correct-format-of-wusb_chid-sysfs-file.patch @@ -0,0 +1,69 @@ +From dvrabel@hera.kernel.org Wed Apr 15 21:03:49 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Wed, 8 Apr 2009 17:36:30 +0000 +Subject: WUSB: correct format of wusb_chid sysfs file +To: Greg KH <gregkh@suse.de> +Cc: David Vrabel <david.vrabel@csr.com> +Message-ID: <1239212193-27618-4-git-send-email-david.vrabel@csr.com> + + +Make the wusb_chid sysfs file match the ABI documentation. + +Print all zeros if the WUSB host is stopped (instead of an empty file) +and end the file with a newline. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/wusbcore/wusbhc.c | 26 ++++++++++++-------------- + 1 file changed, 12 insertions(+), 14 deletions(-) + +--- a/drivers/usb/wusbcore/wusbhc.c ++++ b/drivers/usb/wusbcore/wusbhc.c +@@ -88,33 +88,31 @@ static DEVICE_ATTR(wusb_trust_timeout, 0 + wusb_trust_timeout_store); + + /* +- * Show & store the current WUSB CHID ++ * Show the current WUSB CHID. + */ + static ssize_t wusb_chid_show(struct device *dev, + struct device_attribute *attr, char *buf) + { + struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); ++ const struct wusb_ckhdid *chid; + ssize_t result = 0; + + if (wusbhc->wuie_host_info != NULL) +- result += ckhdid_printf(buf, PAGE_SIZE, +- &wusbhc->wuie_host_info->CHID); ++ chid = &wusbhc->wuie_host_info->CHID; ++ else ++ chid = &wusb_ckhdid_zero; ++ ++ result += ckhdid_printf(buf, PAGE_SIZE, chid); ++ result += sprintf(buf + result, "\n"); ++ + return result; + } + + /* +- * Store a new CHID +- * +- * This will (FIXME) trigger many changes. ++ * Store a new CHID. + * +- * - Send an all zeros CHID and it will stop the controller +- * - Send a non-zero CHID and it will start it +- * (unless it was started, it will just change the CHID, +- * diconnecting all devices first). +- * +- * So first we scan the MMC we are sent and then we act on it. We +- * read it in the same format as we print it, an ASCII string of 16 +- * hex bytes. ++ * - Write an all zeros CHID and it will stop the controller ++ * - Write a non-zero CHID and it will start it. + * + * See wusbhc_chid_set() for more info. + */ diff --git a/usb.current/wusb-disconnect-all-devices-when-stopping-a-wusb-hcd.patch b/usb.current/wusb-disconnect-all-devices-when-stopping-a-wusb-hcd.patch new file mode 100644 index 00000000000000..1ec1895f5641d1 --- /dev/null +++ b/usb.current/wusb-disconnect-all-devices-when-stopping-a-wusb-hcd.patch @@ -0,0 +1,58 @@ +From dvrabel@hera.kernel.org Wed Apr 15 21:02:54 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Wed, 8 Apr 2009 17:36:33 +0000 +Subject: WUSB: disconnect all devices when stopping a WUSB HCD +To: Greg KH <gregkh@suse.de> +Cc: David Vrabel <david.vrabel@csr.com> +Message-ID: <1239212193-27618-7-git-send-email-david.vrabel@csr.com> + + +Make sure all WUSB devices are disconnected when stopping a WUSB HCD so +that we don't leak the devices' wusb_dev structures. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/wusbcore/devconnect.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +--- a/drivers/usb/wusbcore/devconnect.c ++++ b/drivers/usb/wusbcore/devconnect.c +@@ -396,7 +396,8 @@ static void __wusbhc_dev_disconnect(stru + + /* After a device disconnects, change the GTK (see [WUSB] + * section 6.2.11.2). */ +- wusbhc_gtk_rekey(wusbhc); ++ if (wusbhc->active) ++ wusbhc_gtk_rekey(wusbhc); + + /* The Wireless USB part has forgotten about the device already; now + * khubd's timer will pick up the disconnection and remove the USB +@@ -1084,15 +1085,21 @@ error_mmcie_set: + * wusbhc_devconnect_stop - stop managing connected devices + * @wusbhc: the WUSB HC + * +- * Removes the Host Info IE and stops the keep alives. +- * +- * FIXME: should this disconnect all devices? ++ * Disconnects any devices still connected, stops the keep alives and ++ * removes the Host Info IE. + */ + void wusbhc_devconnect_stop(struct wusbhc *wusbhc) + { +- cancel_delayed_work_sync(&wusbhc->keep_alive_timer); +- WARN_ON(!list_empty(&wusbhc->cack_list)); ++ int i; + ++ mutex_lock(&wusbhc->mutex); ++ for (i = 0; i < wusbhc->ports_max; i++) { ++ if (wusbhc->port[i].wusb_dev) ++ __wusbhc_dev_disconnect(wusbhc, &wusbhc->port[i]); ++ } ++ mutex_unlock(&wusbhc->mutex); ++ ++ cancel_delayed_work_sync(&wusbhc->keep_alive_timer); + wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr); + kfree(wusbhc->wuie_host_info); + wusbhc->wuie_host_info = NULL; diff --git a/usb.current/wusb-fix-oops-when-completing-urbs-for-disconnected-devices.patch b/usb.current/wusb-fix-oops-when-completing-urbs-for-disconnected-devices.patch new file mode 100644 index 00000000000000..f388a25bb3c792 --- /dev/null +++ b/usb.current/wusb-fix-oops-when-completing-urbs-for-disconnected-devices.patch @@ -0,0 +1,53 @@ +From dvrabel@hera.kernel.org Wed Apr 15 21:03:18 2009 +From: David Vrabel <david.vrabel@csr.com> +Date: Wed, 8 Apr 2009 17:36:32 +0000 +Subject: WUSB: fix oops when completing URBs for disconnected devices +To: Greg KH <gregkh@suse.de> +Cc: David Vrabel <david.vrabel@csr.com> +Message-ID: <1239212193-27618-6-git-send-email-david.vrabel@csr.com> + + +Fix an oops in wusbhc_giveback_urb() if the wusb device had disconnected +while an urb was in progress. Also release the ref count obtained here. + +Signed-off-by: David Vrabel <david.vrabel@csr.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/wusbcore/devconnect.c | 2 ++ + drivers/usb/wusbcore/wusbhc.c | 8 +++++--- + 2 files changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/usb/wusbcore/devconnect.c ++++ b/drivers/usb/wusbcore/devconnect.c +@@ -267,6 +267,8 @@ static void wusbhc_devconnect_acked_work + mutex_lock(&wusbhc->mutex); + wusbhc_devconnect_acked(wusbhc, wusb_dev); + mutex_unlock(&wusbhc->mutex); ++ ++ wusb_dev_put(wusb_dev); + } + + /* +--- a/drivers/usb/wusbcore/wusbhc.c ++++ b/drivers/usb/wusbcore/wusbhc.c +@@ -338,14 +338,16 @@ EXPORT_SYMBOL_GPL(wusb_cluster_id_put); + void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status) + { + struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); +- +- if (status == 0) { ++ ++ if (status == 0 && wusb_dev) { + wusb_dev->entry_ts = jiffies; + +- /* wusbhc_devconnect_acked() can't be called from from ++ /* wusbhc_devconnect_acked() can't be called from + atomic context so defer it to a work queue. */ + if (!list_empty(&wusb_dev->cack_node)) + queue_work(wusbd, &wusb_dev->devconnect_acked_work); ++ else ++ wusb_dev_put(wusb_dev); + } + + usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status); |
