diff options
Diffstat (limited to 'drivers/usb/wusbcore/wa-rpipe.c')
| -rw-r--r-- | drivers/usb/wusbcore/wa-rpipe.c | 183 |
1 files changed, 88 insertions, 95 deletions
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index f18e4aae66e..a80c5d284b5 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -24,7 +24,7 @@ * * RPIPE * - * Targetted at different downstream endpoints + * Targeted at different downstream endpoints * * Descriptor: use to config the remote pipe. * @@ -49,7 +49,7 @@ * * USB Stack port number 4 (1 based) * WUSB code port index 3 (0 based) - * USB Addresss 5 (2 based -- 0 is for default, 1 for root hub) + * USB Address 5 (2 based -- 0 is for default, 1 for root hub) * * Now, because we don't use the concept as default address exactly * like the (wired) USB code does, we need to kind of skip it. So we @@ -57,16 +57,14 @@ * urb->dev->devnum, to make sure that we always have the right * destination address. */ -#include <linux/init.h> -#include <asm/atomic.h> +#include <linux/atomic.h> #include <linux/bitmap.h> +#include <linux/slab.h> +#include <linux/export.h> + #include "wusbhc.h" #include "wa-hc.h" -#define D_LOCAL 0 -#include <linux/uwb/debug.h> - - static int __rpipe_get_descr(struct wahc *wa, struct usb_rpipe_descriptor *descr, u16 index) { @@ -76,13 +74,12 @@ static int __rpipe_get_descr(struct wahc *wa, /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor() * function because the arguments are different. */ - d_printf(1, dev, "rpipe %u: get descr\n", index); result = usb_control_msg( wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE, USB_DT_RPIPE<<8, index, descr, sizeof(*descr), - 1000 /* FIXME: arbitrary */); + USB_CTRL_GET_TIMEOUT); if (result < 0) { dev_err(dev, "rpipe %u: get descriptor failed: %d\n", index, (int)result); @@ -115,13 +112,12 @@ static int __rpipe_set_descr(struct wahc *wa, /* we cannot use the usb_get_descriptor() function because the * arguments are different. */ - d_printf(1, dev, "rpipe %u: set descr\n", index); result = usb_control_msg( wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), USB_REQ_SET_DESCRIPTOR, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, USB_DT_RPIPE<<8, index, descr, sizeof(*descr), - HZ / 10); + USB_CTRL_SET_TIMEOUT); if (result < 0) { dev_err(dev, "rpipe %u: set descriptor failed: %d\n", index, (int)result); @@ -146,17 +142,18 @@ static void rpipe_init(struct wa_rpipe *rpipe) kref_init(&rpipe->refcnt); spin_lock_init(&rpipe->seg_lock); INIT_LIST_HEAD(&rpipe->seg_list); + INIT_LIST_HEAD(&rpipe->list_node); } static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx) { unsigned long flags; - spin_lock_irqsave(&wa->rpipe_bm_lock, flags); + spin_lock_irqsave(&wa->rpipe_lock, flags); rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx); if (rpipe_idx < wa->rpipes) set_bit(rpipe_idx, wa->rpipe_bm); - spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); + spin_unlock_irqrestore(&wa->rpipe_lock, flags); return rpipe_idx; } @@ -165,29 +162,28 @@ static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx) { unsigned long flags; - spin_lock_irqsave(&wa->rpipe_bm_lock, flags); + spin_lock_irqsave(&wa->rpipe_lock, flags); clear_bit(rpipe_idx, wa->rpipe_bm); - spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); + spin_unlock_irqrestore(&wa->rpipe_lock, flags); } void rpipe_destroy(struct kref *_rpipe) { struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt); u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex); - d_fnstart(1, NULL, "(rpipe %p %u)\n", rpipe, index); + if (rpipe->ep) rpipe->ep->hcpriv = NULL; rpipe_put_idx(rpipe->wa, index); wa_put(rpipe->wa); kfree(rpipe); - d_fnend(1, NULL, "(rpipe %p %u)\n", rpipe, index); } EXPORT_SYMBOL_GPL(rpipe_destroy); /* * Locate an idle rpipe, create an structure for it and return it * - * @wa is referenced and unlocked + * @wa is referenced and unlocked * @crs enum rpipe_attr, required endpoint characteristics * * The rpipe can be used only sequentially (not in parallel). @@ -202,7 +198,6 @@ static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs, struct wa_rpipe *rpipe; struct device *dev = &wa->usb_iface->dev; - d_fnstart(3, dev, "(wa %p crs 0x%02x)\n", wa, crs); rpipe = kzalloc(sizeof(*rpipe), gfp); if (rpipe == NULL) return -ENOMEM; @@ -223,14 +218,12 @@ static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs, } *prpipe = NULL; kfree(rpipe); - d_fnend(3, dev, "(wa %p crs 0x%02x) = -ENXIO\n", wa, crs); return -ENXIO; found: set_bit(rpipe_idx, wa->rpipe_bm); rpipe->wa = wa_get(wa); *prpipe = rpipe; - d_fnstart(3, dev, "(wa %p crs 0x%02x) = 0\n", wa, crs); return 0; } @@ -239,12 +232,11 @@ static int __rpipe_reset(struct wahc *wa, unsigned index) int result; struct device *dev = &wa->usb_iface->dev; - d_printf(1, dev, "rpipe %u: reset\n", index); result = usb_control_msg( wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), USB_REQ_RPIPE_RESET, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, - 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); + 0, index, NULL, 0, USB_CTRL_SET_TIMEOUT); if (result < 0) dev_err(dev, "rpipe %u: reset failed: %d\n", index, result); @@ -259,8 +251,8 @@ static int __rpipe_reset(struct wahc *wa, unsigned index) static struct usb_wireless_ep_comp_descriptor epc0 = { .bLength = sizeof(epc0), .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP, -/* .bMaxBurst = 1, */ - .bMaxSequence = 31, + .bMaxBurst = 1, + .bMaxSequence = 2, }; /* @@ -276,7 +268,6 @@ static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find( struct usb_descriptor_header *hdr; struct usb_wireless_ep_comp_descriptor *epcd; - d_fnstart(3, dev, "(ep %p)\n", ep); if (ep->desc.bEndpointAddress == 0) { epcd = &epc0; goto out; @@ -307,17 +298,16 @@ static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find( break; } itr += hdr->bLength; - itr_size -= hdr->bDescriptorType; + itr_size -= hdr->bLength; } out: - d_fnend(3, dev, "(ep %p) = %p\n", ep, epcd); return epcd; } /* * Aim an rpipe to its device & endpoint destination * - * Make sure we change the address to unauthenticathed if the device + * Make sure we change the address to unauthenticated if the device * is WUSB and it is not authenticated. */ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, @@ -327,10 +317,9 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, struct device *dev = &wa->usb_iface->dev; struct usb_device *usb_dev = urb->dev; struct usb_wireless_ep_comp_descriptor *epcd; + u32 ack_window, epcd_max_sequence; u8 unauth; - d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", - rpipe, wa, ep, urb); epcd = rpipe_epc_find(dev, ep); if (epcd == NULL) { dev_err(dev, "ep 0x%02x: can't find companion descriptor\n", @@ -339,41 +328,52 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, } unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0; __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex)); - atomic_set(&rpipe->segs_available, le16_to_cpu(rpipe->descr.wRequests)); + atomic_set(&rpipe->segs_available, + le16_to_cpu(rpipe->descr.wRequests)); /* FIXME: block allocation system; request with queuing and timeout */ /* FIXME: compute so seg_size > ep->maxpktsize */ rpipe->descr.wBlocks = cpu_to_le16(16); /* given */ /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */ - rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize); - rpipe->descr.bHSHubAddress = 0; /* reserved: zero */ - rpipe->descr.bHSHubPort = wusb_port_no_to_idx(urb->dev->portnum); + if (usb_endpoint_xfer_isoc(&ep->desc)) + rpipe->descr.wMaxPacketSize = epcd->wOverTheAirPacketSize; + else + rpipe->descr.wMaxPacketSize = ep->desc.wMaxPacketSize; + + rpipe->descr.hwa_bMaxBurst = max(min_t(unsigned int, + epcd->bMaxBurst, 16U), 1U); + rpipe->descr.hwa_bDeviceInfoIndex = + wusb_port_no_to_idx(urb->dev->portnum); /* FIXME: use maximum speed as supported or recommended by device */ rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ? UWB_PHY_RATE_53 : UWB_PHY_RATE_200; - d_printf(2, dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n", - urb->dev->devnum, urb->dev->devnum | unauth, - le16_to_cpu(rpipe->descr.wRPipeIndex), - usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); - /* see security.c:wusb_update_address() */ - if (unlikely(urb->dev->devnum == 0x80)) - rpipe->descr.bDeviceAddress = 0; - else - rpipe->descr.bDeviceAddress = urb->dev->devnum | unauth; + + dev_dbg(dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n", + urb->dev->devnum, urb->dev->devnum | unauth, + le16_to_cpu(rpipe->descr.wRPipeIndex), + usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed); + + rpipe->descr.hwa_reserved = 0; + rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress; /* FIXME: bDataSequence */ rpipe->descr.bDataSequence = 0; - /* FIXME: dwCurrentWindow */ - rpipe->descr.dwCurrentWindow = cpu_to_le32(1); - /* FIXME: bMaxDataSequence */ - rpipe->descr.bMaxDataSequence = epcd->bMaxSequence - 1; + + /* start with base window of hwa_bMaxBurst bits starting at 0. */ + ack_window = 0xFFFFFFFF >> (32 - rpipe->descr.hwa_bMaxBurst); + rpipe->descr.dwCurrentWindow = cpu_to_le32(ack_window); + epcd_max_sequence = max(min_t(unsigned int, + epcd->bMaxSequence, 32U), 2U); + rpipe->descr.bMaxDataSequence = epcd_max_sequence - 1; rpipe->descr.bInterval = ep->desc.bInterval; - /* FIXME: bOverTheAirInterval */ - rpipe->descr.bOverTheAirInterval = 0; /* 0 if not isoc */ + if (usb_endpoint_xfer_isoc(&ep->desc)) + rpipe->descr.bOverTheAirInterval = epcd->bOverTheAirInterval; + else + rpipe->descr.bOverTheAirInterval = 0; /* 0 if not isoc */ /* FIXME: xmit power & preamble blah blah */ - rpipe->descr.bmAttribute = ep->desc.bmAttributes & 0x03; + rpipe->descr.bmAttribute = (ep->desc.bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK); /* rpipe->descr.bmCharacteristics RO */ - /* FIXME: bmRetryOptions */ - rpipe->descr.bmRetryOptions = 15; + rpipe->descr.bmRetryOptions = (wa->wusb->retry_count & 0xF); /* FIXME: use for assessing link quality? */ rpipe->descr.wNumTransactionErrors = 0; result = __rpipe_set_descr(wa, &rpipe->descr, @@ -384,8 +384,6 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, } result = 0; error: - d_fnend(3, dev, "(rpipe %p wa %p ep %p urb %p) = %d\n", - rpipe, wa, ep, urb, result); return result; } @@ -399,14 +397,10 @@ static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa, const struct usb_host_endpoint *ep, const struct urb *urb, gfp_t gfp) { - int result = 0; /* better code for lack of companion? */ + int result = 0; struct device *dev = &wa->usb_iface->dev; - struct usb_device *usb_dev = urb->dev; - u8 unauth = (usb_dev->wusb && !usb_dev->authenticated) ? 0x80 : 0; u8 portnum = wusb_port_no_to_idx(urb->dev->portnum); - d_fnstart(3, dev, "(rpipe %p wa %p ep %p, urb %p)\n", - rpipe, wa, ep, urb); #define AIM_CHECK(rdf, val, text) \ do { \ if (rpipe->descr.rdf != (val)) { \ @@ -417,13 +411,10 @@ static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa, WARN_ON(1); \ } \ } while (0) - AIM_CHECK(wMaxPacketSize, cpu_to_le16(ep->desc.wMaxPacketSize), - "(%u vs %u)"); - AIM_CHECK(bHSHubPort, portnum, "(%u vs %u)"); + AIM_CHECK(hwa_bDeviceInfoIndex, portnum, "(%u vs %u)"); AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ? UWB_PHY_RATE_53 : UWB_PHY_RATE_200, "(%u vs %u)"); - AIM_CHECK(bDeviceAddress, urb->dev->devnum | unauth, "(%u vs %u)"); AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)"); AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)"); AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)"); @@ -451,8 +442,6 @@ int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, struct wa_rpipe *rpipe; u8 eptype; - d_fnstart(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, - gfp); mutex_lock(&wa->rpipe_mutex); rpipe = ep->hcpriv; if (rpipe != NULL) { @@ -462,9 +451,9 @@ int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, goto error; } __rpipe_get(rpipe); - d_printf(2, dev, "ep 0x%02x: reusing rpipe %u\n", - ep->desc.bEndpointAddress, - le16_to_cpu(rpipe->descr.wRPipeIndex)); + dev_dbg(dev, "ep 0x%02x: reusing rpipe %u\n", + ep->desc.bEndpointAddress, + le16_to_cpu(rpipe->descr.wRPipeIndex)); } else { /* hmm, assign idle rpipe, aim it */ result = -ENOBUFS; @@ -480,14 +469,12 @@ int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep, ep->hcpriv = rpipe; rpipe->ep = ep; __rpipe_get(rpipe); /* for caching into ep->hcpriv */ - d_printf(2, dev, "ep 0x%02x: using rpipe %u\n", - ep->desc.bEndpointAddress, - le16_to_cpu(rpipe->descr.wRPipeIndex)); + dev_dbg(dev, "ep 0x%02x: using rpipe %u\n", + ep->desc.bEndpointAddress, + le16_to_cpu(rpipe->descr.wRPipeIndex)); } - d_dump(4, dev, &rpipe->descr, sizeof(rpipe->descr)); error: mutex_unlock(&wa->rpipe_mutex); - d_fnend(3, dev, "(wa %p ep %p urb %p gfp 0x%08x)\n", wa, ep, urb, gfp); return result; } @@ -496,7 +483,7 @@ error: */ int wa_rpipes_create(struct wahc *wa) { - wa->rpipes = wa->wa_descr->wNumRPipes; + wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes); wa->rpipe_bm = kzalloc(BITS_TO_LONGS(wa->rpipes)*sizeof(unsigned long), GFP_KERNEL); if (wa->rpipe_bm == NULL) @@ -507,7 +494,7 @@ int wa_rpipes_create(struct wahc *wa) void wa_rpipes_destroy(struct wahc *wa) { struct device *dev = &wa->usb_iface->dev; - d_fnstart(3, dev, "(wa %p)\n", wa); + if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) { char buf[256]; WARN_ON(1); @@ -515,7 +502,6 @@ void wa_rpipes_destroy(struct wahc *wa) dev_err(dev, "BUG: pipes not released on exit: %s\n", buf); } kfree(wa->rpipe_bm); - d_fnend(3, dev, "(wa %p)\n", wa); } /* @@ -530,33 +516,40 @@ void wa_rpipes_destroy(struct wahc *wa) */ void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep) { - struct device *dev = &wa->usb_iface->dev; struct wa_rpipe *rpipe; - d_fnstart(2, dev, "(wa %p ep %p)\n", wa, ep); + mutex_lock(&wa->rpipe_mutex); rpipe = ep->hcpriv; if (rpipe != NULL) { - unsigned rc = atomic_read(&rpipe->refcnt.refcount); - int result; u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex); - if (rc != 1) - d_printf(1, dev, "(wa %p ep %p) rpipe %p refcnt %u\n", - wa, ep, rpipe, rc); - - d_printf(1, dev, "rpipe %u: abort\n", index); - result = usb_control_msg( - wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), + usb_control_msg( + wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), USB_REQ_RPIPE_ABORT, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, - 0, index, NULL, 0, 1000 /* FIXME: arbitrary */); - if (result < 0 && result != -ENODEV /* dev is gone */) - d_printf(1, dev, "(wa %p rpipe %u): abort failed: %d\n", - wa, index, result); + 0, index, NULL, 0, USB_CTRL_SET_TIMEOUT); rpipe_put(rpipe); } mutex_unlock(&wa->rpipe_mutex); - d_fnend(2, dev, "(wa %p ep %p)\n", wa, ep); - return; } EXPORT_SYMBOL_GPL(rpipe_ep_disable); + +/* Clear the stalled status of an RPIPE. */ +void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep) +{ + struct wa_rpipe *rpipe; + + mutex_lock(&wa->rpipe_mutex); + rpipe = ep->hcpriv; + if (rpipe != NULL) { + u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex); + + usb_control_msg( + wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), + USB_REQ_CLEAR_FEATURE, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, + RPIPE_STALL, index, NULL, 0, USB_CTRL_SET_TIMEOUT); + } + mutex_unlock(&wa->rpipe_mutex); +} +EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled); |
