diff options
Diffstat (limited to 'drivers/net/usb/rndis_host.c')
-rw-r--r-- | drivers/net/usb/rndis_host.c | 41 |
1 files changed, 33 insertions, 8 deletions
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index dd8a4adf48ca..255d6a424a6b 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, | |||
104 | int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) | 104 | int 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 | ¬ification, 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); |
@@ -573,7 +582,18 @@ EXPORT_SYMBOL_GPL(rndis_tx_fixup); | |||
573 | 582 | ||
574 | static const struct driver_info rndis_info = { | 583 | static const struct driver_info rndis_info = { |
575 | .description = "RNDIS device", | 584 | .description = "RNDIS device", |
576 | .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, | 585 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, |
586 | .bind = rndis_bind, | ||
587 | .unbind = rndis_unbind, | ||
588 | .status = rndis_status, | ||
589 | .rx_fixup = rndis_rx_fixup, | ||
590 | .tx_fixup = rndis_tx_fixup, | ||
591 | }; | ||
592 | |||
593 | static const struct driver_info rndis_poll_status_info = { | ||
594 | .description = "RNDIS device (poll status before control)", | ||
595 | .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, | ||
596 | .data = RNDIS_DRIVER_DATA_POLL_STATUS, | ||
577 | .bind = rndis_bind, | 597 | .bind = rndis_bind, |
578 | .unbind = rndis_unbind, | 598 | .unbind = rndis_unbind, |
579 | .status = rndis_status, | 599 | .status = rndis_status, |
@@ -585,13 +605,18 @@ static const struct driver_info rndis_info = { | |||
585 | 605 | ||
586 | static const struct usb_device_id products [] = { | 606 | static 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), |