diff options
Diffstat (limited to 'drivers/usb/net/cdc_ether.c')
-rw-r--r-- | drivers/usb/net/cdc_ether.c | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 44a91547146e..e5cdafa258dd 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * CDC Ethernet based networking peripherals | 2 | * CDC Ethernet based networking peripherals |
3 | * Copyright (C) 2003-2005 by David Brownell | 3 | * Copyright (C) 2003-2005 by David Brownell |
4 | * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -35,6 +36,29 @@ | |||
35 | #include "usbnet.h" | 36 | #include "usbnet.h" |
36 | 37 | ||
37 | 38 | ||
39 | #if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) | ||
40 | |||
41 | static int is_rndis(struct usb_interface_descriptor *desc) | ||
42 | { | ||
43 | return desc->bInterfaceClass == USB_CLASS_COMM | ||
44 | && desc->bInterfaceSubClass == 2 | ||
45 | && desc->bInterfaceProtocol == 0xff; | ||
46 | } | ||
47 | |||
48 | static int is_activesync(struct usb_interface_descriptor *desc) | ||
49 | { | ||
50 | return desc->bInterfaceClass == USB_CLASS_MISC | ||
51 | && desc->bInterfaceSubClass == 1 | ||
52 | && desc->bInterfaceProtocol == 1; | ||
53 | } | ||
54 | |||
55 | #else | ||
56 | |||
57 | #define is_rndis(desc) 0 | ||
58 | #define is_activesync(desc) 0 | ||
59 | |||
60 | #endif | ||
61 | |||
38 | /* | 62 | /* |
39 | * probes control interface, claims data interface, collects the bulk | 63 | * probes control interface, claims data interface, collects the bulk |
40 | * endpoints, activates data interface (if needed), maybe sets MTU. | 64 | * endpoints, activates data interface (if needed), maybe sets MTU. |
@@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) | |||
71 | /* this assumes that if there's a non-RNDIS vendor variant | 95 | /* this assumes that if there's a non-RNDIS vendor variant |
72 | * of cdc-acm, it'll fail RNDIS requests cleanly. | 96 | * of cdc-acm, it'll fail RNDIS requests cleanly. |
73 | */ | 97 | */ |
74 | rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); | 98 | rndis = is_rndis(&intf->cur_altsetting->desc) |
99 | || is_activesync(&intf->cur_altsetting->desc); | ||
75 | 100 | ||
76 | memset(info, 0, sizeof *info); | 101 | memset(info, 0, sizeof *info); |
77 | info->control = intf; | 102 | info->control = intf; |
@@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) | |||
99 | goto bad_desc; | 124 | goto bad_desc; |
100 | } | 125 | } |
101 | break; | 126 | break; |
127 | case USB_CDC_ACM_TYPE: | ||
128 | /* paranoia: disambiguate a "real" vendor-specific | ||
129 | * modem interface from an RNDIS non-modem. | ||
130 | */ | ||
131 | if (rndis) { | ||
132 | struct usb_cdc_acm_descriptor *d; | ||
133 | |||
134 | d = (void *) buf; | ||
135 | if (d->bmCapabilities) { | ||
136 | dev_dbg(&intf->dev, | ||
137 | "ACM capabilities %02x, " | ||
138 | "not really RNDIS?\n", | ||
139 | d->bmCapabilities); | ||
140 | goto bad_desc; | ||
141 | } | ||
142 | } | ||
143 | break; | ||
102 | case USB_CDC_UNION_TYPE: | 144 | case USB_CDC_UNION_TYPE: |
103 | if (info->u) { | 145 | if (info->u) { |
104 | dev_dbg(&intf->dev, "extra CDC union\n"); | 146 | dev_dbg(&intf->dev, "extra CDC union\n"); |
@@ -171,7 +213,21 @@ next_desc: | |||
171 | buf += buf [0]; | 213 | buf += buf [0]; |
172 | } | 214 | } |
173 | 215 | ||
174 | if (!info->header || !info->u || (!rndis && !info->ether)) { | 216 | /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors, |
217 | * so we'll hard-wire the interfaces and not check for descriptors. | ||
218 | */ | ||
219 | if (is_activesync(&intf->cur_altsetting->desc) && !info->u) { | ||
220 | info->control = usb_ifnum_to_if(dev->udev, 0); | ||
221 | info->data = usb_ifnum_to_if(dev->udev, 1); | ||
222 | if (!info->control || !info->data) { | ||
223 | dev_dbg(&intf->dev, | ||
224 | "activesync: master #0/%p slave #1/%p\n", | ||
225 | info->control, | ||
226 | info->data); | ||
227 | goto bad_desc; | ||
228 | } | ||
229 | |||
230 | } else if (!info->header || !info->u || (!rndis && !info->ether)) { | ||
175 | dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", | 231 | dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", |
176 | info->header ? "" : "header ", | 232 | info->header ? "" : "header ", |
177 | info->u ? "" : "union ", | 233 | info->u ? "" : "union ", |