aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Hutchings <ben@decadent.org.uk>2011-04-13 17:48:55 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-13 17:48:55 -0400
commit4d42d417be75d750b82798922b6e775915e11bce (patch)
tree306b97e4cb6e82d5ecd7109c0b2561d256be67a8 /drivers
parent74ae2fd7d326750d973920c30d5269596724ca71 (diff)
rndis_host: Poll status before control channel where necessary
Some RNDIS devices don't respond on the control channel until polled on the status channel. In particular, this was reported to be the case for the 2Wire HomePortal 1000SW and for some Windows Mobile devices. This is roughly based on a patch by John Carr <john.carr@unrouted.co.uk> which is currently applied by Mandriva. Reported-by: Mark Glassberg <vzeeaxwl@myfairpoint.net> Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/usb/rndis_host.c39
1 files changed, 32 insertions, 7 deletions
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 5994a25c56ac..6d6c1da68a36 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg,
104int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) 104int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
105{ 105{
106 struct cdc_state *info = (void *) &dev->data; 106 struct cdc_state *info = (void *) &dev->data;
107 struct usb_cdc_notification notification;
107 int master_ifnum; 108 int master_ifnum;
108 int retval; 109 int retval;
110 int partial;
109 unsigned count; 111 unsigned count;
110 __le32 rsp; 112 __le32 rsp;
111 u32 xid = 0, msg_len, request_id; 113 u32 xid = 0, msg_len, request_id;
@@ -133,13 +135,20 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
133 if (unlikely(retval < 0 || xid == 0)) 135 if (unlikely(retval < 0 || xid == 0))
134 return retval; 136 return retval;
135 137
136 // FIXME Seems like some devices discard responses when 138 /* Some devices don't respond on the control channel until
137 // we time out and cancel our "get response" requests... 139 * polled on the status channel, so do that first. */
138 // so, this is fragile. Probably need to poll for status. 140 if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) {
141 retval = usb_interrupt_msg(
142 dev->udev,
143 usb_rcvintpipe(dev->udev,
144 dev->status->desc.bEndpointAddress),
145 &notification, sizeof(notification), &partial,
146 RNDIS_CONTROL_TIMEOUT_MS);
147 if (unlikely(retval < 0))
148 return retval;
149 }
139 150
140 /* ignore status endpoint, just poll the control channel; 151 /* Poll the control channel; the request probably completed immediately */
141 * the request probably completed immediately
142 */
143 rsp = buf->msg_type | RNDIS_MSG_COMPLETION; 152 rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
144 for (count = 0; count < 10; count++) { 153 for (count = 0; count < 10; count++) {
145 memset(buf, 0, CONTROL_BUFFER_SIZE); 154 memset(buf, 0, CONTROL_BUFFER_SIZE);
@@ -581,17 +590,33 @@ static const struct driver_info rndis_info = {
581 .tx_fixup = rndis_tx_fixup, 590 .tx_fixup = rndis_tx_fixup,
582}; 591};
583 592
593static const struct driver_info rndis_poll_status_info = {
594 .description = "RNDIS device (poll status before control)",
595 .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT,
596 .data = RNDIS_DRIVER_DATA_POLL_STATUS,
597 .bind = rndis_bind,
598 .unbind = rndis_unbind,
599 .status = rndis_status,
600 .rx_fixup = rndis_rx_fixup,
601 .tx_fixup = rndis_tx_fixup,
602};
603
584/*-------------------------------------------------------------------------*/ 604/*-------------------------------------------------------------------------*/
585 605
586static const struct usb_device_id products [] = { 606static const struct usb_device_id products [] = {
587{ 607{
608 /* 2Wire HomePortal 1000SW */
609 USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042,
610 USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
611 .driver_info = (unsigned long) &rndis_poll_status_info,
612}, {
588 /* RNDIS is MSFT's un-official variant of CDC ACM */ 613 /* RNDIS is MSFT's un-official variant of CDC ACM */
589 USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), 614 USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
590 .driver_info = (unsigned long) &rndis_info, 615 .driver_info = (unsigned long) &rndis_info,
591}, { 616}, {
592 /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ 617 /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
593 USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), 618 USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
594 .driver_info = (unsigned long) &rndis_info, 619 .driver_info = (unsigned long) &rndis_poll_status_info,
595}, { 620}, {
596 /* RNDIS for tethering */ 621 /* RNDIS for tethering */
597 USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), 622 USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3),