aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/wusbcore
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/wusbcore')
-rw-r--r--drivers/usb/wusbcore/devconnect.c6
-rw-r--r--drivers/usb/wusbcore/mmc.c33
-rw-r--r--drivers/usb/wusbcore/pal.c5
-rw-r--r--drivers/usb/wusbcore/reservation.c3
-rw-r--r--drivers/usb/wusbcore/rh.c20
-rw-r--r--drivers/usb/wusbcore/wa-nep.c3
-rw-r--r--drivers/usb/wusbcore/wa-rpipe.c45
-rw-r--r--drivers/usb/wusbcore/wa-xfer.c181
-rw-r--r--drivers/usb/wusbcore/wusbhc.c79
-rw-r--r--drivers/usb/wusbcore/wusbhc.h7
10 files changed, 303 insertions, 79 deletions
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c
index 1d365316960c..33a12788f9ca 100644
--- a/drivers/usb/wusbcore/devconnect.c
+++ b/drivers/usb/wusbcore/devconnect.c
@@ -455,8 +455,8 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
dev_err(dev, "KEEPALIVE: device %u timed out\n",
wusb_dev->addr);
__wusbhc_dev_disconnect(wusbhc, wusb_port);
- } else if (time_after(jiffies, wusb_dev->entry_ts + tt/2)) {
- /* Approaching timeout cut out, need to refresh */
+ } else if (time_after(jiffies, wusb_dev->entry_ts + tt/3)) {
+ /* Approaching timeout cut off, need to refresh */
ie->bDeviceAddress[keep_alives++] = wusb_dev->addr;
}
}
@@ -1062,7 +1062,7 @@ int wusbhc_devconnect_start(struct wusbhc *wusbhc)
wusbhc->wuie_host_info = hi;
queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
- (wusbhc->trust_timeout*CONFIG_HZ)/1000/2);
+ msecs_to_jiffies(wusbhc->trust_timeout / 2));
return 0;
diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c
index b8c72583c040..b71760c8d3ad 100644
--- a/drivers/usb/wusbcore/mmc.c
+++ b/drivers/usb/wusbcore/mmc.c
@@ -195,6 +195,7 @@ int wusbhc_start(struct wusbhc *wusbhc)
struct device *dev = wusbhc->dev;
WARN_ON(wusbhc->wuie_host_info != NULL);
+ BUG_ON(wusbhc->uwb_rc == NULL);
result = wusbhc_rsv_establish(wusbhc);
if (result < 0) {
@@ -214,9 +215,9 @@ int wusbhc_start(struct wusbhc *wusbhc)
dev_err(dev, "error starting security in the HC: %d\n", result);
goto error_sec_start;
}
- /* FIXME: the choice of the DNTS parameters is somewhat
- * arbitrary */
- result = wusbhc->set_num_dnts(wusbhc, 0, 15);
+
+ result = wusbhc->set_num_dnts(wusbhc, wusbhc->dnts_interval,
+ wusbhc->dnts_num_slots);
if (result < 0) {
dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
goto error_set_num_dnts;
@@ -276,12 +277,38 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
}
wusbhc->chid = *chid;
}
+
+ /* register with UWB if we haven't already since we are about to start
+ the radio. */
+ if ((chid) && (wusbhc->uwb_rc == NULL)) {
+ wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent);
+ if (wusbhc->uwb_rc == NULL) {
+ result = -ENODEV;
+ dev_err(wusbhc->dev, "Cannot get associated UWB Host Controller\n");
+ goto error_rc_get;
+ }
+
+ result = wusbhc_pal_register(wusbhc);
+ if (result < 0) {
+ dev_err(wusbhc->dev, "Cannot register as a UWB PAL\n");
+ goto error_pal_register;
+ }
+ }
mutex_unlock(&wusbhc->mutex);
if (chid)
result = uwb_radio_start(&wusbhc->pal);
else
uwb_radio_stop(&wusbhc->pal);
+
+ return result;
+
+error_pal_register:
+ uwb_rc_put(wusbhc->uwb_rc);
+ wusbhc->uwb_rc = NULL;
+error_rc_get:
+ mutex_unlock(&wusbhc->mutex);
+
return result;
}
EXPORT_SYMBOL_GPL(wusbhc_chid_set);
diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c
index d0b172c5ecc7..59e100c2eb50 100644
--- a/drivers/usb/wusbcore/pal.c
+++ b/drivers/usb/wusbcore/pal.c
@@ -45,10 +45,11 @@ int wusbhc_pal_register(struct wusbhc *wusbhc)
}
/**
- * wusbhc_pal_register - unregister the WUSB HC as a UWB PAL
+ * wusbhc_pal_unregister - unregister the WUSB HC as a UWB PAL
* @wusbhc: the WUSB HC
*/
void wusbhc_pal_unregister(struct wusbhc *wusbhc)
{
- uwb_pal_unregister(&wusbhc->pal);
+ if (wusbhc->uwb_rc)
+ uwb_pal_unregister(&wusbhc->pal);
}
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c
index 6f4fafdc2401..ead79f793927 100644
--- a/drivers/usb/wusbcore/reservation.c
+++ b/drivers/usb/wusbcore/reservation.c
@@ -80,6 +80,9 @@ int wusbhc_rsv_establish(struct wusbhc *wusbhc)
struct uwb_dev_addr bcid;
int ret;
+ if (rc == NULL)
+ return -ENODEV;
+
rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);
if (rsv == NULL)
return -ENOMEM;
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
index 59ff254dfb6f..bdb0cc3046b5 100644
--- a/drivers/usb/wusbcore/rh.c
+++ b/drivers/usb/wusbcore/rh.c
@@ -393,26 +393,6 @@ int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue,
}
EXPORT_SYMBOL_GPL(wusbhc_rh_control);
-int wusbhc_rh_suspend(struct usb_hcd *usb_hcd)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
- usb_hcd, wusbhc);
- /* dump_stack(); */
- return -ENOSYS;
-}
-EXPORT_SYMBOL_GPL(wusbhc_rh_suspend);
-
-int wusbhc_rh_resume(struct usb_hcd *usb_hcd)
-{
- struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
- dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
- usb_hcd, wusbhc);
- /* dump_stack(); */
- return -ENOSYS;
-}
-EXPORT_SYMBOL_GPL(wusbhc_rh_resume);
-
int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx)
{
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c
index f67f7f1e6df9..ada4e0870623 100644
--- a/drivers/usb/wusbcore/wa-nep.c
+++ b/drivers/usb/wusbcore/wa-nep.c
@@ -134,9 +134,10 @@ static void wa_notif_dispatch(struct work_struct *ws)
case WA_NOTIF_TRANSFER:
wa_handle_notif_xfer(wa, notif_hdr);
break;
+ case HWA_NOTIF_BPST_ADJ:
+ break; /* no action needed for BPST ADJ. */
case DWA_NOTIF_RWAKE:
case DWA_NOTIF_PORTSTATUS:
- case HWA_NOTIF_BPST_ADJ:
/* FIXME: unimplemented WA NOTIFs */
/* fallthru */
default:
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
index f0d546c5a089..9a595c1ed867 100644
--- a/drivers/usb/wusbcore/wa-rpipe.c
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -251,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,
};
/*
@@ -317,6 +317,7 @@ 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;
epcd = rpipe_epc_find(dev, ep);
@@ -333,8 +334,11 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,
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);
+
+ 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;
@@ -344,26 +348,26 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,
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;
+ 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 */
/* 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,
@@ -387,10 +391,8 @@ 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);
#define AIM_CHECK(rdf, val, text) \
@@ -403,13 +405,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)");
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
index 6ef94bce8c0d..16968c899493 100644
--- a/drivers/usb/wusbcore/wa-xfer.c
+++ b/drivers/usb/wusbcore/wa-xfer.c
@@ -85,6 +85,7 @@
#include <linux/hash.h>
#include <linux/ratelimit.h>
#include <linux/export.h>
+#include <linux/scatterlist.h>
#include "wa-hc.h"
#include "wusbhc.h"
@@ -442,8 +443,7 @@ static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,
goto error;
}
xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize;
- xfer->segs = (urb->transfer_buffer_length + xfer->seg_size - 1)
- / xfer->seg_size;
+ xfer->segs = DIV_ROUND_UP(urb->transfer_buffer_length, xfer->seg_size);
if (xfer->segs >= WA_SEGS_MAX) {
dev_err(dev, "BUG? ops, number of segments %d bigger than %d\n",
(int)(urb->transfer_buffer_length / xfer->seg_size),
@@ -627,6 +627,86 @@ static void wa_seg_cb(struct urb *urb)
}
}
+/* allocate an SG list to store bytes_to_transfer bytes and copy the
+ * subset of the in_sg that matches the buffer subset
+ * we are about to transfer. */
+static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
+ const unsigned int bytes_transferred,
+ const unsigned int bytes_to_transfer, unsigned int *out_num_sgs)
+{
+ struct scatterlist *out_sg;
+ unsigned int bytes_processed = 0, offset_into_current_page_data = 0,
+ nents;
+ struct scatterlist *current_xfer_sg = in_sg;
+ struct scatterlist *current_seg_sg, *last_seg_sg;
+
+ /* skip previously transferred pages. */
+ while ((current_xfer_sg) &&
+ (bytes_processed < bytes_transferred)) {
+ bytes_processed += current_xfer_sg->length;
+
+ /* advance the sg if current segment starts on or past the
+ next page. */
+ if (bytes_processed <= bytes_transferred)
+ current_xfer_sg = sg_next(current_xfer_sg);
+ }
+
+ /* the data for the current segment starts in current_xfer_sg.
+ calculate the offset. */
+ if (bytes_processed > bytes_transferred) {
+ offset_into_current_page_data = current_xfer_sg->length -
+ (bytes_processed - bytes_transferred);
+ }
+
+ /* calculate the number of pages needed by this segment. */
+ nents = DIV_ROUND_UP((bytes_to_transfer +
+ offset_into_current_page_data +
+ current_xfer_sg->offset),
+ PAGE_SIZE);
+
+ out_sg = kmalloc((sizeof(struct scatterlist) * nents), GFP_ATOMIC);
+ if (out_sg) {
+ sg_init_table(out_sg, nents);
+
+ /* copy the portion of the incoming SG that correlates to the
+ * data to be transferred by this segment to the segment SG. */
+ last_seg_sg = current_seg_sg = out_sg;
+ bytes_processed = 0;
+
+ /* reset nents and calculate the actual number of sg entries
+ needed. */
+ nents = 0;
+ while ((bytes_processed < bytes_to_transfer) &&
+ current_seg_sg && current_xfer_sg) {
+ unsigned int page_len = min((current_xfer_sg->length -
+ offset_into_current_page_data),
+ (bytes_to_transfer - bytes_processed));
+
+ sg_set_page(current_seg_sg, sg_page(current_xfer_sg),
+ page_len,
+ current_xfer_sg->offset +
+ offset_into_current_page_data);
+
+ bytes_processed += page_len;
+
+ last_seg_sg = current_seg_sg;
+ current_seg_sg = sg_next(current_seg_sg);
+ current_xfer_sg = sg_next(current_xfer_sg);
+
+ /* only the first page may require additional offset. */
+ offset_into_current_page_data = 0;
+ nents++;
+ }
+
+ /* update num_sgs and terminate the list since we may have
+ * concatenated pages. */
+ sg_mark_end(last_seg_sg);
+ *out_num_sgs = nents;
+ }
+
+ return out_sg;
+}
+
/*
* Allocate the segs array and initialize each of them
*
@@ -663,9 +743,9 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
dto_epd->bEndpointAddress),
&seg->xfer_hdr, xfer_hdr_size,
wa_seg_cb, seg);
- buf_itr_size = buf_size > xfer->seg_size ?
- xfer->seg_size : buf_size;
+ buf_itr_size = min(buf_size, xfer->seg_size);
if (xfer->is_inbound == 0 && buf_size > 0) {
+ /* outbound data. */
seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC);
if (seg->dto_urb == NULL)
goto error_dto_alloc;
@@ -679,9 +759,42 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
xfer->urb->transfer_dma + buf_itr;
seg->dto_urb->transfer_flags |=
URB_NO_TRANSFER_DMA_MAP;
- } else
- seg->dto_urb->transfer_buffer =
- xfer->urb->transfer_buffer + buf_itr;
+ seg->dto_urb->transfer_buffer = NULL;
+ seg->dto_urb->sg = NULL;
+ seg->dto_urb->num_sgs = 0;
+ } else {
+ /* do buffer or SG processing. */
+ seg->dto_urb->transfer_flags &=
+ ~URB_NO_TRANSFER_DMA_MAP;
+ /* this should always be 0 before a resubmit. */
+ seg->dto_urb->num_mapped_sgs = 0;
+
+ if (xfer->urb->transfer_buffer) {
+ seg->dto_urb->transfer_buffer =
+ xfer->urb->transfer_buffer +
+ buf_itr;
+ seg->dto_urb->sg = NULL;
+ seg->dto_urb->num_sgs = 0;
+ } else {
+ /* allocate an SG list to store seg_size
+ bytes and copy the subset of the
+ xfer->urb->sg that matches the
+ buffer subset we are about to read.
+ */
+ seg->dto_urb->sg =
+ wa_xfer_create_subset_sg(
+ xfer->urb->sg,
+ buf_itr, buf_itr_size,
+ &(seg->dto_urb->num_sgs));
+
+ if (!(seg->dto_urb->sg)) {
+ seg->dto_urb->num_sgs = 0;
+ goto error_sg_alloc;
+ }
+
+ seg->dto_urb->transfer_buffer = NULL;
+ }
+ }
seg->dto_urb->transfer_buffer_length = buf_itr_size;
}
seg->status = WA_SEG_READY;
@@ -690,6 +803,8 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
}
return 0;
+error_sg_alloc:
+ kfree(seg->dto_urb);
error_dto_alloc:
kfree(xfer->seg[cnt]);
cnt--;
@@ -1026,7 +1141,8 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,
unsigned long my_flags;
unsigned cant_sleep = irqs_disabled() | in_atomic();
- if (urb->transfer_buffer == NULL
+ if ((urb->transfer_buffer == NULL)
+ && (urb->sg == NULL)
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
&& urb->transfer_buffer_length != 0) {
dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb);
@@ -1261,7 +1377,7 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)
seg = xfer->seg[seg_idx];
rpipe = xfer->ep->hcpriv;
usb_status = xfer_result->bTransferStatus;
- dev_dbg(dev, "xfer %p#%u: bTransferStatus 0x%02x (seg %u)\n",
+ dev_dbg(dev, "xfer %p#%u: bTransferStatus 0x%02x (seg status %u)\n",
xfer, seg_idx, usb_status, seg->status);
if (seg->status == WA_SEG_ABORTED
|| seg->status == WA_SEG_ERROR) /* already handled */
@@ -1276,8 +1392,8 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)
}
if (usb_status & 0x80) {
seg->result = wa_xfer_status_to_errno(usb_status);
- dev_err(dev, "DTI: xfer %p#%u failed (0x%02x)\n",
- xfer, seg->index, usb_status);
+ dev_err(dev, "DTI: xfer %p#:%08X:%u failed (0x%02x)\n",
+ xfer, xfer->id, seg->index, usb_status);
goto error_complete;
}
/* FIXME: we ignore warnings, tally them for stats */
@@ -1286,18 +1402,47 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)
if (xfer->is_inbound) { /* IN data phase: read to buffer */
seg->status = WA_SEG_DTI_PENDING;
BUG_ON(wa->buf_in_urb->status == -EINPROGRESS);
+ /* this should always be 0 before a resubmit. */
+ wa->buf_in_urb->num_mapped_sgs = 0;
+
if (xfer->is_dma) {
wa->buf_in_urb->transfer_dma =
xfer->urb->transfer_dma
- + seg_idx * xfer->seg_size;
+ + (seg_idx * xfer->seg_size);
wa->buf_in_urb->transfer_flags
|= URB_NO_TRANSFER_DMA_MAP;
+ wa->buf_in_urb->transfer_buffer = NULL;
+ wa->buf_in_urb->sg = NULL;
+ wa->buf_in_urb->num_sgs = 0;
} else {
- wa->buf_in_urb->transfer_buffer =
- xfer->urb->transfer_buffer
- + seg_idx * xfer->seg_size;
+ /* do buffer or SG processing. */
wa->buf_in_urb->transfer_flags
&= ~URB_NO_TRANSFER_DMA_MAP;
+
+ if (xfer->urb->transfer_buffer) {
+ wa->buf_in_urb->transfer_buffer =
+ xfer->urb->transfer_buffer
+ + (seg_idx * xfer->seg_size);
+ wa->buf_in_urb->sg = NULL;
+ wa->buf_in_urb->num_sgs = 0;
+ } else {
+ /* allocate an SG list to store seg_size bytes
+ and copy the subset of the xfer->urb->sg
+ that matches the buffer subset we are
+ about to read. */
+ wa->buf_in_urb->sg = wa_xfer_create_subset_sg(
+ xfer->urb->sg,
+ seg_idx * xfer->seg_size,
+ le32_to_cpu(
+ xfer_result->dwTransferLength),
+ &(wa->buf_in_urb->num_sgs));
+
+ if (!(wa->buf_in_urb->sg)) {
+ wa->buf_in_urb->num_sgs = 0;
+ goto error_sg_alloc;
+ }
+ wa->buf_in_urb->transfer_buffer = NULL;
+ }
}
wa->buf_in_urb->transfer_buffer_length =
le32_to_cpu(xfer_result->dwTransferLength);
@@ -1330,6 +1475,8 @@ error_submit_buf_in:
dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",
xfer, seg_idx, result);
seg->result = result;
+ kfree(wa->buf_in_urb->sg);
+error_sg_alloc:
error_complete:
seg->status = WA_SEG_ERROR;
xfer->segs_done++;
@@ -1381,6 +1528,10 @@ static void wa_buf_in_cb(struct urb *urb)
unsigned long flags;
u8 done = 0;
+ /* free the sg if it was used. */
+ kfree(urb->sg);
+ urb->sg = NULL;
+
switch (urb->status) {
case 0:
spin_lock_irqsave(&xfer->lock, flags);
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
index 0faca16df765..742c607d1fa3 100644
--- a/drivers/usb/wusbcore/wusbhc.c
+++ b/drivers/usb/wusbcore/wusbhc.c
@@ -75,12 +75,11 @@ static ssize_t wusb_trust_timeout_store(struct device *dev,
result = -EINVAL;
goto out;
}
- /* FIXME: maybe we should check for range validity? */
- wusbhc->trust_timeout = trust_timeout;
+ wusbhc->trust_timeout = min_t(unsigned, trust_timeout, 500);
cancel_delayed_work(&wusbhc->keep_alive_timer);
flush_workqueue(wusbd);
queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
- (trust_timeout * CONFIG_HZ)/1000/2);
+ msecs_to_jiffies(wusbhc->trust_timeout / 2));
out:
return result < 0 ? result : size;
}
@@ -176,11 +175,72 @@ static ssize_t wusb_phy_rate_store(struct device *dev,
}
static DEVICE_ATTR(wusb_phy_rate, 0644, wusb_phy_rate_show, wusb_phy_rate_store);
+static ssize_t wusb_dnts_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+ return sprintf(buf, "num slots: %d\ninterval: %dms\n",
+ wusbhc->dnts_num_slots, wusbhc->dnts_interval);
+}
+
+static ssize_t wusb_dnts_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ uint8_t num_slots, interval;
+ ssize_t result;
+
+ result = sscanf(buf, "%hhu %hhu", &num_slots, &interval);
+
+ if (result != 2)
+ return -EINVAL;
+
+ wusbhc->dnts_num_slots = num_slots;
+ wusbhc->dnts_interval = interval;
+
+ return size;
+}
+static DEVICE_ATTR(wusb_dnts, 0644, wusb_dnts_show, wusb_dnts_store);
+
+static ssize_t wusb_retry_count_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+ return sprintf(buf, "%d\n", wusbhc->retry_count);
+}
+
+static ssize_t wusb_retry_count_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+ uint8_t retry_count;
+ ssize_t result;
+
+ result = sscanf(buf, "%hhu", &retry_count);
+
+ if (result != 1)
+ return -EINVAL;
+
+ wusbhc->retry_count = max_t(uint8_t, retry_count, WUSB_RETRY_COUNT_MAX);
+
+ return size;
+}
+static DEVICE_ATTR(wusb_retry_count, 0644, wusb_retry_count_show,
+ wusb_retry_count_store);
+
/* Group all the WUSBHC attributes */
static struct attribute *wusbhc_attrs[] = {
&dev_attr_wusb_trust_timeout.attr,
&dev_attr_wusb_chid.attr,
&dev_attr_wusb_phy_rate.attr,
+ &dev_attr_wusb_dnts.attr,
+ &dev_attr_wusb_retry_count.attr,
NULL,
};
@@ -206,8 +266,12 @@ int wusbhc_create(struct wusbhc *wusbhc)
{
int result = 0;
+ /* set defaults. These can be overwritten using sysfs attributes. */
wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;
wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1;
+ wusbhc->dnts_num_slots = 4;
+ wusbhc->dnts_interval = 2;
+ wusbhc->retry_count = WUSB_RETRY_COUNT_INFINITE;
mutex_init(&wusbhc->mutex);
result = wusbhc_mmcie_create(wusbhc);
@@ -261,13 +325,7 @@ int wusbhc_b_create(struct wusbhc *wusbhc)
goto error_create_attr_group;
}
- result = wusbhc_pal_register(wusbhc);
- if (result < 0)
- goto error_pal_register;
return 0;
-
-error_pal_register:
- sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
error_create_attr_group:
return result;
}
@@ -393,7 +451,8 @@ EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
*/
void wusbhc_reset_all(struct wusbhc *wusbhc)
{
- uwb_rc_reset_all(wusbhc->uwb_rc);
+ if (wusbhc->uwb_rc)
+ uwb_rc_reset_all(wusbhc->uwb_rc);
}
EXPORT_SYMBOL_GPL(wusbhc_reset_all);
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h
index 3a2d09162e70..711b1952b114 100644
--- a/drivers/usb/wusbcore/wusbhc.h
+++ b/drivers/usb/wusbcore/wusbhc.h
@@ -69,6 +69,8 @@
* zone 0.
*/
#define WUSB_CHANNEL_STOP_DELAY_MS 8
+#define WUSB_RETRY_COUNT_MAX 15
+#define WUSB_RETRY_COUNT_INFINITE 0
/**
* Wireless USB device
@@ -252,6 +254,9 @@ struct wusbhc {
unsigned trust_timeout; /* in jiffies */
struct wusb_ckhdid chid;
uint8_t phy_rate;
+ uint8_t dnts_num_slots;
+ uint8_t dnts_interval;
+ uint8_t retry_count;
struct wuie_host_info *wuie_host_info;
struct mutex mutex; /* locks everything else */
@@ -399,8 +404,6 @@ extern void wusbhc_rh_destroy(struct wusbhc *);
extern int wusbhc_rh_status_data(struct usb_hcd *, char *);
extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16);
-extern int wusbhc_rh_suspend(struct usb_hcd *);
-extern int wusbhc_rh_resume(struct usb_hcd *);
extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned);
/* MMC handling */