Commit 7e99eeddb35cdaafb820676a57517b5e58685e4c
Committed by
Jeff Garzik
1 parent
7a2f53ee0b
Exists in
master
and in
7 other branches
rndis_host: support WM6 devices as modems
This patch allows Windows Mobile 6 devices to be used for tethering -- that is, used as modems. It was requested by AdamW in kernel bugzilla: http://bugzilla.kernel.org/show_bug.cgi?id=11119 and Mandriva kernel-discuss list. It is tested and confirmed to work by Peterl: http://forum.eeeuser.com/viewtopic.php?pid=323543#p323543 This patch is based on the patch in the above kernel bugzilla, which is from the usb-rndis-lite tree. [ dbrownell@users.sourceforge.net: misc fixes ] Signed-off-by: Thomas Backlund <tmb@mandriva.org> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Showing 2 changed files with 14 additions and 1 deletions Inline Diff
drivers/net/usb/cdc_ether.c
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 | * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) |
5 | * | 5 | * |
6 | * 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 |
7 | * 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 |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | // #define DEBUG // error path messages, extra info | 21 | // #define DEBUG // error path messages, extra info |
22 | // #define VERBOSE // more; success messages | 22 | // #define VERBOSE // more; success messages |
23 | 23 | ||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/netdevice.h> | 26 | #include <linux/netdevice.h> |
27 | #include <linux/etherdevice.h> | 27 | #include <linux/etherdevice.h> |
28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
29 | #include <linux/ethtool.h> | 29 | #include <linux/ethtool.h> |
30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
31 | #include <linux/mii.h> | 31 | #include <linux/mii.h> |
32 | #include <linux/usb.h> | 32 | #include <linux/usb.h> |
33 | #include <linux/usb/cdc.h> | 33 | #include <linux/usb/cdc.h> |
34 | #include <linux/usb/usbnet.h> | 34 | #include <linux/usb/usbnet.h> |
35 | 35 | ||
36 | 36 | ||
37 | #if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) | 37 | #if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE) |
38 | 38 | ||
39 | static int is_rndis(struct usb_interface_descriptor *desc) | 39 | static int is_rndis(struct usb_interface_descriptor *desc) |
40 | { | 40 | { |
41 | return desc->bInterfaceClass == USB_CLASS_COMM | 41 | return desc->bInterfaceClass == USB_CLASS_COMM |
42 | && desc->bInterfaceSubClass == 2 | 42 | && desc->bInterfaceSubClass == 2 |
43 | && desc->bInterfaceProtocol == 0xff; | 43 | && desc->bInterfaceProtocol == 0xff; |
44 | } | 44 | } |
45 | 45 | ||
46 | static int is_activesync(struct usb_interface_descriptor *desc) | 46 | static int is_activesync(struct usb_interface_descriptor *desc) |
47 | { | 47 | { |
48 | return desc->bInterfaceClass == USB_CLASS_MISC | 48 | return desc->bInterfaceClass == USB_CLASS_MISC |
49 | && desc->bInterfaceSubClass == 1 | 49 | && desc->bInterfaceSubClass == 1 |
50 | && desc->bInterfaceProtocol == 1; | 50 | && desc->bInterfaceProtocol == 1; |
51 | } | 51 | } |
52 | 52 | ||
53 | static int is_wireless_rndis(struct usb_interface_descriptor *desc) | ||
54 | { | ||
55 | return desc->bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER | ||
56 | && desc->bInterfaceSubClass == 1 | ||
57 | && desc->bInterfaceProtocol == 3; | ||
58 | } | ||
59 | |||
53 | #else | 60 | #else |
54 | 61 | ||
55 | #define is_rndis(desc) 0 | 62 | #define is_rndis(desc) 0 |
56 | #define is_activesync(desc) 0 | 63 | #define is_activesync(desc) 0 |
64 | #define is_wireless_rndis(desc) 0 | ||
57 | 65 | ||
58 | #endif | 66 | #endif |
59 | 67 | ||
60 | /* | 68 | /* |
61 | * probes control interface, claims data interface, collects the bulk | 69 | * probes control interface, claims data interface, collects the bulk |
62 | * endpoints, activates data interface (if needed), maybe sets MTU. | 70 | * endpoints, activates data interface (if needed), maybe sets MTU. |
63 | * all pure cdc, except for certain firmware workarounds, and knowing | 71 | * all pure cdc, except for certain firmware workarounds, and knowing |
64 | * that rndis uses one different rule. | 72 | * that rndis uses one different rule. |
65 | */ | 73 | */ |
66 | int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) | 74 | int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) |
67 | { | 75 | { |
68 | u8 *buf = intf->cur_altsetting->extra; | 76 | u8 *buf = intf->cur_altsetting->extra; |
69 | int len = intf->cur_altsetting->extralen; | 77 | int len = intf->cur_altsetting->extralen; |
70 | struct usb_interface_descriptor *d; | 78 | struct usb_interface_descriptor *d; |
71 | struct cdc_state *info = (void *) &dev->data; | 79 | struct cdc_state *info = (void *) &dev->data; |
72 | int status; | 80 | int status; |
73 | int rndis; | 81 | int rndis; |
74 | struct usb_driver *driver = driver_of(intf); | 82 | struct usb_driver *driver = driver_of(intf); |
75 | 83 | ||
76 | if (sizeof dev->data < sizeof *info) | 84 | if (sizeof dev->data < sizeof *info) |
77 | return -EDOM; | 85 | return -EDOM; |
78 | 86 | ||
79 | /* expect strict spec conformance for the descriptors, but | 87 | /* expect strict spec conformance for the descriptors, but |
80 | * cope with firmware which stores them in the wrong place | 88 | * cope with firmware which stores them in the wrong place |
81 | */ | 89 | */ |
82 | if (len == 0 && dev->udev->actconfig->extralen) { | 90 | if (len == 0 && dev->udev->actconfig->extralen) { |
83 | /* Motorola SB4100 (and others: Brad Hards says it's | 91 | /* Motorola SB4100 (and others: Brad Hards says it's |
84 | * from a Broadcom design) put CDC descriptors here | 92 | * from a Broadcom design) put CDC descriptors here |
85 | */ | 93 | */ |
86 | buf = dev->udev->actconfig->extra; | 94 | buf = dev->udev->actconfig->extra; |
87 | len = dev->udev->actconfig->extralen; | 95 | len = dev->udev->actconfig->extralen; |
88 | if (len) | 96 | if (len) |
89 | dev_dbg(&intf->dev, | 97 | dev_dbg(&intf->dev, |
90 | "CDC descriptors on config\n"); | 98 | "CDC descriptors on config\n"); |
91 | } | 99 | } |
92 | 100 | ||
93 | /* Maybe CDC descriptors are after the endpoint? This bug has | 101 | /* Maybe CDC descriptors are after the endpoint? This bug has |
94 | * been seen on some 2Wire Inc RNDIS-ish products. | 102 | * been seen on some 2Wire Inc RNDIS-ish products. |
95 | */ | 103 | */ |
96 | if (len == 0) { | 104 | if (len == 0) { |
97 | struct usb_host_endpoint *hep; | 105 | struct usb_host_endpoint *hep; |
98 | 106 | ||
99 | hep = intf->cur_altsetting->endpoint; | 107 | hep = intf->cur_altsetting->endpoint; |
100 | if (hep) { | 108 | if (hep) { |
101 | buf = hep->extra; | 109 | buf = hep->extra; |
102 | len = hep->extralen; | 110 | len = hep->extralen; |
103 | } | 111 | } |
104 | if (len) | 112 | if (len) |
105 | dev_dbg(&intf->dev, | 113 | dev_dbg(&intf->dev, |
106 | "CDC descriptors on endpoint\n"); | 114 | "CDC descriptors on endpoint\n"); |
107 | } | 115 | } |
108 | 116 | ||
109 | /* this assumes that if there's a non-RNDIS vendor variant | 117 | /* this assumes that if there's a non-RNDIS vendor variant |
110 | * of cdc-acm, it'll fail RNDIS requests cleanly. | 118 | * of cdc-acm, it'll fail RNDIS requests cleanly. |
111 | */ | 119 | */ |
112 | rndis = is_rndis(&intf->cur_altsetting->desc) | 120 | rndis = is_rndis(&intf->cur_altsetting->desc) |
113 | || is_activesync(&intf->cur_altsetting->desc); | 121 | || is_activesync(&intf->cur_altsetting->desc) |
122 | || is_wireless_rndis(&intf->cur_altsetting->desc); | ||
114 | 123 | ||
115 | memset(info, 0, sizeof *info); | 124 | memset(info, 0, sizeof *info); |
116 | info->control = intf; | 125 | info->control = intf; |
117 | while (len > 3) { | 126 | while (len > 3) { |
118 | if (buf [1] != USB_DT_CS_INTERFACE) | 127 | if (buf [1] != USB_DT_CS_INTERFACE) |
119 | goto next_desc; | 128 | goto next_desc; |
120 | 129 | ||
121 | /* use bDescriptorSubType to identify the CDC descriptors. | 130 | /* use bDescriptorSubType to identify the CDC descriptors. |
122 | * We expect devices with CDC header and union descriptors. | 131 | * We expect devices with CDC header and union descriptors. |
123 | * For CDC Ethernet we need the ethernet descriptor. | 132 | * For CDC Ethernet we need the ethernet descriptor. |
124 | * For RNDIS, ignore two (pointless) CDC modem descriptors | 133 | * For RNDIS, ignore two (pointless) CDC modem descriptors |
125 | * in favor of a complicated OID-based RPC scheme doing what | 134 | * in favor of a complicated OID-based RPC scheme doing what |
126 | * CDC Ethernet achieves with a simple descriptor. | 135 | * CDC Ethernet achieves with a simple descriptor. |
127 | */ | 136 | */ |
128 | switch (buf [2]) { | 137 | switch (buf [2]) { |
129 | case USB_CDC_HEADER_TYPE: | 138 | case USB_CDC_HEADER_TYPE: |
130 | if (info->header) { | 139 | if (info->header) { |
131 | dev_dbg(&intf->dev, "extra CDC header\n"); | 140 | dev_dbg(&intf->dev, "extra CDC header\n"); |
132 | goto bad_desc; | 141 | goto bad_desc; |
133 | } | 142 | } |
134 | info->header = (void *) buf; | 143 | info->header = (void *) buf; |
135 | if (info->header->bLength != sizeof *info->header) { | 144 | if (info->header->bLength != sizeof *info->header) { |
136 | dev_dbg(&intf->dev, "CDC header len %u\n", | 145 | dev_dbg(&intf->dev, "CDC header len %u\n", |
137 | info->header->bLength); | 146 | info->header->bLength); |
138 | goto bad_desc; | 147 | goto bad_desc; |
139 | } | 148 | } |
140 | break; | 149 | break; |
141 | case USB_CDC_ACM_TYPE: | 150 | case USB_CDC_ACM_TYPE: |
142 | /* paranoia: disambiguate a "real" vendor-specific | 151 | /* paranoia: disambiguate a "real" vendor-specific |
143 | * modem interface from an RNDIS non-modem. | 152 | * modem interface from an RNDIS non-modem. |
144 | */ | 153 | */ |
145 | if (rndis) { | 154 | if (rndis) { |
146 | struct usb_cdc_acm_descriptor *acm; | 155 | struct usb_cdc_acm_descriptor *acm; |
147 | 156 | ||
148 | acm = (void *) buf; | 157 | acm = (void *) buf; |
149 | if (acm->bmCapabilities) { | 158 | if (acm->bmCapabilities) { |
150 | dev_dbg(&intf->dev, | 159 | dev_dbg(&intf->dev, |
151 | "ACM capabilities %02x, " | 160 | "ACM capabilities %02x, " |
152 | "not really RNDIS?\n", | 161 | "not really RNDIS?\n", |
153 | acm->bmCapabilities); | 162 | acm->bmCapabilities); |
154 | goto bad_desc; | 163 | goto bad_desc; |
155 | } | 164 | } |
156 | } | 165 | } |
157 | break; | 166 | break; |
158 | case USB_CDC_UNION_TYPE: | 167 | case USB_CDC_UNION_TYPE: |
159 | if (info->u) { | 168 | if (info->u) { |
160 | dev_dbg(&intf->dev, "extra CDC union\n"); | 169 | dev_dbg(&intf->dev, "extra CDC union\n"); |
161 | goto bad_desc; | 170 | goto bad_desc; |
162 | } | 171 | } |
163 | info->u = (void *) buf; | 172 | info->u = (void *) buf; |
164 | if (info->u->bLength != sizeof *info->u) { | 173 | if (info->u->bLength != sizeof *info->u) { |
165 | dev_dbg(&intf->dev, "CDC union len %u\n", | 174 | dev_dbg(&intf->dev, "CDC union len %u\n", |
166 | info->u->bLength); | 175 | info->u->bLength); |
167 | goto bad_desc; | 176 | goto bad_desc; |
168 | } | 177 | } |
169 | 178 | ||
170 | /* we need a master/control interface (what we're | 179 | /* we need a master/control interface (what we're |
171 | * probed with) and a slave/data interface; union | 180 | * probed with) and a slave/data interface; union |
172 | * descriptors sort this all out. | 181 | * descriptors sort this all out. |
173 | */ | 182 | */ |
174 | info->control = usb_ifnum_to_if(dev->udev, | 183 | info->control = usb_ifnum_to_if(dev->udev, |
175 | info->u->bMasterInterface0); | 184 | info->u->bMasterInterface0); |
176 | info->data = usb_ifnum_to_if(dev->udev, | 185 | info->data = usb_ifnum_to_if(dev->udev, |
177 | info->u->bSlaveInterface0); | 186 | info->u->bSlaveInterface0); |
178 | if (!info->control || !info->data) { | 187 | if (!info->control || !info->data) { |
179 | dev_dbg(&intf->dev, | 188 | dev_dbg(&intf->dev, |
180 | "master #%u/%p slave #%u/%p\n", | 189 | "master #%u/%p slave #%u/%p\n", |
181 | info->u->bMasterInterface0, | 190 | info->u->bMasterInterface0, |
182 | info->control, | 191 | info->control, |
183 | info->u->bSlaveInterface0, | 192 | info->u->bSlaveInterface0, |
184 | info->data); | 193 | info->data); |
185 | goto bad_desc; | 194 | goto bad_desc; |
186 | } | 195 | } |
187 | if (info->control != intf) { | 196 | if (info->control != intf) { |
188 | dev_dbg(&intf->dev, "bogus CDC Union\n"); | 197 | dev_dbg(&intf->dev, "bogus CDC Union\n"); |
189 | /* Ambit USB Cable Modem (and maybe others) | 198 | /* Ambit USB Cable Modem (and maybe others) |
190 | * interchanges master and slave interface. | 199 | * interchanges master and slave interface. |
191 | */ | 200 | */ |
192 | if (info->data == intf) { | 201 | if (info->data == intf) { |
193 | info->data = info->control; | 202 | info->data = info->control; |
194 | info->control = intf; | 203 | info->control = intf; |
195 | } else | 204 | } else |
196 | goto bad_desc; | 205 | goto bad_desc; |
197 | } | 206 | } |
198 | 207 | ||
199 | /* a data interface altsetting does the real i/o */ | 208 | /* a data interface altsetting does the real i/o */ |
200 | d = &info->data->cur_altsetting->desc; | 209 | d = &info->data->cur_altsetting->desc; |
201 | if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { | 210 | if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { |
202 | dev_dbg(&intf->dev, "slave class %u\n", | 211 | dev_dbg(&intf->dev, "slave class %u\n", |
203 | d->bInterfaceClass); | 212 | d->bInterfaceClass); |
204 | goto bad_desc; | 213 | goto bad_desc; |
205 | } | 214 | } |
206 | break; | 215 | break; |
207 | case USB_CDC_ETHERNET_TYPE: | 216 | case USB_CDC_ETHERNET_TYPE: |
208 | if (info->ether) { | 217 | if (info->ether) { |
209 | dev_dbg(&intf->dev, "extra CDC ether\n"); | 218 | dev_dbg(&intf->dev, "extra CDC ether\n"); |
210 | goto bad_desc; | 219 | goto bad_desc; |
211 | } | 220 | } |
212 | info->ether = (void *) buf; | 221 | info->ether = (void *) buf; |
213 | if (info->ether->bLength != sizeof *info->ether) { | 222 | if (info->ether->bLength != sizeof *info->ether) { |
214 | dev_dbg(&intf->dev, "CDC ether len %u\n", | 223 | dev_dbg(&intf->dev, "CDC ether len %u\n", |
215 | info->ether->bLength); | 224 | info->ether->bLength); |
216 | goto bad_desc; | 225 | goto bad_desc; |
217 | } | 226 | } |
218 | dev->hard_mtu = le16_to_cpu( | 227 | dev->hard_mtu = le16_to_cpu( |
219 | info->ether->wMaxSegmentSize); | 228 | info->ether->wMaxSegmentSize); |
220 | /* because of Zaurus, we may be ignoring the host | 229 | /* because of Zaurus, we may be ignoring the host |
221 | * side link address we were given. | 230 | * side link address we were given. |
222 | */ | 231 | */ |
223 | break; | 232 | break; |
224 | } | 233 | } |
225 | next_desc: | 234 | next_desc: |
226 | len -= buf [0]; /* bLength */ | 235 | len -= buf [0]; /* bLength */ |
227 | buf += buf [0]; | 236 | buf += buf [0]; |
228 | } | 237 | } |
229 | 238 | ||
230 | /* Microsoft ActiveSync based and some regular RNDIS devices lack the | 239 | /* Microsoft ActiveSync based and some regular RNDIS devices lack the |
231 | * CDC descriptors, so we'll hard-wire the interfaces and not check | 240 | * CDC descriptors, so we'll hard-wire the interfaces and not check |
232 | * for descriptors. | 241 | * for descriptors. |
233 | */ | 242 | */ |
234 | if (rndis && !info->u) { | 243 | if (rndis && !info->u) { |
235 | info->control = usb_ifnum_to_if(dev->udev, 0); | 244 | info->control = usb_ifnum_to_if(dev->udev, 0); |
236 | info->data = usb_ifnum_to_if(dev->udev, 1); | 245 | info->data = usb_ifnum_to_if(dev->udev, 1); |
237 | if (!info->control || !info->data) { | 246 | if (!info->control || !info->data) { |
238 | dev_dbg(&intf->dev, | 247 | dev_dbg(&intf->dev, |
239 | "rndis: master #0/%p slave #1/%p\n", | 248 | "rndis: master #0/%p slave #1/%p\n", |
240 | info->control, | 249 | info->control, |
241 | info->data); | 250 | info->data); |
242 | goto bad_desc; | 251 | goto bad_desc; |
243 | } | 252 | } |
244 | 253 | ||
245 | } else if (!info->header || !info->u || (!rndis && !info->ether)) { | 254 | } else if (!info->header || !info->u || (!rndis && !info->ether)) { |
246 | dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", | 255 | dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n", |
247 | info->header ? "" : "header ", | 256 | info->header ? "" : "header ", |
248 | info->u ? "" : "union ", | 257 | info->u ? "" : "union ", |
249 | info->ether ? "" : "ether "); | 258 | info->ether ? "" : "ether "); |
250 | goto bad_desc; | 259 | goto bad_desc; |
251 | } | 260 | } |
252 | 261 | ||
253 | /* claim data interface and set it up ... with side effects. | 262 | /* claim data interface and set it up ... with side effects. |
254 | * network traffic can't flow until an altsetting is enabled. | 263 | * network traffic can't flow until an altsetting is enabled. |
255 | */ | 264 | */ |
256 | status = usb_driver_claim_interface(driver, info->data, dev); | 265 | status = usb_driver_claim_interface(driver, info->data, dev); |
257 | if (status < 0) | 266 | if (status < 0) |
258 | return status; | 267 | return status; |
259 | status = usbnet_get_endpoints(dev, info->data); | 268 | status = usbnet_get_endpoints(dev, info->data); |
260 | if (status < 0) { | 269 | if (status < 0) { |
261 | /* ensure immediate exit from usbnet_disconnect */ | 270 | /* ensure immediate exit from usbnet_disconnect */ |
262 | usb_set_intfdata(info->data, NULL); | 271 | usb_set_intfdata(info->data, NULL); |
263 | usb_driver_release_interface(driver, info->data); | 272 | usb_driver_release_interface(driver, info->data); |
264 | return status; | 273 | return status; |
265 | } | 274 | } |
266 | 275 | ||
267 | /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */ | 276 | /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */ |
268 | dev->status = NULL; | 277 | dev->status = NULL; |
269 | if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { | 278 | if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { |
270 | struct usb_endpoint_descriptor *desc; | 279 | struct usb_endpoint_descriptor *desc; |
271 | 280 | ||
272 | dev->status = &info->control->cur_altsetting->endpoint [0]; | 281 | dev->status = &info->control->cur_altsetting->endpoint [0]; |
273 | desc = &dev->status->desc; | 282 | desc = &dev->status->desc; |
274 | if (!usb_endpoint_is_int_in(desc) | 283 | if (!usb_endpoint_is_int_in(desc) |
275 | || (le16_to_cpu(desc->wMaxPacketSize) | 284 | || (le16_to_cpu(desc->wMaxPacketSize) |
276 | < sizeof(struct usb_cdc_notification)) | 285 | < sizeof(struct usb_cdc_notification)) |
277 | || !desc->bInterval) { | 286 | || !desc->bInterval) { |
278 | dev_dbg(&intf->dev, "bad notification endpoint\n"); | 287 | dev_dbg(&intf->dev, "bad notification endpoint\n"); |
279 | dev->status = NULL; | 288 | dev->status = NULL; |
280 | } | 289 | } |
281 | } | 290 | } |
282 | if (rndis && !dev->status) { | 291 | if (rndis && !dev->status) { |
283 | dev_dbg(&intf->dev, "missing RNDIS status endpoint\n"); | 292 | dev_dbg(&intf->dev, "missing RNDIS status endpoint\n"); |
284 | usb_set_intfdata(info->data, NULL); | 293 | usb_set_intfdata(info->data, NULL); |
285 | usb_driver_release_interface(driver, info->data); | 294 | usb_driver_release_interface(driver, info->data); |
286 | return -ENODEV; | 295 | return -ENODEV; |
287 | } | 296 | } |
288 | return 0; | 297 | return 0; |
289 | 298 | ||
290 | bad_desc: | 299 | bad_desc: |
291 | dev_info(&dev->udev->dev, "bad CDC descriptors\n"); | 300 | dev_info(&dev->udev->dev, "bad CDC descriptors\n"); |
292 | return -ENODEV; | 301 | return -ENODEV; |
293 | } | 302 | } |
294 | EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind); | 303 | EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind); |
295 | 304 | ||
296 | void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf) | 305 | void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf) |
297 | { | 306 | { |
298 | struct cdc_state *info = (void *) &dev->data; | 307 | struct cdc_state *info = (void *) &dev->data; |
299 | struct usb_driver *driver = driver_of(intf); | 308 | struct usb_driver *driver = driver_of(intf); |
300 | 309 | ||
301 | /* disconnect master --> disconnect slave */ | 310 | /* disconnect master --> disconnect slave */ |
302 | if (intf == info->control && info->data) { | 311 | if (intf == info->control && info->data) { |
303 | /* ensure immediate exit from usbnet_disconnect */ | 312 | /* ensure immediate exit from usbnet_disconnect */ |
304 | usb_set_intfdata(info->data, NULL); | 313 | usb_set_intfdata(info->data, NULL); |
305 | usb_driver_release_interface(driver, info->data); | 314 | usb_driver_release_interface(driver, info->data); |
306 | info->data = NULL; | 315 | info->data = NULL; |
307 | } | 316 | } |
308 | 317 | ||
309 | /* and vice versa (just in case) */ | 318 | /* and vice versa (just in case) */ |
310 | else if (intf == info->data && info->control) { | 319 | else if (intf == info->data && info->control) { |
311 | /* ensure immediate exit from usbnet_disconnect */ | 320 | /* ensure immediate exit from usbnet_disconnect */ |
312 | usb_set_intfdata(info->control, NULL); | 321 | usb_set_intfdata(info->control, NULL); |
313 | usb_driver_release_interface(driver, info->control); | 322 | usb_driver_release_interface(driver, info->control); |
314 | info->control = NULL; | 323 | info->control = NULL; |
315 | } | 324 | } |
316 | } | 325 | } |
317 | EXPORT_SYMBOL_GPL(usbnet_cdc_unbind); | 326 | EXPORT_SYMBOL_GPL(usbnet_cdc_unbind); |
318 | 327 | ||
319 | /*------------------------------------------------------------------------- | 328 | /*------------------------------------------------------------------------- |
320 | * | 329 | * |
321 | * Communications Device Class, Ethernet Control model | 330 | * Communications Device Class, Ethernet Control model |
322 | * | 331 | * |
323 | * Takes two interfaces. The DATA interface is inactive till an altsetting | 332 | * Takes two interfaces. The DATA interface is inactive till an altsetting |
324 | * is selected. Configuration data includes class descriptors. There's | 333 | * is selected. Configuration data includes class descriptors. There's |
325 | * an optional status endpoint on the control interface. | 334 | * an optional status endpoint on the control interface. |
326 | * | 335 | * |
327 | * This should interop with whatever the 2.4 "CDCEther.c" driver | 336 | * This should interop with whatever the 2.4 "CDCEther.c" driver |
328 | * (by Brad Hards) talked with, with more functionality. | 337 | * (by Brad Hards) talked with, with more functionality. |
329 | * | 338 | * |
330 | *-------------------------------------------------------------------------*/ | 339 | *-------------------------------------------------------------------------*/ |
331 | 340 | ||
332 | static void dumpspeed(struct usbnet *dev, __le32 *speeds) | 341 | static void dumpspeed(struct usbnet *dev, __le32 *speeds) |
333 | { | 342 | { |
334 | if (netif_msg_timer(dev)) | 343 | if (netif_msg_timer(dev)) |
335 | devinfo(dev, "link speeds: %u kbps up, %u kbps down", | 344 | devinfo(dev, "link speeds: %u kbps up, %u kbps down", |
336 | __le32_to_cpu(speeds[0]) / 1000, | 345 | __le32_to_cpu(speeds[0]) / 1000, |
337 | __le32_to_cpu(speeds[1]) / 1000); | 346 | __le32_to_cpu(speeds[1]) / 1000); |
338 | } | 347 | } |
339 | 348 | ||
340 | static void cdc_status(struct usbnet *dev, struct urb *urb) | 349 | static void cdc_status(struct usbnet *dev, struct urb *urb) |
341 | { | 350 | { |
342 | struct usb_cdc_notification *event; | 351 | struct usb_cdc_notification *event; |
343 | 352 | ||
344 | if (urb->actual_length < sizeof *event) | 353 | if (urb->actual_length < sizeof *event) |
345 | return; | 354 | return; |
346 | 355 | ||
347 | /* SPEED_CHANGE can get split into two 8-byte packets */ | 356 | /* SPEED_CHANGE can get split into two 8-byte packets */ |
348 | if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { | 357 | if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) { |
349 | dumpspeed(dev, (__le32 *) urb->transfer_buffer); | 358 | dumpspeed(dev, (__le32 *) urb->transfer_buffer); |
350 | return; | 359 | return; |
351 | } | 360 | } |
352 | 361 | ||
353 | event = urb->transfer_buffer; | 362 | event = urb->transfer_buffer; |
354 | switch (event->bNotificationType) { | 363 | switch (event->bNotificationType) { |
355 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: | 364 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: |
356 | if (netif_msg_timer(dev)) | 365 | if (netif_msg_timer(dev)) |
357 | devdbg(dev, "CDC: carrier %s", | 366 | devdbg(dev, "CDC: carrier %s", |
358 | event->wValue ? "on" : "off"); | 367 | event->wValue ? "on" : "off"); |
359 | if (event->wValue) | 368 | if (event->wValue) |
360 | netif_carrier_on(dev->net); | 369 | netif_carrier_on(dev->net); |
361 | else | 370 | else |
362 | netif_carrier_off(dev->net); | 371 | netif_carrier_off(dev->net); |
363 | break; | 372 | break; |
364 | case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ | 373 | case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ |
365 | if (netif_msg_timer(dev)) | 374 | if (netif_msg_timer(dev)) |
366 | devdbg(dev, "CDC: speed change (len %d)", | 375 | devdbg(dev, "CDC: speed change (len %d)", |
367 | urb->actual_length); | 376 | urb->actual_length); |
368 | if (urb->actual_length != (sizeof *event + 8)) | 377 | if (urb->actual_length != (sizeof *event + 8)) |
369 | set_bit(EVENT_STS_SPLIT, &dev->flags); | 378 | set_bit(EVENT_STS_SPLIT, &dev->flags); |
370 | else | 379 | else |
371 | dumpspeed(dev, (__le32 *) &event[1]); | 380 | dumpspeed(dev, (__le32 *) &event[1]); |
372 | break; | 381 | break; |
373 | /* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS), | 382 | /* USB_CDC_NOTIFY_RESPONSE_AVAILABLE can happen too (e.g. RNDIS), |
374 | * but there are no standard formats for the response data. | 383 | * but there are no standard formats for the response data. |
375 | */ | 384 | */ |
376 | default: | 385 | default: |
377 | deverr(dev, "CDC: unexpected notification %02x!", | 386 | deverr(dev, "CDC: unexpected notification %02x!", |
378 | event->bNotificationType); | 387 | event->bNotificationType); |
379 | break; | 388 | break; |
380 | } | 389 | } |
381 | } | 390 | } |
382 | 391 | ||
383 | static u8 nibble(unsigned char c) | 392 | static u8 nibble(unsigned char c) |
384 | { | 393 | { |
385 | if (likely(isdigit(c))) | 394 | if (likely(isdigit(c))) |
386 | return c - '0'; | 395 | return c - '0'; |
387 | c = toupper(c); | 396 | c = toupper(c); |
388 | if (likely(isxdigit(c))) | 397 | if (likely(isxdigit(c))) |
389 | return 10 + c - 'A'; | 398 | return 10 + c - 'A'; |
390 | return 0; | 399 | return 0; |
391 | } | 400 | } |
392 | 401 | ||
393 | static inline int | 402 | static inline int |
394 | get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) | 403 | get_ethernet_addr(struct usbnet *dev, struct usb_cdc_ether_desc *e) |
395 | { | 404 | { |
396 | int tmp, i; | 405 | int tmp, i; |
397 | unsigned char buf [13]; | 406 | unsigned char buf [13]; |
398 | 407 | ||
399 | tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); | 408 | tmp = usb_string(dev->udev, e->iMACAddress, buf, sizeof buf); |
400 | if (tmp != 12) { | 409 | if (tmp != 12) { |
401 | dev_dbg(&dev->udev->dev, | 410 | dev_dbg(&dev->udev->dev, |
402 | "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); | 411 | "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); |
403 | if (tmp >= 0) | 412 | if (tmp >= 0) |
404 | tmp = -EINVAL; | 413 | tmp = -EINVAL; |
405 | return tmp; | 414 | return tmp; |
406 | } | 415 | } |
407 | for (i = tmp = 0; i < 6; i++, tmp += 2) | 416 | for (i = tmp = 0; i < 6; i++, tmp += 2) |
408 | dev->net->dev_addr [i] = | 417 | dev->net->dev_addr [i] = |
409 | (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); | 418 | (nibble(buf [tmp]) << 4) + nibble(buf [tmp + 1]); |
410 | return 0; | 419 | return 0; |
411 | } | 420 | } |
412 | 421 | ||
413 | static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) | 422 | static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) |
414 | { | 423 | { |
415 | int status; | 424 | int status; |
416 | struct cdc_state *info = (void *) &dev->data; | 425 | struct cdc_state *info = (void *) &dev->data; |
417 | 426 | ||
418 | status = usbnet_generic_cdc_bind(dev, intf); | 427 | status = usbnet_generic_cdc_bind(dev, intf); |
419 | if (status < 0) | 428 | if (status < 0) |
420 | return status; | 429 | return status; |
421 | 430 | ||
422 | status = get_ethernet_addr(dev, info->ether); | 431 | status = get_ethernet_addr(dev, info->ether); |
423 | if (status < 0) { | 432 | if (status < 0) { |
424 | usb_set_intfdata(info->data, NULL); | 433 | usb_set_intfdata(info->data, NULL); |
425 | usb_driver_release_interface(driver_of(intf), info->data); | 434 | usb_driver_release_interface(driver_of(intf), info->data); |
426 | return status; | 435 | return status; |
427 | } | 436 | } |
428 | 437 | ||
429 | /* FIXME cdc-ether has some multicast code too, though it complains | 438 | /* FIXME cdc-ether has some multicast code too, though it complains |
430 | * in routine cases. info->ether describes the multicast support. | 439 | * in routine cases. info->ether describes the multicast support. |
431 | * Implement that here, manipulating the cdc filter as needed. | 440 | * Implement that here, manipulating the cdc filter as needed. |
432 | */ | 441 | */ |
433 | return 0; | 442 | return 0; |
434 | } | 443 | } |
435 | 444 | ||
436 | static const struct driver_info cdc_info = { | 445 | static const struct driver_info cdc_info = { |
437 | .description = "CDC Ethernet Device", | 446 | .description = "CDC Ethernet Device", |
438 | .flags = FLAG_ETHER, | 447 | .flags = FLAG_ETHER, |
439 | // .check_connect = cdc_check_connect, | 448 | // .check_connect = cdc_check_connect, |
440 | .bind = cdc_bind, | 449 | .bind = cdc_bind, |
441 | .unbind = usbnet_cdc_unbind, | 450 | .unbind = usbnet_cdc_unbind, |
442 | .status = cdc_status, | 451 | .status = cdc_status, |
443 | }; | 452 | }; |
444 | 453 | ||
445 | /*-------------------------------------------------------------------------*/ | 454 | /*-------------------------------------------------------------------------*/ |
446 | 455 | ||
447 | 456 | ||
448 | static const struct usb_device_id products [] = { | 457 | static const struct usb_device_id products [] = { |
449 | /* | 458 | /* |
450 | * BLACKLIST !! | 459 | * BLACKLIST !! |
451 | * | 460 | * |
452 | * First blacklist any products that are egregiously nonconformant | 461 | * First blacklist any products that are egregiously nonconformant |
453 | * with the CDC Ethernet specs. Minor braindamage we cope with; when | 462 | * with the CDC Ethernet specs. Minor braindamage we cope with; when |
454 | * they're not even trying, needing a separate driver is only the first | 463 | * they're not even trying, needing a separate driver is only the first |
455 | * of the differences to show up. | 464 | * of the differences to show up. |
456 | */ | 465 | */ |
457 | 466 | ||
458 | #define ZAURUS_MASTER_INTERFACE \ | 467 | #define ZAURUS_MASTER_INTERFACE \ |
459 | .bInterfaceClass = USB_CLASS_COMM, \ | 468 | .bInterfaceClass = USB_CLASS_COMM, \ |
460 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ | 469 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, \ |
461 | .bInterfaceProtocol = USB_CDC_PROTO_NONE | 470 | .bInterfaceProtocol = USB_CDC_PROTO_NONE |
462 | 471 | ||
463 | /* SA-1100 based Sharp Zaurus ("collie"), or compatible; | 472 | /* SA-1100 based Sharp Zaurus ("collie"), or compatible; |
464 | * wire-incompatible with true CDC Ethernet implementations. | 473 | * wire-incompatible with true CDC Ethernet implementations. |
465 | * (And, it seems, needlessly so...) | 474 | * (And, it seems, needlessly so...) |
466 | */ | 475 | */ |
467 | { | 476 | { |
468 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 477 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
469 | | USB_DEVICE_ID_MATCH_DEVICE, | 478 | | USB_DEVICE_ID_MATCH_DEVICE, |
470 | .idVendor = 0x04DD, | 479 | .idVendor = 0x04DD, |
471 | .idProduct = 0x8004, | 480 | .idProduct = 0x8004, |
472 | ZAURUS_MASTER_INTERFACE, | 481 | ZAURUS_MASTER_INTERFACE, |
473 | .driver_info = 0, | 482 | .driver_info = 0, |
474 | }, | 483 | }, |
475 | 484 | ||
476 | /* PXA-25x based Sharp Zaurii. Note that it seems some of these | 485 | /* PXA-25x based Sharp Zaurii. Note that it seems some of these |
477 | * (later models especially) may have shipped only with firmware | 486 | * (later models especially) may have shipped only with firmware |
478 | * advertising false "CDC MDLM" compatibility ... but we're not | 487 | * advertising false "CDC MDLM" compatibility ... but we're not |
479 | * clear which models did that, so for now let's assume the worst. | 488 | * clear which models did that, so for now let's assume the worst. |
480 | */ | 489 | */ |
481 | { | 490 | { |
482 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 491 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
483 | | USB_DEVICE_ID_MATCH_DEVICE, | 492 | | USB_DEVICE_ID_MATCH_DEVICE, |
484 | .idVendor = 0x04DD, | 493 | .idVendor = 0x04DD, |
485 | .idProduct = 0x8005, /* A-300 */ | 494 | .idProduct = 0x8005, /* A-300 */ |
486 | ZAURUS_MASTER_INTERFACE, | 495 | ZAURUS_MASTER_INTERFACE, |
487 | .driver_info = 0, | 496 | .driver_info = 0, |
488 | }, { | 497 | }, { |
489 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 498 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
490 | | USB_DEVICE_ID_MATCH_DEVICE, | 499 | | USB_DEVICE_ID_MATCH_DEVICE, |
491 | .idVendor = 0x04DD, | 500 | .idVendor = 0x04DD, |
492 | .idProduct = 0x8006, /* B-500/SL-5600 */ | 501 | .idProduct = 0x8006, /* B-500/SL-5600 */ |
493 | ZAURUS_MASTER_INTERFACE, | 502 | ZAURUS_MASTER_INTERFACE, |
494 | .driver_info = 0, | 503 | .driver_info = 0, |
495 | }, { | 504 | }, { |
496 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 505 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
497 | | USB_DEVICE_ID_MATCH_DEVICE, | 506 | | USB_DEVICE_ID_MATCH_DEVICE, |
498 | .idVendor = 0x04DD, | 507 | .idVendor = 0x04DD, |
499 | .idProduct = 0x8007, /* C-700 */ | 508 | .idProduct = 0x8007, /* C-700 */ |
500 | ZAURUS_MASTER_INTERFACE, | 509 | ZAURUS_MASTER_INTERFACE, |
501 | .driver_info = 0, | 510 | .driver_info = 0, |
502 | }, { | 511 | }, { |
503 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 512 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
504 | | USB_DEVICE_ID_MATCH_DEVICE, | 513 | | USB_DEVICE_ID_MATCH_DEVICE, |
505 | .idVendor = 0x04DD, | 514 | .idVendor = 0x04DD, |
506 | .idProduct = 0x9031, /* C-750 C-760 */ | 515 | .idProduct = 0x9031, /* C-750 C-760 */ |
507 | ZAURUS_MASTER_INTERFACE, | 516 | ZAURUS_MASTER_INTERFACE, |
508 | .driver_info = 0, | 517 | .driver_info = 0, |
509 | }, { | 518 | }, { |
510 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 519 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
511 | | USB_DEVICE_ID_MATCH_DEVICE, | 520 | | USB_DEVICE_ID_MATCH_DEVICE, |
512 | .idVendor = 0x04DD, | 521 | .idVendor = 0x04DD, |
513 | .idProduct = 0x9032, /* SL-6000 */ | 522 | .idProduct = 0x9032, /* SL-6000 */ |
514 | ZAURUS_MASTER_INTERFACE, | 523 | ZAURUS_MASTER_INTERFACE, |
515 | .driver_info = 0, | 524 | .driver_info = 0, |
516 | }, { | 525 | }, { |
517 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 526 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
518 | | USB_DEVICE_ID_MATCH_DEVICE, | 527 | | USB_DEVICE_ID_MATCH_DEVICE, |
519 | .idVendor = 0x04DD, | 528 | .idVendor = 0x04DD, |
520 | /* reported with some C860 units */ | 529 | /* reported with some C860 units */ |
521 | .idProduct = 0x9050, /* C-860 */ | 530 | .idProduct = 0x9050, /* C-860 */ |
522 | ZAURUS_MASTER_INTERFACE, | 531 | ZAURUS_MASTER_INTERFACE, |
523 | .driver_info = 0, | 532 | .driver_info = 0, |
524 | }, | 533 | }, |
525 | 534 | ||
526 | /* Olympus has some models with a Zaurus-compatible option. | 535 | /* Olympus has some models with a Zaurus-compatible option. |
527 | * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) | 536 | * R-1000 uses a FreeScale i.MXL cpu (ARMv4T) |
528 | */ | 537 | */ |
529 | { | 538 | { |
530 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO | 539 | .match_flags = USB_DEVICE_ID_MATCH_INT_INFO |
531 | | USB_DEVICE_ID_MATCH_DEVICE, | 540 | | USB_DEVICE_ID_MATCH_DEVICE, |
532 | .idVendor = 0x07B4, | 541 | .idVendor = 0x07B4, |
533 | .idProduct = 0x0F02, /* R-1000 */ | 542 | .idProduct = 0x0F02, /* R-1000 */ |
534 | ZAURUS_MASTER_INTERFACE, | 543 | ZAURUS_MASTER_INTERFACE, |
535 | .driver_info = 0, | 544 | .driver_info = 0, |
536 | }, | 545 | }, |
537 | 546 | ||
538 | /* | 547 | /* |
539 | * WHITELIST!!! | 548 | * WHITELIST!!! |
540 | * | 549 | * |
541 | * CDC Ether uses two interfaces, not necessarily consecutive. | 550 | * CDC Ether uses two interfaces, not necessarily consecutive. |
542 | * We match the main interface, ignoring the optional device | 551 | * We match the main interface, ignoring the optional device |
543 | * class so we could handle devices that aren't exclusively | 552 | * class so we could handle devices that aren't exclusively |
544 | * CDC ether. | 553 | * CDC ether. |
545 | * | 554 | * |
546 | * NOTE: this match must come AFTER entries blacklisting devices | 555 | * NOTE: this match must come AFTER entries blacklisting devices |
547 | * because of bugs/quirks in a given product (like Zaurus, above). | 556 | * because of bugs/quirks in a given product (like Zaurus, above). |
548 | */ | 557 | */ |
549 | { | 558 | { |
550 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, | 559 | USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, |
551 | USB_CDC_PROTO_NONE), | 560 | USB_CDC_PROTO_NONE), |
552 | .driver_info = (unsigned long) &cdc_info, | 561 | .driver_info = (unsigned long) &cdc_info, |
553 | }, | 562 | }, |
554 | { }, // END | 563 | { }, // END |
555 | }; | 564 | }; |
556 | MODULE_DEVICE_TABLE(usb, products); | 565 | MODULE_DEVICE_TABLE(usb, products); |
557 | 566 | ||
558 | static struct usb_driver cdc_driver = { | 567 | static struct usb_driver cdc_driver = { |
559 | .name = "cdc_ether", | 568 | .name = "cdc_ether", |
560 | .id_table = products, | 569 | .id_table = products, |
561 | .probe = usbnet_probe, | 570 | .probe = usbnet_probe, |
562 | .disconnect = usbnet_disconnect, | 571 | .disconnect = usbnet_disconnect, |
563 | .suspend = usbnet_suspend, | 572 | .suspend = usbnet_suspend, |
564 | .resume = usbnet_resume, | 573 | .resume = usbnet_resume, |
565 | }; | 574 | }; |
566 | 575 | ||
567 | 576 | ||
568 | static int __init cdc_init(void) | 577 | static int __init cdc_init(void) |
569 | { | 578 | { |
570 | BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) | 579 | BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) |
571 | < sizeof(struct cdc_state))); | 580 | < sizeof(struct cdc_state))); |
572 | 581 | ||
573 | return usb_register(&cdc_driver); | 582 | return usb_register(&cdc_driver); |
574 | } | 583 | } |
575 | module_init(cdc_init); | 584 | module_init(cdc_init); |
576 | 585 | ||
577 | static void __exit cdc_exit(void) | 586 | static void __exit cdc_exit(void) |
578 | { | 587 | { |
579 | usb_deregister(&cdc_driver); | 588 | usb_deregister(&cdc_driver); |
580 | } | 589 | } |
581 | module_exit(cdc_exit); | 590 | module_exit(cdc_exit); |
582 | 591 | ||
583 | MODULE_AUTHOR("David Brownell"); | 592 | MODULE_AUTHOR("David Brownell"); |
584 | MODULE_DESCRIPTION("USB CDC Ethernet devices"); | 593 | MODULE_DESCRIPTION("USB CDC Ethernet devices"); |
585 | MODULE_LICENSE("GPL"); | 594 | MODULE_LICENSE("GPL"); |
586 | 595 |
drivers/net/usb/rndis_host.c
1 | /* | 1 | /* |
2 | * Host Side support for RNDIS Networking Links | 2 | * Host Side support for RNDIS Networking Links |
3 | * Copyright (C) 2005 by David Brownell | 3 | * Copyright (C) 2005 by David Brownell |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * 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 | 6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or | 7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. | 8 | * (at your option) any later version. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/netdevice.h> | 21 | #include <linux/netdevice.h> |
22 | #include <linux/etherdevice.h> | 22 | #include <linux/etherdevice.h> |
23 | #include <linux/ethtool.h> | 23 | #include <linux/ethtool.h> |
24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
25 | #include <linux/mii.h> | 25 | #include <linux/mii.h> |
26 | #include <linux/usb.h> | 26 | #include <linux/usb.h> |
27 | #include <linux/usb/cdc.h> | 27 | #include <linux/usb/cdc.h> |
28 | #include <linux/usb/usbnet.h> | 28 | #include <linux/usb/usbnet.h> |
29 | #include <linux/usb/rndis_host.h> | 29 | #include <linux/usb/rndis_host.h> |
30 | 30 | ||
31 | 31 | ||
32 | /* | 32 | /* |
33 | * RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of | 33 | * RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of |
34 | * course ACM was intended for modems, not Ethernet links! USB's standard | 34 | * course ACM was intended for modems, not Ethernet links! USB's standard |
35 | * for Ethernet links is "CDC Ethernet", which is significantly simpler. | 35 | * for Ethernet links is "CDC Ethernet", which is significantly simpler. |
36 | * | 36 | * |
37 | * NOTE that Microsoft's "RNDIS 1.0" specification is incomplete. Issues | 37 | * NOTE that Microsoft's "RNDIS 1.0" specification is incomplete. Issues |
38 | * include: | 38 | * include: |
39 | * - Power management in particular relies on information that's scattered | 39 | * - Power management in particular relies on information that's scattered |
40 | * through other documentation, and which is incomplete or incorrect even | 40 | * through other documentation, and which is incomplete or incorrect even |
41 | * there. | 41 | * there. |
42 | * - There are various undocumented protocol requirements, such as the | 42 | * - There are various undocumented protocol requirements, such as the |
43 | * need to send unused garbage in control-OUT messages. | 43 | * need to send unused garbage in control-OUT messages. |
44 | * - In some cases, MS-Windows will emit undocumented requests; this | 44 | * - In some cases, MS-Windows will emit undocumented requests; this |
45 | * matters more to peripheral implementations than host ones. | 45 | * matters more to peripheral implementations than host ones. |
46 | * | 46 | * |
47 | * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync". | 47 | * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync". |
48 | * | 48 | * |
49 | * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in | 49 | * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in |
50 | * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and | 50 | * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and |
51 | * currently rare) "Ethernet Emulation Model" (EEM). | 51 | * currently rare) "Ethernet Emulation Model" (EEM). |
52 | */ | 52 | */ |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * RNDIS notifications from device: command completion; "reverse" | 55 | * RNDIS notifications from device: command completion; "reverse" |
56 | * keepalives; etc | 56 | * keepalives; etc |
57 | */ | 57 | */ |
58 | void rndis_status(struct usbnet *dev, struct urb *urb) | 58 | void rndis_status(struct usbnet *dev, struct urb *urb) |
59 | { | 59 | { |
60 | devdbg(dev, "rndis status urb, len %d stat %d", | 60 | devdbg(dev, "rndis status urb, len %d stat %d", |
61 | urb->actual_length, urb->status); | 61 | urb->actual_length, urb->status); |
62 | // FIXME for keepalives, respond immediately (asynchronously) | 62 | // FIXME for keepalives, respond immediately (asynchronously) |
63 | // if not an RNDIS status, do like cdc_status(dev,urb) does | 63 | // if not an RNDIS status, do like cdc_status(dev,urb) does |
64 | } | 64 | } |
65 | EXPORT_SYMBOL_GPL(rndis_status); | 65 | EXPORT_SYMBOL_GPL(rndis_status); |
66 | 66 | ||
67 | /* | 67 | /* |
68 | * RPC done RNDIS-style. Caller guarantees: | 68 | * RPC done RNDIS-style. Caller guarantees: |
69 | * - message is properly byteswapped | 69 | * - message is properly byteswapped |
70 | * - there's no other request pending | 70 | * - there's no other request pending |
71 | * - buf can hold up to 1KB response (required by RNDIS spec) | 71 | * - buf can hold up to 1KB response (required by RNDIS spec) |
72 | * On return, the first few entries are already byteswapped. | 72 | * On return, the first few entries are already byteswapped. |
73 | * | 73 | * |
74 | * Call context is likely probe(), before interface name is known, | 74 | * Call context is likely probe(), before interface name is known, |
75 | * which is why we won't try to use it in the diagnostics. | 75 | * which is why we won't try to use it in the diagnostics. |
76 | */ | 76 | */ |
77 | int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) | 77 | int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) |
78 | { | 78 | { |
79 | struct cdc_state *info = (void *) &dev->data; | 79 | struct cdc_state *info = (void *) &dev->data; |
80 | int master_ifnum; | 80 | int master_ifnum; |
81 | int retval; | 81 | int retval; |
82 | unsigned count; | 82 | unsigned count; |
83 | __le32 rsp; | 83 | __le32 rsp; |
84 | u32 xid = 0, msg_len, request_id; | 84 | u32 xid = 0, msg_len, request_id; |
85 | 85 | ||
86 | /* REVISIT when this gets called from contexts other than probe() or | 86 | /* REVISIT when this gets called from contexts other than probe() or |
87 | * disconnect(): either serialize, or dispatch responses on xid | 87 | * disconnect(): either serialize, or dispatch responses on xid |
88 | */ | 88 | */ |
89 | 89 | ||
90 | /* Issue the request; xid is unique, don't bother byteswapping it */ | 90 | /* Issue the request; xid is unique, don't bother byteswapping it */ |
91 | if (likely(buf->msg_type != RNDIS_MSG_HALT | 91 | if (likely(buf->msg_type != RNDIS_MSG_HALT |
92 | && buf->msg_type != RNDIS_MSG_RESET)) { | 92 | && buf->msg_type != RNDIS_MSG_RESET)) { |
93 | xid = dev->xid++; | 93 | xid = dev->xid++; |
94 | if (!xid) | 94 | if (!xid) |
95 | xid = dev->xid++; | 95 | xid = dev->xid++; |
96 | buf->request_id = (__force __le32) xid; | 96 | buf->request_id = (__force __le32) xid; |
97 | } | 97 | } |
98 | master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber; | 98 | master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber; |
99 | retval = usb_control_msg(dev->udev, | 99 | retval = usb_control_msg(dev->udev, |
100 | usb_sndctrlpipe(dev->udev, 0), | 100 | usb_sndctrlpipe(dev->udev, 0), |
101 | USB_CDC_SEND_ENCAPSULATED_COMMAND, | 101 | USB_CDC_SEND_ENCAPSULATED_COMMAND, |
102 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 102 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
103 | 0, master_ifnum, | 103 | 0, master_ifnum, |
104 | buf, le32_to_cpu(buf->msg_len), | 104 | buf, le32_to_cpu(buf->msg_len), |
105 | RNDIS_CONTROL_TIMEOUT_MS); | 105 | RNDIS_CONTROL_TIMEOUT_MS); |
106 | if (unlikely(retval < 0 || xid == 0)) | 106 | if (unlikely(retval < 0 || xid == 0)) |
107 | return retval; | 107 | return retval; |
108 | 108 | ||
109 | // FIXME Seems like some devices discard responses when | 109 | // FIXME Seems like some devices discard responses when |
110 | // we time out and cancel our "get response" requests... | 110 | // we time out and cancel our "get response" requests... |
111 | // so, this is fragile. Probably need to poll for status. | 111 | // so, this is fragile. Probably need to poll for status. |
112 | 112 | ||
113 | /* ignore status endpoint, just poll the control channel; | 113 | /* ignore status endpoint, just poll the control channel; |
114 | * the request probably completed immediately | 114 | * the request probably completed immediately |
115 | */ | 115 | */ |
116 | rsp = buf->msg_type | RNDIS_MSG_COMPLETION; | 116 | rsp = buf->msg_type | RNDIS_MSG_COMPLETION; |
117 | for (count = 0; count < 10; count++) { | 117 | for (count = 0; count < 10; count++) { |
118 | memset(buf, 0, CONTROL_BUFFER_SIZE); | 118 | memset(buf, 0, CONTROL_BUFFER_SIZE); |
119 | retval = usb_control_msg(dev->udev, | 119 | retval = usb_control_msg(dev->udev, |
120 | usb_rcvctrlpipe(dev->udev, 0), | 120 | usb_rcvctrlpipe(dev->udev, 0), |
121 | USB_CDC_GET_ENCAPSULATED_RESPONSE, | 121 | USB_CDC_GET_ENCAPSULATED_RESPONSE, |
122 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 122 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
123 | 0, master_ifnum, | 123 | 0, master_ifnum, |
124 | buf, buflen, | 124 | buf, buflen, |
125 | RNDIS_CONTROL_TIMEOUT_MS); | 125 | RNDIS_CONTROL_TIMEOUT_MS); |
126 | if (likely(retval >= 8)) { | 126 | if (likely(retval >= 8)) { |
127 | msg_len = le32_to_cpu(buf->msg_len); | 127 | msg_len = le32_to_cpu(buf->msg_len); |
128 | request_id = (__force u32) buf->request_id; | 128 | request_id = (__force u32) buf->request_id; |
129 | if (likely(buf->msg_type == rsp)) { | 129 | if (likely(buf->msg_type == rsp)) { |
130 | if (likely(request_id == xid)) { | 130 | if (likely(request_id == xid)) { |
131 | if (unlikely(rsp == RNDIS_MSG_RESET_C)) | 131 | if (unlikely(rsp == RNDIS_MSG_RESET_C)) |
132 | return 0; | 132 | return 0; |
133 | if (likely(RNDIS_STATUS_SUCCESS | 133 | if (likely(RNDIS_STATUS_SUCCESS |
134 | == buf->status)) | 134 | == buf->status)) |
135 | return 0; | 135 | return 0; |
136 | dev_dbg(&info->control->dev, | 136 | dev_dbg(&info->control->dev, |
137 | "rndis reply status %08x\n", | 137 | "rndis reply status %08x\n", |
138 | le32_to_cpu(buf->status)); | 138 | le32_to_cpu(buf->status)); |
139 | return -EL3RST; | 139 | return -EL3RST; |
140 | } | 140 | } |
141 | dev_dbg(&info->control->dev, | 141 | dev_dbg(&info->control->dev, |
142 | "rndis reply id %d expected %d\n", | 142 | "rndis reply id %d expected %d\n", |
143 | request_id, xid); | 143 | request_id, xid); |
144 | /* then likely retry */ | 144 | /* then likely retry */ |
145 | } else switch (buf->msg_type) { | 145 | } else switch (buf->msg_type) { |
146 | case RNDIS_MSG_INDICATE: { /* fault/event */ | 146 | case RNDIS_MSG_INDICATE: { /* fault/event */ |
147 | struct rndis_indicate *msg = (void *)buf; | 147 | struct rndis_indicate *msg = (void *)buf; |
148 | int state = 0; | 148 | int state = 0; |
149 | 149 | ||
150 | switch (msg->status) { | 150 | switch (msg->status) { |
151 | case RNDIS_STATUS_MEDIA_CONNECT: | 151 | case RNDIS_STATUS_MEDIA_CONNECT: |
152 | state = 1; | 152 | state = 1; |
153 | case RNDIS_STATUS_MEDIA_DISCONNECT: | 153 | case RNDIS_STATUS_MEDIA_DISCONNECT: |
154 | dev_info(&info->control->dev, | 154 | dev_info(&info->control->dev, |
155 | "rndis media %sconnect\n", | 155 | "rndis media %sconnect\n", |
156 | !state?"dis":""); | 156 | !state?"dis":""); |
157 | if (dev->driver_info->link_change) | 157 | if (dev->driver_info->link_change) |
158 | dev->driver_info->link_change( | 158 | dev->driver_info->link_change( |
159 | dev, state); | 159 | dev, state); |
160 | break; | 160 | break; |
161 | default: | 161 | default: |
162 | dev_info(&info->control->dev, | 162 | dev_info(&info->control->dev, |
163 | "rndis indication: 0x%08x\n", | 163 | "rndis indication: 0x%08x\n", |
164 | le32_to_cpu(msg->status)); | 164 | le32_to_cpu(msg->status)); |
165 | } | 165 | } |
166 | } | 166 | } |
167 | break; | 167 | break; |
168 | case RNDIS_MSG_KEEPALIVE: { /* ping */ | 168 | case RNDIS_MSG_KEEPALIVE: { /* ping */ |
169 | struct rndis_keepalive_c *msg = (void *)buf; | 169 | struct rndis_keepalive_c *msg = (void *)buf; |
170 | 170 | ||
171 | msg->msg_type = RNDIS_MSG_KEEPALIVE_C; | 171 | msg->msg_type = RNDIS_MSG_KEEPALIVE_C; |
172 | msg->msg_len = ccpu2(sizeof *msg); | 172 | msg->msg_len = ccpu2(sizeof *msg); |
173 | msg->status = RNDIS_STATUS_SUCCESS; | 173 | msg->status = RNDIS_STATUS_SUCCESS; |
174 | retval = usb_control_msg(dev->udev, | 174 | retval = usb_control_msg(dev->udev, |
175 | usb_sndctrlpipe(dev->udev, 0), | 175 | usb_sndctrlpipe(dev->udev, 0), |
176 | USB_CDC_SEND_ENCAPSULATED_COMMAND, | 176 | USB_CDC_SEND_ENCAPSULATED_COMMAND, |
177 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | 177 | USB_TYPE_CLASS | USB_RECIP_INTERFACE, |
178 | 0, master_ifnum, | 178 | 0, master_ifnum, |
179 | msg, sizeof *msg, | 179 | msg, sizeof *msg, |
180 | RNDIS_CONTROL_TIMEOUT_MS); | 180 | RNDIS_CONTROL_TIMEOUT_MS); |
181 | if (unlikely(retval < 0)) | 181 | if (unlikely(retval < 0)) |
182 | dev_dbg(&info->control->dev, | 182 | dev_dbg(&info->control->dev, |
183 | "rndis keepalive err %d\n", | 183 | "rndis keepalive err %d\n", |
184 | retval); | 184 | retval); |
185 | } | 185 | } |
186 | break; | 186 | break; |
187 | default: | 187 | default: |
188 | dev_dbg(&info->control->dev, | 188 | dev_dbg(&info->control->dev, |
189 | "unexpected rndis msg %08x len %d\n", | 189 | "unexpected rndis msg %08x len %d\n", |
190 | le32_to_cpu(buf->msg_type), msg_len); | 190 | le32_to_cpu(buf->msg_type), msg_len); |
191 | } | 191 | } |
192 | } else { | 192 | } else { |
193 | /* device probably issued a protocol stall; ignore */ | 193 | /* device probably issued a protocol stall; ignore */ |
194 | dev_dbg(&info->control->dev, | 194 | dev_dbg(&info->control->dev, |
195 | "rndis response error, code %d\n", retval); | 195 | "rndis response error, code %d\n", retval); |
196 | } | 196 | } |
197 | msleep(20); | 197 | msleep(20); |
198 | } | 198 | } |
199 | dev_dbg(&info->control->dev, "rndis response timeout\n"); | 199 | dev_dbg(&info->control->dev, "rndis response timeout\n"); |
200 | return -ETIMEDOUT; | 200 | return -ETIMEDOUT; |
201 | } | 201 | } |
202 | EXPORT_SYMBOL_GPL(rndis_command); | 202 | EXPORT_SYMBOL_GPL(rndis_command); |
203 | 203 | ||
204 | /* | 204 | /* |
205 | * rndis_query: | 205 | * rndis_query: |
206 | * | 206 | * |
207 | * Performs a query for @oid along with 0 or more bytes of payload as | 207 | * Performs a query for @oid along with 0 or more bytes of payload as |
208 | * specified by @in_len. If @reply_len is not set to -1 then the reply | 208 | * specified by @in_len. If @reply_len is not set to -1 then the reply |
209 | * length is checked against this value, resulting in an error if it | 209 | * length is checked against this value, resulting in an error if it |
210 | * doesn't match. | 210 | * doesn't match. |
211 | * | 211 | * |
212 | * NOTE: Adding a payload exactly or greater than the size of the expected | 212 | * NOTE: Adding a payload exactly or greater than the size of the expected |
213 | * response payload is an evident requirement MSFT added for ActiveSync. | 213 | * response payload is an evident requirement MSFT added for ActiveSync. |
214 | * | 214 | * |
215 | * The only exception is for OIDs that return a variably sized response, | 215 | * The only exception is for OIDs that return a variably sized response, |
216 | * in which case no payload should be added. This undocumented (and | 216 | * in which case no payload should be added. This undocumented (and |
217 | * nonsensical!) issue was found by sniffing protocol requests from the | 217 | * nonsensical!) issue was found by sniffing protocol requests from the |
218 | * ActiveSync 4.1 Windows driver. | 218 | * ActiveSync 4.1 Windows driver. |
219 | */ | 219 | */ |
220 | static int rndis_query(struct usbnet *dev, struct usb_interface *intf, | 220 | static int rndis_query(struct usbnet *dev, struct usb_interface *intf, |
221 | void *buf, __le32 oid, u32 in_len, | 221 | void *buf, __le32 oid, u32 in_len, |
222 | void **reply, int *reply_len) | 222 | void **reply, int *reply_len) |
223 | { | 223 | { |
224 | int retval; | 224 | int retval; |
225 | union { | 225 | union { |
226 | void *buf; | 226 | void *buf; |
227 | struct rndis_msg_hdr *header; | 227 | struct rndis_msg_hdr *header; |
228 | struct rndis_query *get; | 228 | struct rndis_query *get; |
229 | struct rndis_query_c *get_c; | 229 | struct rndis_query_c *get_c; |
230 | } u; | 230 | } u; |
231 | u32 off, len; | 231 | u32 off, len; |
232 | 232 | ||
233 | u.buf = buf; | 233 | u.buf = buf; |
234 | 234 | ||
235 | memset(u.get, 0, sizeof *u.get + in_len); | 235 | memset(u.get, 0, sizeof *u.get + in_len); |
236 | u.get->msg_type = RNDIS_MSG_QUERY; | 236 | u.get->msg_type = RNDIS_MSG_QUERY; |
237 | u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); | 237 | u.get->msg_len = cpu_to_le32(sizeof *u.get + in_len); |
238 | u.get->oid = oid; | 238 | u.get->oid = oid; |
239 | u.get->len = cpu_to_le32(in_len); | 239 | u.get->len = cpu_to_le32(in_len); |
240 | u.get->offset = ccpu2(20); | 240 | u.get->offset = ccpu2(20); |
241 | 241 | ||
242 | retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); | 242 | retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); |
243 | if (unlikely(retval < 0)) { | 243 | if (unlikely(retval < 0)) { |
244 | dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n", | 244 | dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) failed, %d\n", |
245 | oid, retval); | 245 | oid, retval); |
246 | return retval; | 246 | return retval; |
247 | } | 247 | } |
248 | 248 | ||
249 | off = le32_to_cpu(u.get_c->offset); | 249 | off = le32_to_cpu(u.get_c->offset); |
250 | len = le32_to_cpu(u.get_c->len); | 250 | len = le32_to_cpu(u.get_c->len); |
251 | if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE)) | 251 | if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE)) |
252 | goto response_error; | 252 | goto response_error; |
253 | 253 | ||
254 | if (*reply_len != -1 && len != *reply_len) | 254 | if (*reply_len != -1 && len != *reply_len) |
255 | goto response_error; | 255 | goto response_error; |
256 | 256 | ||
257 | *reply = (unsigned char *) &u.get_c->request_id + off; | 257 | *reply = (unsigned char *) &u.get_c->request_id + off; |
258 | *reply_len = len; | 258 | *reply_len = len; |
259 | 259 | ||
260 | return retval; | 260 | return retval; |
261 | 261 | ||
262 | response_error: | 262 | response_error: |
263 | dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) " | 263 | dev_err(&intf->dev, "RNDIS_MSG_QUERY(0x%08x) " |
264 | "invalid response - off %d len %d\n", | 264 | "invalid response - off %d len %d\n", |
265 | oid, off, len); | 265 | oid, off, len); |
266 | return -EDOM; | 266 | return -EDOM; |
267 | } | 267 | } |
268 | 268 | ||
269 | int | 269 | int |
270 | generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) | 270 | generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags) |
271 | { | 271 | { |
272 | int retval; | 272 | int retval; |
273 | struct net_device *net = dev->net; | 273 | struct net_device *net = dev->net; |
274 | struct cdc_state *info = (void *) &dev->data; | 274 | struct cdc_state *info = (void *) &dev->data; |
275 | union { | 275 | union { |
276 | void *buf; | 276 | void *buf; |
277 | struct rndis_msg_hdr *header; | 277 | struct rndis_msg_hdr *header; |
278 | struct rndis_init *init; | 278 | struct rndis_init *init; |
279 | struct rndis_init_c *init_c; | 279 | struct rndis_init_c *init_c; |
280 | struct rndis_query *get; | 280 | struct rndis_query *get; |
281 | struct rndis_query_c *get_c; | 281 | struct rndis_query_c *get_c; |
282 | struct rndis_set *set; | 282 | struct rndis_set *set; |
283 | struct rndis_set_c *set_c; | 283 | struct rndis_set_c *set_c; |
284 | struct rndis_halt *halt; | 284 | struct rndis_halt *halt; |
285 | } u; | 285 | } u; |
286 | u32 tmp; | 286 | u32 tmp; |
287 | __le32 phym_unspec, *phym; | 287 | __le32 phym_unspec, *phym; |
288 | int reply_len; | 288 | int reply_len; |
289 | unsigned char *bp; | 289 | unsigned char *bp; |
290 | 290 | ||
291 | /* we can't rely on i/o from stack working, or stack allocation */ | 291 | /* we can't rely on i/o from stack working, or stack allocation */ |
292 | u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); | 292 | u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); |
293 | if (!u.buf) | 293 | if (!u.buf) |
294 | return -ENOMEM; | 294 | return -ENOMEM; |
295 | retval = usbnet_generic_cdc_bind(dev, intf); | 295 | retval = usbnet_generic_cdc_bind(dev, intf); |
296 | if (retval < 0) | 296 | if (retval < 0) |
297 | goto fail; | 297 | goto fail; |
298 | 298 | ||
299 | u.init->msg_type = RNDIS_MSG_INIT; | 299 | u.init->msg_type = RNDIS_MSG_INIT; |
300 | u.init->msg_len = ccpu2(sizeof *u.init); | 300 | u.init->msg_len = ccpu2(sizeof *u.init); |
301 | u.init->major_version = ccpu2(1); | 301 | u.init->major_version = ccpu2(1); |
302 | u.init->minor_version = ccpu2(0); | 302 | u.init->minor_version = ccpu2(0); |
303 | 303 | ||
304 | /* max transfer (in spec) is 0x4000 at full speed, but for | 304 | /* max transfer (in spec) is 0x4000 at full speed, but for |
305 | * TX we'll stick to one Ethernet packet plus RNDIS framing. | 305 | * TX we'll stick to one Ethernet packet plus RNDIS framing. |
306 | * For RX we handle drivers that zero-pad to end-of-packet. | 306 | * For RX we handle drivers that zero-pad to end-of-packet. |
307 | * Don't let userspace change these settings. | 307 | * Don't let userspace change these settings. |
308 | * | 308 | * |
309 | * NOTE: there still seems to be wierdness here, as if we need | 309 | * NOTE: there still seems to be wierdness here, as if we need |
310 | * to do some more things to make sure WinCE targets accept this. | 310 | * to do some more things to make sure WinCE targets accept this. |
311 | * They default to jumbograms of 8KB or 16KB, which is absurd | 311 | * They default to jumbograms of 8KB or 16KB, which is absurd |
312 | * for such low data rates and which is also more than Linux | 312 | * for such low data rates and which is also more than Linux |
313 | * can usually expect to allocate for SKB data... | 313 | * can usually expect to allocate for SKB data... |
314 | */ | 314 | */ |
315 | net->hard_header_len += sizeof (struct rndis_data_hdr); | 315 | net->hard_header_len += sizeof (struct rndis_data_hdr); |
316 | dev->hard_mtu = net->mtu + net->hard_header_len; | 316 | dev->hard_mtu = net->mtu + net->hard_header_len; |
317 | 317 | ||
318 | dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); | 318 | dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); |
319 | if (dev->maxpacket == 0) { | 319 | if (dev->maxpacket == 0) { |
320 | if (netif_msg_probe(dev)) | 320 | if (netif_msg_probe(dev)) |
321 | dev_dbg(&intf->dev, "dev->maxpacket can't be 0\n"); | 321 | dev_dbg(&intf->dev, "dev->maxpacket can't be 0\n"); |
322 | retval = -EINVAL; | 322 | retval = -EINVAL; |
323 | goto fail_and_release; | 323 | goto fail_and_release; |
324 | } | 324 | } |
325 | 325 | ||
326 | dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); | 326 | dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1); |
327 | dev->rx_urb_size &= ~(dev->maxpacket - 1); | 327 | dev->rx_urb_size &= ~(dev->maxpacket - 1); |
328 | u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); | 328 | u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size); |
329 | 329 | ||
330 | net->change_mtu = NULL; | 330 | net->change_mtu = NULL; |
331 | retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); | 331 | retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); |
332 | if (unlikely(retval < 0)) { | 332 | if (unlikely(retval < 0)) { |
333 | /* it might not even be an RNDIS device!! */ | 333 | /* it might not even be an RNDIS device!! */ |
334 | dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); | 334 | dev_err(&intf->dev, "RNDIS init failed, %d\n", retval); |
335 | goto fail_and_release; | 335 | goto fail_and_release; |
336 | } | 336 | } |
337 | tmp = le32_to_cpu(u.init_c->max_transfer_size); | 337 | tmp = le32_to_cpu(u.init_c->max_transfer_size); |
338 | if (tmp < dev->hard_mtu) { | 338 | if (tmp < dev->hard_mtu) { |
339 | if (tmp <= net->hard_header_len) { | 339 | if (tmp <= net->hard_header_len) { |
340 | dev_err(&intf->dev, | 340 | dev_err(&intf->dev, |
341 | "dev can't take %u byte packets (max %u)\n", | 341 | "dev can't take %u byte packets (max %u)\n", |
342 | dev->hard_mtu, tmp); | 342 | dev->hard_mtu, tmp); |
343 | retval = -EINVAL; | 343 | retval = -EINVAL; |
344 | goto halt_fail_and_release; | 344 | goto halt_fail_and_release; |
345 | } | 345 | } |
346 | dev->hard_mtu = tmp; | 346 | dev->hard_mtu = tmp; |
347 | net->mtu = dev->hard_mtu - net->hard_header_len; | 347 | net->mtu = dev->hard_mtu - net->hard_header_len; |
348 | dev_warn(&intf->dev, | 348 | dev_warn(&intf->dev, |
349 | "dev can't take %u byte packets (max %u), " | 349 | "dev can't take %u byte packets (max %u), " |
350 | "adjusting MTU to %u\n", | 350 | "adjusting MTU to %u\n", |
351 | dev->hard_mtu, tmp, net->mtu); | 351 | dev->hard_mtu, tmp, net->mtu); |
352 | } | 352 | } |
353 | 353 | ||
354 | /* REVISIT: peripheral "alignment" request is ignored ... */ | 354 | /* REVISIT: peripheral "alignment" request is ignored ... */ |
355 | dev_dbg(&intf->dev, | 355 | dev_dbg(&intf->dev, |
356 | "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n", | 356 | "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n", |
357 | dev->hard_mtu, tmp, dev->rx_urb_size, | 357 | dev->hard_mtu, tmp, dev->rx_urb_size, |
358 | 1 << le32_to_cpu(u.init_c->packet_alignment)); | 358 | 1 << le32_to_cpu(u.init_c->packet_alignment)); |
359 | 359 | ||
360 | /* module has some device initialization code needs to be done right | 360 | /* module has some device initialization code needs to be done right |
361 | * after RNDIS_INIT */ | 361 | * after RNDIS_INIT */ |
362 | if (dev->driver_info->early_init && | 362 | if (dev->driver_info->early_init && |
363 | dev->driver_info->early_init(dev) != 0) | 363 | dev->driver_info->early_init(dev) != 0) |
364 | goto halt_fail_and_release; | 364 | goto halt_fail_and_release; |
365 | 365 | ||
366 | /* Check physical medium */ | 366 | /* Check physical medium */ |
367 | phym = NULL; | 367 | phym = NULL; |
368 | reply_len = sizeof *phym; | 368 | reply_len = sizeof *phym; |
369 | retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM, | 369 | retval = rndis_query(dev, intf, u.buf, OID_GEN_PHYSICAL_MEDIUM, |
370 | 0, (void **) &phym, &reply_len); | 370 | 0, (void **) &phym, &reply_len); |
371 | if (retval != 0 || !phym) { | 371 | if (retval != 0 || !phym) { |
372 | /* OID is optional so don't fail here. */ | 372 | /* OID is optional so don't fail here. */ |
373 | phym_unspec = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED; | 373 | phym_unspec = RNDIS_PHYSICAL_MEDIUM_UNSPECIFIED; |
374 | phym = &phym_unspec; | 374 | phym = &phym_unspec; |
375 | } | 375 | } |
376 | if ((flags & FLAG_RNDIS_PHYM_WIRELESS) && | 376 | if ((flags & FLAG_RNDIS_PHYM_WIRELESS) && |
377 | *phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { | 377 | *phym != RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { |
378 | if (netif_msg_probe(dev)) | 378 | if (netif_msg_probe(dev)) |
379 | dev_dbg(&intf->dev, "driver requires wireless " | 379 | dev_dbg(&intf->dev, "driver requires wireless " |
380 | "physical medium, but device is not.\n"); | 380 | "physical medium, but device is not.\n"); |
381 | retval = -ENODEV; | 381 | retval = -ENODEV; |
382 | goto halt_fail_and_release; | 382 | goto halt_fail_and_release; |
383 | } | 383 | } |
384 | if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) && | 384 | if ((flags & FLAG_RNDIS_PHYM_NOT_WIRELESS) && |
385 | *phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { | 385 | *phym == RNDIS_PHYSICAL_MEDIUM_WIRELESS_LAN) { |
386 | if (netif_msg_probe(dev)) | 386 | if (netif_msg_probe(dev)) |
387 | dev_dbg(&intf->dev, "driver requires non-wireless " | 387 | dev_dbg(&intf->dev, "driver requires non-wireless " |
388 | "physical medium, but device is wireless.\n"); | 388 | "physical medium, but device is wireless.\n"); |
389 | retval = -ENODEV; | 389 | retval = -ENODEV; |
390 | goto halt_fail_and_release; | 390 | goto halt_fail_and_release; |
391 | } | 391 | } |
392 | 392 | ||
393 | /* Get designated host ethernet address */ | 393 | /* Get designated host ethernet address */ |
394 | reply_len = ETH_ALEN; | 394 | reply_len = ETH_ALEN; |
395 | retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS, | 395 | retval = rndis_query(dev, intf, u.buf, OID_802_3_PERMANENT_ADDRESS, |
396 | 48, (void **) &bp, &reply_len); | 396 | 48, (void **) &bp, &reply_len); |
397 | if (unlikely(retval< 0)) { | 397 | if (unlikely(retval< 0)) { |
398 | dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); | 398 | dev_err(&intf->dev, "rndis get ethaddr, %d\n", retval); |
399 | goto halt_fail_and_release; | 399 | goto halt_fail_and_release; |
400 | } | 400 | } |
401 | memcpy(net->dev_addr, bp, ETH_ALEN); | 401 | memcpy(net->dev_addr, bp, ETH_ALEN); |
402 | 402 | ||
403 | /* set a nonzero filter to enable data transfers */ | 403 | /* set a nonzero filter to enable data transfers */ |
404 | memset(u.set, 0, sizeof *u.set); | 404 | memset(u.set, 0, sizeof *u.set); |
405 | u.set->msg_type = RNDIS_MSG_SET; | 405 | u.set->msg_type = RNDIS_MSG_SET; |
406 | u.set->msg_len = ccpu2(4 + sizeof *u.set); | 406 | u.set->msg_len = ccpu2(4 + sizeof *u.set); |
407 | u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; | 407 | u.set->oid = OID_GEN_CURRENT_PACKET_FILTER; |
408 | u.set->len = ccpu2(4); | 408 | u.set->len = ccpu2(4); |
409 | u.set->offset = ccpu2((sizeof *u.set) - 8); | 409 | u.set->offset = ccpu2((sizeof *u.set) - 8); |
410 | *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER; | 410 | *(__le32 *)(u.buf + sizeof *u.set) = RNDIS_DEFAULT_FILTER; |
411 | 411 | ||
412 | retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); | 412 | retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE); |
413 | if (unlikely(retval < 0)) { | 413 | if (unlikely(retval < 0)) { |
414 | dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); | 414 | dev_err(&intf->dev, "rndis set packet filter, %d\n", retval); |
415 | goto halt_fail_and_release; | 415 | goto halt_fail_and_release; |
416 | } | 416 | } |
417 | 417 | ||
418 | retval = 0; | 418 | retval = 0; |
419 | 419 | ||
420 | kfree(u.buf); | 420 | kfree(u.buf); |
421 | return retval; | 421 | return retval; |
422 | 422 | ||
423 | halt_fail_and_release: | 423 | halt_fail_and_release: |
424 | memset(u.halt, 0, sizeof *u.halt); | 424 | memset(u.halt, 0, sizeof *u.halt); |
425 | u.halt->msg_type = RNDIS_MSG_HALT; | 425 | u.halt->msg_type = RNDIS_MSG_HALT; |
426 | u.halt->msg_len = ccpu2(sizeof *u.halt); | 426 | u.halt->msg_len = ccpu2(sizeof *u.halt); |
427 | (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE); | 427 | (void) rndis_command(dev, (void *)u.halt, CONTROL_BUFFER_SIZE); |
428 | fail_and_release: | 428 | fail_and_release: |
429 | usb_set_intfdata(info->data, NULL); | 429 | usb_set_intfdata(info->data, NULL); |
430 | usb_driver_release_interface(driver_of(intf), info->data); | 430 | usb_driver_release_interface(driver_of(intf), info->data); |
431 | info->data = NULL; | 431 | info->data = NULL; |
432 | fail: | 432 | fail: |
433 | kfree(u.buf); | 433 | kfree(u.buf); |
434 | return retval; | 434 | return retval; |
435 | } | 435 | } |
436 | EXPORT_SYMBOL_GPL(generic_rndis_bind); | 436 | EXPORT_SYMBOL_GPL(generic_rndis_bind); |
437 | 437 | ||
438 | static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) | 438 | static int rndis_bind(struct usbnet *dev, struct usb_interface *intf) |
439 | { | 439 | { |
440 | return generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_NOT_WIRELESS); | 440 | return generic_rndis_bind(dev, intf, FLAG_RNDIS_PHYM_NOT_WIRELESS); |
441 | } | 441 | } |
442 | 442 | ||
443 | void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) | 443 | void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) |
444 | { | 444 | { |
445 | struct rndis_halt *halt; | 445 | struct rndis_halt *halt; |
446 | 446 | ||
447 | /* try to clear any rndis state/activity (no i/o from stack!) */ | 447 | /* try to clear any rndis state/activity (no i/o from stack!) */ |
448 | halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); | 448 | halt = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL); |
449 | if (halt) { | 449 | if (halt) { |
450 | halt->msg_type = RNDIS_MSG_HALT; | 450 | halt->msg_type = RNDIS_MSG_HALT; |
451 | halt->msg_len = ccpu2(sizeof *halt); | 451 | halt->msg_len = ccpu2(sizeof *halt); |
452 | (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE); | 452 | (void) rndis_command(dev, (void *)halt, CONTROL_BUFFER_SIZE); |
453 | kfree(halt); | 453 | kfree(halt); |
454 | } | 454 | } |
455 | 455 | ||
456 | usbnet_cdc_unbind(dev, intf); | 456 | usbnet_cdc_unbind(dev, intf); |
457 | } | 457 | } |
458 | EXPORT_SYMBOL_GPL(rndis_unbind); | 458 | EXPORT_SYMBOL_GPL(rndis_unbind); |
459 | 459 | ||
460 | /* | 460 | /* |
461 | * DATA -- host must not write zlps | 461 | * DATA -- host must not write zlps |
462 | */ | 462 | */ |
463 | int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) | 463 | int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
464 | { | 464 | { |
465 | /* peripheral may have batched packets to us... */ | 465 | /* peripheral may have batched packets to us... */ |
466 | while (likely(skb->len)) { | 466 | while (likely(skb->len)) { |
467 | struct rndis_data_hdr *hdr = (void *)skb->data; | 467 | struct rndis_data_hdr *hdr = (void *)skb->data; |
468 | struct sk_buff *skb2; | 468 | struct sk_buff *skb2; |
469 | u32 msg_len, data_offset, data_len; | 469 | u32 msg_len, data_offset, data_len; |
470 | 470 | ||
471 | msg_len = le32_to_cpu(hdr->msg_len); | 471 | msg_len = le32_to_cpu(hdr->msg_len); |
472 | data_offset = le32_to_cpu(hdr->data_offset); | 472 | data_offset = le32_to_cpu(hdr->data_offset); |
473 | data_len = le32_to_cpu(hdr->data_len); | 473 | data_len = le32_to_cpu(hdr->data_len); |
474 | 474 | ||
475 | /* don't choke if we see oob, per-packet data, etc */ | 475 | /* don't choke if we see oob, per-packet data, etc */ |
476 | if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET | 476 | if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET |
477 | || skb->len < msg_len | 477 | || skb->len < msg_len |
478 | || (data_offset + data_len + 8) > msg_len)) { | 478 | || (data_offset + data_len + 8) > msg_len)) { |
479 | dev->stats.rx_frame_errors++; | 479 | dev->stats.rx_frame_errors++; |
480 | devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d", | 480 | devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d", |
481 | le32_to_cpu(hdr->msg_type), | 481 | le32_to_cpu(hdr->msg_type), |
482 | msg_len, data_offset, data_len, skb->len); | 482 | msg_len, data_offset, data_len, skb->len); |
483 | return 0; | 483 | return 0; |
484 | } | 484 | } |
485 | skb_pull(skb, 8 + data_offset); | 485 | skb_pull(skb, 8 + data_offset); |
486 | 486 | ||
487 | /* at most one packet left? */ | 487 | /* at most one packet left? */ |
488 | if (likely((data_len - skb->len) <= sizeof *hdr)) { | 488 | if (likely((data_len - skb->len) <= sizeof *hdr)) { |
489 | skb_trim(skb, data_len); | 489 | skb_trim(skb, data_len); |
490 | break; | 490 | break; |
491 | } | 491 | } |
492 | 492 | ||
493 | /* try to return all the packets in the batch */ | 493 | /* try to return all the packets in the batch */ |
494 | skb2 = skb_clone(skb, GFP_ATOMIC); | 494 | skb2 = skb_clone(skb, GFP_ATOMIC); |
495 | if (unlikely(!skb2)) | 495 | if (unlikely(!skb2)) |
496 | break; | 496 | break; |
497 | skb_pull(skb, msg_len - sizeof *hdr); | 497 | skb_pull(skb, msg_len - sizeof *hdr); |
498 | skb_trim(skb2, data_len); | 498 | skb_trim(skb2, data_len); |
499 | usbnet_skb_return(dev, skb2); | 499 | usbnet_skb_return(dev, skb2); |
500 | } | 500 | } |
501 | 501 | ||
502 | /* caller will usbnet_skb_return the remaining packet */ | 502 | /* caller will usbnet_skb_return the remaining packet */ |
503 | return 1; | 503 | return 1; |
504 | } | 504 | } |
505 | EXPORT_SYMBOL_GPL(rndis_rx_fixup); | 505 | EXPORT_SYMBOL_GPL(rndis_rx_fixup); |
506 | 506 | ||
507 | struct sk_buff * | 507 | struct sk_buff * |
508 | rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) | 508 | rndis_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) |
509 | { | 509 | { |
510 | struct rndis_data_hdr *hdr; | 510 | struct rndis_data_hdr *hdr; |
511 | struct sk_buff *skb2; | 511 | struct sk_buff *skb2; |
512 | unsigned len = skb->len; | 512 | unsigned len = skb->len; |
513 | 513 | ||
514 | if (likely(!skb_cloned(skb))) { | 514 | if (likely(!skb_cloned(skb))) { |
515 | int room = skb_headroom(skb); | 515 | int room = skb_headroom(skb); |
516 | 516 | ||
517 | /* enough head room as-is? */ | 517 | /* enough head room as-is? */ |
518 | if (unlikely((sizeof *hdr) <= room)) | 518 | if (unlikely((sizeof *hdr) <= room)) |
519 | goto fill; | 519 | goto fill; |
520 | 520 | ||
521 | /* enough room, but needs to be readjusted? */ | 521 | /* enough room, but needs to be readjusted? */ |
522 | room += skb_tailroom(skb); | 522 | room += skb_tailroom(skb); |
523 | if (likely((sizeof *hdr) <= room)) { | 523 | if (likely((sizeof *hdr) <= room)) { |
524 | skb->data = memmove(skb->head + sizeof *hdr, | 524 | skb->data = memmove(skb->head + sizeof *hdr, |
525 | skb->data, len); | 525 | skb->data, len); |
526 | skb_set_tail_pointer(skb, len); | 526 | skb_set_tail_pointer(skb, len); |
527 | goto fill; | 527 | goto fill; |
528 | } | 528 | } |
529 | } | 529 | } |
530 | 530 | ||
531 | /* create a new skb, with the correct size (and tailpad) */ | 531 | /* create a new skb, with the correct size (and tailpad) */ |
532 | skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags); | 532 | skb2 = skb_copy_expand(skb, sizeof *hdr, 1, flags); |
533 | dev_kfree_skb_any(skb); | 533 | dev_kfree_skb_any(skb); |
534 | if (unlikely(!skb2)) | 534 | if (unlikely(!skb2)) |
535 | return skb2; | 535 | return skb2; |
536 | skb = skb2; | 536 | skb = skb2; |
537 | 537 | ||
538 | /* fill out the RNDIS header. we won't bother trying to batch | 538 | /* fill out the RNDIS header. we won't bother trying to batch |
539 | * packets; Linux minimizes wasted bandwidth through tx queues. | 539 | * packets; Linux minimizes wasted bandwidth through tx queues. |
540 | */ | 540 | */ |
541 | fill: | 541 | fill: |
542 | hdr = (void *) __skb_push(skb, sizeof *hdr); | 542 | hdr = (void *) __skb_push(skb, sizeof *hdr); |
543 | memset(hdr, 0, sizeof *hdr); | 543 | memset(hdr, 0, sizeof *hdr); |
544 | hdr->msg_type = RNDIS_MSG_PACKET; | 544 | hdr->msg_type = RNDIS_MSG_PACKET; |
545 | hdr->msg_len = cpu_to_le32(skb->len); | 545 | hdr->msg_len = cpu_to_le32(skb->len); |
546 | hdr->data_offset = ccpu2(sizeof(*hdr) - 8); | 546 | hdr->data_offset = ccpu2(sizeof(*hdr) - 8); |
547 | hdr->data_len = cpu_to_le32(len); | 547 | hdr->data_len = cpu_to_le32(len); |
548 | 548 | ||
549 | /* FIXME make the last packet always be short ... */ | 549 | /* FIXME make the last packet always be short ... */ |
550 | return skb; | 550 | return skb; |
551 | } | 551 | } |
552 | EXPORT_SYMBOL_GPL(rndis_tx_fixup); | 552 | EXPORT_SYMBOL_GPL(rndis_tx_fixup); |
553 | 553 | ||
554 | 554 | ||
555 | static const struct driver_info rndis_info = { | 555 | static const struct driver_info rndis_info = { |
556 | .description = "RNDIS device", | 556 | .description = "RNDIS device", |
557 | .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, | 557 | .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, |
558 | .bind = rndis_bind, | 558 | .bind = rndis_bind, |
559 | .unbind = rndis_unbind, | 559 | .unbind = rndis_unbind, |
560 | .status = rndis_status, | 560 | .status = rndis_status, |
561 | .rx_fixup = rndis_rx_fixup, | 561 | .rx_fixup = rndis_rx_fixup, |
562 | .tx_fixup = rndis_tx_fixup, | 562 | .tx_fixup = rndis_tx_fixup, |
563 | }; | 563 | }; |
564 | 564 | ||
565 | #undef ccpu2 | 565 | #undef ccpu2 |
566 | 566 | ||
567 | 567 | ||
568 | /*-------------------------------------------------------------------------*/ | 568 | /*-------------------------------------------------------------------------*/ |
569 | 569 | ||
570 | static const struct usb_device_id products [] = { | 570 | static const struct usb_device_id products [] = { |
571 | { | 571 | { |
572 | /* RNDIS is MSFT's un-official variant of CDC ACM */ | 572 | /* RNDIS is MSFT's un-official variant of CDC ACM */ |
573 | USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), | 573 | USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff), |
574 | .driver_info = (unsigned long) &rndis_info, | 574 | .driver_info = (unsigned long) &rndis_info, |
575 | }, { | 575 | }, { |
576 | /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ | 576 | /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */ |
577 | USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), | 577 | USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1), |
578 | .driver_info = (unsigned long) &rndis_info, | 578 | .driver_info = (unsigned long) &rndis_info, |
579 | }, { | ||
580 | /* RNDIS for tethering */ | ||
581 | USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3), | ||
582 | .driver_info = (unsigned long) &rndis_info, | ||
579 | }, | 583 | }, |
580 | { }, // END | 584 | { }, // END |
581 | }; | 585 | }; |
582 | MODULE_DEVICE_TABLE(usb, products); | 586 | MODULE_DEVICE_TABLE(usb, products); |
583 | 587 | ||
584 | static struct usb_driver rndis_driver = { | 588 | static struct usb_driver rndis_driver = { |
585 | .name = "rndis_host", | 589 | .name = "rndis_host", |
586 | .id_table = products, | 590 | .id_table = products, |
587 | .probe = usbnet_probe, | 591 | .probe = usbnet_probe, |
588 | .disconnect = usbnet_disconnect, | 592 | .disconnect = usbnet_disconnect, |
589 | .suspend = usbnet_suspend, | 593 | .suspend = usbnet_suspend, |
590 | .resume = usbnet_resume, | 594 | .resume = usbnet_resume, |
591 | }; | 595 | }; |
592 | 596 | ||
593 | static int __init rndis_init(void) | 597 | static int __init rndis_init(void) |
594 | { | 598 | { |
595 | return usb_register(&rndis_driver); | 599 | return usb_register(&rndis_driver); |
596 | } | 600 | } |
597 | module_init(rndis_init); | 601 | module_init(rndis_init); |
598 | 602 | ||
599 | static void __exit rndis_exit(void) | 603 | static void __exit rndis_exit(void) |
600 | { | 604 | { |
601 | usb_deregister(&rndis_driver); | 605 | usb_deregister(&rndis_driver); |
602 | } | 606 | } |
603 | module_exit(rndis_exit); | 607 | module_exit(rndis_exit); |
604 | 608 | ||
605 | MODULE_AUTHOR("David Brownell"); | 609 | MODULE_AUTHOR("David Brownell"); |
606 | MODULE_DESCRIPTION("USB Host side RNDIS driver"); | 610 | MODULE_DESCRIPTION("USB Host side RNDIS driver"); |
607 | MODULE_LICENSE("GPL"); | 611 | MODULE_LICENSE("GPL"); |
608 | 612 |