rndis_host: Poll status channel before control channel
authorBen Hutchings <ben@decadent.org.uk>
Sun, 16 May 2010 06:03:29 +0000 (23:03 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sun, 16 May 2010 06:03:29 +0000 (23:03 -0700)
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.

This is roughly based on a patch by John Carr <john.carr@unrouted.co.uk>
which is reported to be needed for use with some Windows Mobile devices
and which is currently applied by Mandriva.

Reported-by: Mark Glassberg <vzeeaxwl@myfairpoint.net>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Tested-by: Mark Glassberg <vzeeaxwl@myfairpoint.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/usb/rndis_host.c

index dd8a4adf48cadf3d1c85507dc9c71c9d9c316004..28d3ee175e7bbffe697e00f0019c15636eeb6050 100644 (file)
@@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg,
 int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
 {
        struct cdc_state        *info = (void *) &dev->data;
+       struct usb_cdc_notification notification;
        int                     master_ifnum;
        int                     retval;
+       int                     partial;
        unsigned                count;
        __le32                  rsp;
        u32                     xid = 0, msg_len, request_id;
@@ -133,13 +135,17 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
        if (unlikely(retval < 0 || xid == 0))
                return retval;
 
-       // FIXME Seems like some devices discard responses when
-       // we time out and cancel our "get response" requests...
-       // so, this is fragile.  Probably need to poll for status.
+       /* Some devices don't respond on the control channel until
+        * polled on the status channel, so do that first. */
+       retval = usb_interrupt_msg(
+               dev->udev,
+               usb_rcvintpipe(dev->udev, dev->status->desc.bEndpointAddress),
+               &notification, sizeof(notification), &partial,
+               RNDIS_CONTROL_TIMEOUT_MS);
+       if (unlikely(retval < 0))
+               return retval;
 
-       /* ignore status endpoint, just poll the control channel;
-        * the request probably completed immediately
-        */
+       /* Poll the control channel; the request probably completed immediately */
        rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
        for (count = 0; count < 10; count++) {
                memset(buf, 0, CONTROL_BUFFER_SIZE);