Commit | Line | Data |
---|---|---|
da741b8c DB |
1 | /* |
2 | * f_ecm.c -- USB CDC Ethernet (ECM) link function driver | |
3 | * | |
4 | * Copyright (C) 2003-2005,2008 David Brownell | |
5 | * Copyright (C) 2008 Nokia Corporation | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | */ | |
21 | ||
22 | /* #define VERBOSE_DEBUG */ | |
23 | ||
24 | #include <linux/kernel.h> | |
25 | #include <linux/device.h> | |
26 | #include <linux/etherdevice.h> | |
27 | ||
28 | #include "u_ether.h" | |
29 | ||
30 | ||
31 | /* | |
32 | * This function is a "CDC Ethernet Networking Control Model" (CDC ECM) | |
33 | * Ethernet link. The data transfer model is simple (packets sent and | |
34 | * received over bulk endpoints using normal short packet termination), | |
35 | * and the control model exposes various data and optional notifications. | |
36 | * | |
37 | * ECM is well standardized and (except for Microsoft) supported by most | |
38 | * operating systems with USB host support. It's the preferred interop | |
39 | * solution for Ethernet over USB, at least for firmware based solutions. | |
40 | * (Hardware solutions tend to be more minimalist.) A newer and simpler | |
41 | * "Ethernet Emulation Model" (CDC EEM) hasn't yet caught on. | |
42 | * | |
43 | * Note that ECM requires the use of "alternate settings" for its data | |
44 | * interface. This means that the set_alt() method has real work to do, | |
45 | * and also means that a get_alt() method is required. | |
46 | */ | |
47 | ||
48 | struct ecm_ep_descs { | |
49 | struct usb_endpoint_descriptor *in; | |
50 | struct usb_endpoint_descriptor *out; | |
51 | struct usb_endpoint_descriptor *notify; | |
52 | }; | |
53 | ||
54 | enum ecm_notify_state { | |
55 | ECM_NOTIFY_NONE, /* don't notify */ | |
56 | ECM_NOTIFY_CONNECT, /* issue CONNECT next */ | |
57 | ECM_NOTIFY_SPEED, /* issue SPEED_CHANGE next */ | |
58 | }; | |
59 | ||
60 | struct f_ecm { | |
61 | struct gether port; | |
62 | u8 ctrl_id, data_id; | |
63 | ||
64 | char ethaddr[14]; | |
65 | ||
da741b8c | 66 | struct ecm_ep_descs fs; |
da741b8c DB |
67 | struct ecm_ep_descs hs; |
68 | ||
69 | struct usb_ep *notify; | |
70 | struct usb_endpoint_descriptor *notify_desc; | |
71 | struct usb_request *notify_req; | |
72 | u8 notify_state; | |
73 | bool is_open; | |
74 | ||
75 | /* FIXME is_open needs some irq-ish locking | |
76 | * ... possibly the same as port.ioport | |
77 | */ | |
78 | }; | |
79 | ||
80 | static inline struct f_ecm *func_to_ecm(struct usb_function *f) | |
81 | { | |
82 | return container_of(f, struct f_ecm, port.func); | |
83 | } | |
84 | ||
85 | /* peak (theoretical) bulk transfer rate in bits-per-second */ | |
33376c1c | 86 | static inline unsigned ecm_bitrate(struct usb_gadget *g) |
da741b8c DB |
87 | { |
88 | if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) | |
89 | return 13 * 512 * 8 * 1000 * 8; | |
90 | else | |
91 | return 19 * 64 * 1 * 1000 * 8; | |
92 | } | |
93 | ||
94 | /*-------------------------------------------------------------------------*/ | |
95 | ||
96 | /* | |
97 | * Include the status endpoint if we can, even though it's optional. | |
98 | * | |
99 | * Use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one | |
100 | * packet, to simplify cancellation; and a big transfer interval, to | |
101 | * waste less bandwidth. | |
102 | * | |
103 | * Some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even | |
104 | * if they ignore the connect/disconnect notifications that real aether | |
105 | * can provide. More advanced cdc configurations might want to support | |
106 | * encapsulated commands (vendor-specific, using control-OUT). | |
107 | */ | |
108 | ||
109 | #define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ | |
33376c1c | 110 | #define ECM_STATUS_BYTECOUNT 16 /* 8 byte header + data */ |
da741b8c DB |
111 | |
112 | ||
113 | /* interface descriptor: */ | |
114 | ||
115 | static struct usb_interface_descriptor ecm_control_intf __initdata = { | |
116 | .bLength = sizeof ecm_control_intf, | |
117 | .bDescriptorType = USB_DT_INTERFACE, | |
118 | ||
119 | /* .bInterfaceNumber = DYNAMIC */ | |
120 | /* status endpoint is optional; this could be patched later */ | |
121 | .bNumEndpoints = 1, | |
122 | .bInterfaceClass = USB_CLASS_COMM, | |
123 | .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, | |
124 | .bInterfaceProtocol = USB_CDC_PROTO_NONE, | |
125 | /* .iInterface = DYNAMIC */ | |
126 | }; | |
127 | ||
33376c1c DB |
128 | static struct usb_cdc_header_desc ecm_header_desc __initdata = { |
129 | .bLength = sizeof ecm_header_desc, | |
da741b8c DB |
130 | .bDescriptorType = USB_DT_CS_INTERFACE, |
131 | .bDescriptorSubType = USB_CDC_HEADER_TYPE, | |
132 | ||
551509d2 | 133 | .bcdCDC = cpu_to_le16(0x0110), |
da741b8c DB |
134 | }; |
135 | ||
136 | static struct usb_cdc_union_desc ecm_union_desc __initdata = { | |
137 | .bLength = sizeof(ecm_union_desc), | |
138 | .bDescriptorType = USB_DT_CS_INTERFACE, | |
139 | .bDescriptorSubType = USB_CDC_UNION_TYPE, | |
140 | /* .bMasterInterface0 = DYNAMIC */ | |
141 | /* .bSlaveInterface0 = DYNAMIC */ | |
142 | }; | |
143 | ||
33376c1c DB |
144 | static struct usb_cdc_ether_desc ecm_desc __initdata = { |
145 | .bLength = sizeof ecm_desc, | |
da741b8c DB |
146 | .bDescriptorType = USB_DT_CS_INTERFACE, |
147 | .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, | |
148 | ||
149 | /* this descriptor actually adds value, surprise! */ | |
150 | /* .iMACAddress = DYNAMIC */ | |
551509d2 HH |
151 | .bmEthernetStatistics = cpu_to_le32(0), /* no statistics */ |
152 | .wMaxSegmentSize = cpu_to_le16(ETH_FRAME_LEN), | |
153 | .wNumberMCFilters = cpu_to_le16(0), | |
da741b8c DB |
154 | .bNumberPowerFilters = 0, |
155 | }; | |
156 | ||
157 | /* the default data interface has no endpoints ... */ | |
158 | ||
159 | static struct usb_interface_descriptor ecm_data_nop_intf __initdata = { | |
160 | .bLength = sizeof ecm_data_nop_intf, | |
161 | .bDescriptorType = USB_DT_INTERFACE, | |
162 | ||
163 | .bInterfaceNumber = 1, | |
164 | .bAlternateSetting = 0, | |
165 | .bNumEndpoints = 0, | |
166 | .bInterfaceClass = USB_CLASS_CDC_DATA, | |
167 | .bInterfaceSubClass = 0, | |
168 | .bInterfaceProtocol = 0, | |
169 | /* .iInterface = DYNAMIC */ | |
170 | }; | |
171 | ||
172 | /* ... but the "real" data interface has two bulk endpoints */ | |
173 | ||
174 | static struct usb_interface_descriptor ecm_data_intf __initdata = { | |
175 | .bLength = sizeof ecm_data_intf, | |
176 | .bDescriptorType = USB_DT_INTERFACE, | |
177 | ||
178 | .bInterfaceNumber = 1, | |
179 | .bAlternateSetting = 1, | |
180 | .bNumEndpoints = 2, | |
181 | .bInterfaceClass = USB_CLASS_CDC_DATA, | |
182 | .bInterfaceSubClass = 0, | |
183 | .bInterfaceProtocol = 0, | |
184 | /* .iInterface = DYNAMIC */ | |
185 | }; | |
186 | ||
187 | /* full speed support: */ | |
188 | ||
33376c1c | 189 | static struct usb_endpoint_descriptor fs_ecm_notify_desc __initdata = { |
da741b8c DB |
190 | .bLength = USB_DT_ENDPOINT_SIZE, |
191 | .bDescriptorType = USB_DT_ENDPOINT, | |
192 | ||
193 | .bEndpointAddress = USB_DIR_IN, | |
194 | .bmAttributes = USB_ENDPOINT_XFER_INT, | |
551509d2 | 195 | .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), |
da741b8c DB |
196 | .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, |
197 | }; | |
198 | ||
33376c1c | 199 | static struct usb_endpoint_descriptor fs_ecm_in_desc __initdata = { |
da741b8c DB |
200 | .bLength = USB_DT_ENDPOINT_SIZE, |
201 | .bDescriptorType = USB_DT_ENDPOINT, | |
202 | ||
203 | .bEndpointAddress = USB_DIR_IN, | |
204 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | |
205 | }; | |
206 | ||
33376c1c | 207 | static struct usb_endpoint_descriptor fs_ecm_out_desc __initdata = { |
da741b8c DB |
208 | .bLength = USB_DT_ENDPOINT_SIZE, |
209 | .bDescriptorType = USB_DT_ENDPOINT, | |
210 | ||
211 | .bEndpointAddress = USB_DIR_OUT, | |
212 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | |
213 | }; | |
214 | ||
33376c1c | 215 | static struct usb_descriptor_header *ecm_fs_function[] __initdata = { |
da741b8c DB |
216 | /* CDC ECM control descriptors */ |
217 | (struct usb_descriptor_header *) &ecm_control_intf, | |
33376c1c | 218 | (struct usb_descriptor_header *) &ecm_header_desc, |
da741b8c | 219 | (struct usb_descriptor_header *) &ecm_union_desc, |
33376c1c | 220 | (struct usb_descriptor_header *) &ecm_desc, |
da741b8c | 221 | /* NOTE: status endpoint might need to be removed */ |
33376c1c | 222 | (struct usb_descriptor_header *) &fs_ecm_notify_desc, |
da741b8c DB |
223 | /* data interface, altsettings 0 and 1 */ |
224 | (struct usb_descriptor_header *) &ecm_data_nop_intf, | |
225 | (struct usb_descriptor_header *) &ecm_data_intf, | |
33376c1c DB |
226 | (struct usb_descriptor_header *) &fs_ecm_in_desc, |
227 | (struct usb_descriptor_header *) &fs_ecm_out_desc, | |
da741b8c DB |
228 | NULL, |
229 | }; | |
230 | ||
231 | /* high speed support: */ | |
232 | ||
33376c1c | 233 | static struct usb_endpoint_descriptor hs_ecm_notify_desc __initdata = { |
da741b8c DB |
234 | .bLength = USB_DT_ENDPOINT_SIZE, |
235 | .bDescriptorType = USB_DT_ENDPOINT, | |
236 | ||
237 | .bEndpointAddress = USB_DIR_IN, | |
238 | .bmAttributes = USB_ENDPOINT_XFER_INT, | |
551509d2 | 239 | .wMaxPacketSize = cpu_to_le16(ECM_STATUS_BYTECOUNT), |
da741b8c DB |
240 | .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, |
241 | }; | |
33376c1c | 242 | static struct usb_endpoint_descriptor hs_ecm_in_desc __initdata = { |
da741b8c DB |
243 | .bLength = USB_DT_ENDPOINT_SIZE, |
244 | .bDescriptorType = USB_DT_ENDPOINT, | |
245 | ||
246 | .bEndpointAddress = USB_DIR_IN, | |
247 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | |
551509d2 | 248 | .wMaxPacketSize = cpu_to_le16(512), |
da741b8c DB |
249 | }; |
250 | ||
33376c1c | 251 | static struct usb_endpoint_descriptor hs_ecm_out_desc __initdata = { |
da741b8c DB |
252 | .bLength = USB_DT_ENDPOINT_SIZE, |
253 | .bDescriptorType = USB_DT_ENDPOINT, | |
254 | ||
255 | .bEndpointAddress = USB_DIR_OUT, | |
256 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | |
551509d2 | 257 | .wMaxPacketSize = cpu_to_le16(512), |
da741b8c DB |
258 | }; |
259 | ||
33376c1c | 260 | static struct usb_descriptor_header *ecm_hs_function[] __initdata = { |
da741b8c DB |
261 | /* CDC ECM control descriptors */ |
262 | (struct usb_descriptor_header *) &ecm_control_intf, | |
33376c1c | 263 | (struct usb_descriptor_header *) &ecm_header_desc, |
da741b8c | 264 | (struct usb_descriptor_header *) &ecm_union_desc, |
33376c1c | 265 | (struct usb_descriptor_header *) &ecm_desc, |
da741b8c | 266 | /* NOTE: status endpoint might need to be removed */ |
33376c1c | 267 | (struct usb_descriptor_header *) &hs_ecm_notify_desc, |
da741b8c DB |
268 | /* data interface, altsettings 0 and 1 */ |
269 | (struct usb_descriptor_header *) &ecm_data_nop_intf, | |
270 | (struct usb_descriptor_header *) &ecm_data_intf, | |
33376c1c DB |
271 | (struct usb_descriptor_header *) &hs_ecm_in_desc, |
272 | (struct usb_descriptor_header *) &hs_ecm_out_desc, | |
da741b8c DB |
273 | NULL, |
274 | }; | |
275 | ||
276 | /* string descriptors: */ | |
277 | ||
278 | static struct usb_string ecm_string_defs[] = { | |
279 | [0].s = "CDC Ethernet Control Model (ECM)", | |
280 | [1].s = NULL /* DYNAMIC */, | |
281 | [2].s = "CDC Ethernet Data", | |
282 | { } /* end of list */ | |
283 | }; | |
284 | ||
285 | static struct usb_gadget_strings ecm_string_table = { | |
286 | .language = 0x0409, /* en-us */ | |
287 | .strings = ecm_string_defs, | |
288 | }; | |
289 | ||
290 | static struct usb_gadget_strings *ecm_strings[] = { | |
291 | &ecm_string_table, | |
292 | NULL, | |
293 | }; | |
294 | ||
295 | /*-------------------------------------------------------------------------*/ | |
296 | ||
297 | static void ecm_do_notify(struct f_ecm *ecm) | |
298 | { | |
299 | struct usb_request *req = ecm->notify_req; | |
300 | struct usb_cdc_notification *event; | |
301 | struct usb_composite_dev *cdev = ecm->port.func.config->cdev; | |
302 | __le32 *data; | |
303 | int status; | |
304 | ||
305 | /* notification already in flight? */ | |
306 | if (!req) | |
307 | return; | |
308 | ||
309 | event = req->buf; | |
310 | switch (ecm->notify_state) { | |
311 | case ECM_NOTIFY_NONE: | |
312 | return; | |
313 | ||
314 | case ECM_NOTIFY_CONNECT: | |
315 | event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION; | |
316 | if (ecm->is_open) | |
317 | event->wValue = cpu_to_le16(1); | |
318 | else | |
319 | event->wValue = cpu_to_le16(0); | |
320 | event->wLength = 0; | |
321 | req->length = sizeof *event; | |
322 | ||
323 | DBG(cdev, "notify connect %s\n", | |
324 | ecm->is_open ? "true" : "false"); | |
325 | ecm->notify_state = ECM_NOTIFY_SPEED; | |
326 | break; | |
327 | ||
328 | case ECM_NOTIFY_SPEED: | |
329 | event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE; | |
330 | event->wValue = cpu_to_le16(0); | |
331 | event->wLength = cpu_to_le16(8); | |
33376c1c | 332 | req->length = ECM_STATUS_BYTECOUNT; |
da741b8c DB |
333 | |
334 | /* SPEED_CHANGE data is up/down speeds in bits/sec */ | |
335 | data = req->buf + sizeof *event; | |
33376c1c | 336 | data[0] = cpu_to_le32(ecm_bitrate(cdev->gadget)); |
da741b8c DB |
337 | data[1] = data[0]; |
338 | ||
33376c1c | 339 | DBG(cdev, "notify speed %d\n", ecm_bitrate(cdev->gadget)); |
da741b8c DB |
340 | ecm->notify_state = ECM_NOTIFY_NONE; |
341 | break; | |
342 | } | |
343 | event->bmRequestType = 0xA1; | |
344 | event->wIndex = cpu_to_le16(ecm->ctrl_id); | |
345 | ||
346 | ecm->notify_req = NULL; | |
347 | status = usb_ep_queue(ecm->notify, req, GFP_ATOMIC); | |
348 | if (status < 0) { | |
349 | ecm->notify_req = req; | |
350 | DBG(cdev, "notify --> %d\n", status); | |
351 | } | |
352 | } | |
353 | ||
354 | static void ecm_notify(struct f_ecm *ecm) | |
355 | { | |
356 | /* NOTE on most versions of Linux, host side cdc-ethernet | |
357 | * won't listen for notifications until its netdevice opens. | |
358 | * The first notification then sits in the FIFO for a long | |
359 | * time, and the second one is queued. | |
360 | */ | |
361 | ecm->notify_state = ECM_NOTIFY_CONNECT; | |
362 | ecm_do_notify(ecm); | |
363 | } | |
364 | ||
365 | static void ecm_notify_complete(struct usb_ep *ep, struct usb_request *req) | |
366 | { | |
367 | struct f_ecm *ecm = req->context; | |
368 | struct usb_composite_dev *cdev = ecm->port.func.config->cdev; | |
369 | struct usb_cdc_notification *event = req->buf; | |
370 | ||
371 | switch (req->status) { | |
372 | case 0: | |
373 | /* no fault */ | |
374 | break; | |
375 | case -ECONNRESET: | |
376 | case -ESHUTDOWN: | |
377 | ecm->notify_state = ECM_NOTIFY_NONE; | |
378 | break; | |
379 | default: | |
380 | DBG(cdev, "event %02x --> %d\n", | |
381 | event->bNotificationType, req->status); | |
382 | break; | |
383 | } | |
384 | ecm->notify_req = req; | |
385 | ecm_do_notify(ecm); | |
386 | } | |
387 | ||
388 | static int ecm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | |
389 | { | |
390 | struct f_ecm *ecm = func_to_ecm(f); | |
391 | struct usb_composite_dev *cdev = f->config->cdev; | |
392 | struct usb_request *req = cdev->req; | |
393 | int value = -EOPNOTSUPP; | |
394 | u16 w_index = le16_to_cpu(ctrl->wIndex); | |
395 | u16 w_value = le16_to_cpu(ctrl->wValue); | |
396 | u16 w_length = le16_to_cpu(ctrl->wLength); | |
397 | ||
398 | /* composite driver infrastructure handles everything except | |
399 | * CDC class messages; interface activation uses set_alt(). | |
400 | */ | |
401 | switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { | |
402 | case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) | |
403 | | USB_CDC_SET_ETHERNET_PACKET_FILTER: | |
404 | /* see 6.2.30: no data, wIndex = interface, | |
405 | * wValue = packet filter bitmap | |
406 | */ | |
407 | if (w_length != 0 || w_index != ecm->ctrl_id) | |
408 | goto invalid; | |
409 | DBG(cdev, "packet filter %02x\n", w_value); | |
410 | /* REVISIT locking of cdc_filter. This assumes the UDC | |
411 | * driver won't have a concurrent packet TX irq running on | |
412 | * another CPU; or that if it does, this write is atomic... | |
413 | */ | |
414 | ecm->port.cdc_filter = w_value; | |
415 | value = 0; | |
416 | break; | |
417 | ||
418 | /* and optionally: | |
419 | * case USB_CDC_SEND_ENCAPSULATED_COMMAND: | |
420 | * case USB_CDC_GET_ENCAPSULATED_RESPONSE: | |
421 | * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS: | |
422 | * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER: | |
423 | * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER: | |
424 | * case USB_CDC_GET_ETHERNET_STATISTIC: | |
425 | */ | |
426 | ||
427 | default: | |
428 | invalid: | |
429 | DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n", | |
430 | ctrl->bRequestType, ctrl->bRequest, | |
431 | w_value, w_index, w_length); | |
432 | } | |
433 | ||
434 | /* respond with data transfer or status phase? */ | |
435 | if (value >= 0) { | |
436 | DBG(cdev, "ecm req%02x.%02x v%04x i%04x l%d\n", | |
437 | ctrl->bRequestType, ctrl->bRequest, | |
438 | w_value, w_index, w_length); | |
439 | req->zero = 0; | |
440 | req->length = value; | |
441 | value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC); | |
442 | if (value < 0) | |
443 | ERROR(cdev, "ecm req %02x.%02x response err %d\n", | |
444 | ctrl->bRequestType, ctrl->bRequest, | |
445 | value); | |
446 | } | |
447 | ||
448 | /* device either stalls (value < 0) or reports success */ | |
449 | return value; | |
450 | } | |
451 | ||
452 | ||
453 | static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt) | |
454 | { | |
455 | struct f_ecm *ecm = func_to_ecm(f); | |
456 | struct usb_composite_dev *cdev = f->config->cdev; | |
457 | ||
458 | /* Control interface has only altsetting 0 */ | |
459 | if (intf == ecm->ctrl_id) { | |
460 | if (alt != 0) | |
461 | goto fail; | |
462 | ||
463 | if (ecm->notify->driver_data) { | |
464 | VDBG(cdev, "reset ecm control %d\n", intf); | |
465 | usb_ep_disable(ecm->notify); | |
466 | } else { | |
467 | VDBG(cdev, "init ecm ctrl %d\n", intf); | |
468 | ecm->notify_desc = ep_choose(cdev->gadget, | |
469 | ecm->hs.notify, | |
470 | ecm->fs.notify); | |
471 | } | |
472 | usb_ep_enable(ecm->notify, ecm->notify_desc); | |
473 | ecm->notify->driver_data = ecm; | |
474 | ||
475 | /* Data interface has two altsettings, 0 and 1 */ | |
476 | } else if (intf == ecm->data_id) { | |
477 | if (alt > 1) | |
478 | goto fail; | |
479 | ||
480 | if (ecm->port.in_ep->driver_data) { | |
481 | DBG(cdev, "reset ecm\n"); | |
482 | gether_disconnect(&ecm->port); | |
483 | } | |
484 | ||
485 | if (!ecm->port.in) { | |
486 | DBG(cdev, "init ecm\n"); | |
487 | ecm->port.in = ep_choose(cdev->gadget, | |
488 | ecm->hs.in, ecm->fs.in); | |
489 | ecm->port.out = ep_choose(cdev->gadget, | |
490 | ecm->hs.out, ecm->fs.out); | |
491 | } | |
492 | ||
493 | /* CDC Ethernet only sends data in non-default altsettings. | |
494 | * Changing altsettings resets filters, statistics, etc. | |
495 | */ | |
496 | if (alt == 1) { | |
497 | struct net_device *net; | |
498 | ||
499 | /* Enable zlps by default for ECM conformance; | |
90f79768 | 500 | * override for musb_hdrc (avoids txdma ovhead). |
da741b8c | 501 | */ |
90f79768 | 502 | ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget) |
da741b8c DB |
503 | ); |
504 | ecm->port.cdc_filter = DEFAULT_FILTER; | |
505 | DBG(cdev, "activate ecm\n"); | |
506 | net = gether_connect(&ecm->port); | |
507 | if (IS_ERR(net)) | |
508 | return PTR_ERR(net); | |
509 | } | |
510 | ||
511 | /* NOTE this can be a minor disagreement with the ECM spec, | |
512 | * which says speed notifications will "always" follow | |
513 | * connection notifications. But we allow one connect to | |
514 | * follow another (if the first is in flight), and instead | |
515 | * just guarantee that a speed notification is always sent. | |
516 | */ | |
517 | ecm_notify(ecm); | |
518 | } else | |
519 | goto fail; | |
520 | ||
521 | return 0; | |
522 | fail: | |
523 | return -EINVAL; | |
524 | } | |
525 | ||
526 | /* Because the data interface supports multiple altsettings, | |
527 | * this ECM function *MUST* implement a get_alt() method. | |
528 | */ | |
529 | static int ecm_get_alt(struct usb_function *f, unsigned intf) | |
530 | { | |
531 | struct f_ecm *ecm = func_to_ecm(f); | |
532 | ||
533 | if (intf == ecm->ctrl_id) | |
534 | return 0; | |
535 | return ecm->port.in_ep->driver_data ? 1 : 0; | |
536 | } | |
537 | ||
538 | static void ecm_disable(struct usb_function *f) | |
539 | { | |
540 | struct f_ecm *ecm = func_to_ecm(f); | |
541 | struct usb_composite_dev *cdev = f->config->cdev; | |
542 | ||
543 | DBG(cdev, "ecm deactivated\n"); | |
544 | ||
545 | if (ecm->port.in_ep->driver_data) | |
546 | gether_disconnect(&ecm->port); | |
547 | ||
548 | if (ecm->notify->driver_data) { | |
549 | usb_ep_disable(ecm->notify); | |
550 | ecm->notify->driver_data = NULL; | |
551 | ecm->notify_desc = NULL; | |
552 | } | |
553 | } | |
554 | ||
555 | /*-------------------------------------------------------------------------*/ | |
556 | ||
557 | /* | |
558 | * Callbacks let us notify the host about connect/disconnect when the | |
559 | * net device is opened or closed. | |
560 | * | |
561 | * For testing, note that link states on this side include both opened | |
562 | * and closed variants of: | |
563 | * | |
564 | * - disconnected/unconfigured | |
565 | * - configured but inactive (data alt 0) | |
566 | * - configured and active (data alt 1) | |
567 | * | |
568 | * Each needs to be tested with unplug, rmmod, SET_CONFIGURATION, and | |
569 | * SET_INTERFACE (altsetting). Remember also that "configured" doesn't | |
570 | * imply the host is actually polling the notification endpoint, and | |
571 | * likewise that "active" doesn't imply it's actually using the data | |
572 | * endpoints for traffic. | |
573 | */ | |
574 | ||
575 | static void ecm_open(struct gether *geth) | |
576 | { | |
577 | struct f_ecm *ecm = func_to_ecm(&geth->func); | |
578 | ||
579 | DBG(ecm->port.func.config->cdev, "%s\n", __func__); | |
580 | ||
581 | ecm->is_open = true; | |
582 | ecm_notify(ecm); | |
583 | } | |
584 | ||
585 | static void ecm_close(struct gether *geth) | |
586 | { | |
587 | struct f_ecm *ecm = func_to_ecm(&geth->func); | |
588 | ||
589 | DBG(ecm->port.func.config->cdev, "%s\n", __func__); | |
590 | ||
591 | ecm->is_open = false; | |
592 | ecm_notify(ecm); | |
593 | } | |
594 | ||
595 | /*-------------------------------------------------------------------------*/ | |
596 | ||
597 | /* ethernet function driver setup/binding */ | |
598 | ||
599 | static int __init | |
600 | ecm_bind(struct usb_configuration *c, struct usb_function *f) | |
601 | { | |
602 | struct usb_composite_dev *cdev = c->cdev; | |
603 | struct f_ecm *ecm = func_to_ecm(f); | |
604 | int status; | |
605 | struct usb_ep *ep; | |
606 | ||
607 | /* allocate instance-specific interface IDs */ | |
608 | status = usb_interface_id(c, f); | |
609 | if (status < 0) | |
610 | goto fail; | |
611 | ecm->ctrl_id = status; | |
612 | ||
613 | ecm_control_intf.bInterfaceNumber = status; | |
614 | ecm_union_desc.bMasterInterface0 = status; | |
615 | ||
616 | status = usb_interface_id(c, f); | |
617 | if (status < 0) | |
618 | goto fail; | |
619 | ecm->data_id = status; | |
620 | ||
621 | ecm_data_nop_intf.bInterfaceNumber = status; | |
622 | ecm_data_intf.bInterfaceNumber = status; | |
623 | ecm_union_desc.bSlaveInterface0 = status; | |
624 | ||
625 | status = -ENODEV; | |
626 | ||
627 | /* allocate instance-specific endpoints */ | |
33376c1c | 628 | ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_in_desc); |
da741b8c DB |
629 | if (!ep) |
630 | goto fail; | |
631 | ecm->port.in_ep = ep; | |
632 | ep->driver_data = cdev; /* claim */ | |
633 | ||
33376c1c | 634 | ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc); |
da741b8c DB |
635 | if (!ep) |
636 | goto fail; | |
637 | ecm->port.out_ep = ep; | |
638 | ep->driver_data = cdev; /* claim */ | |
639 | ||
640 | /* NOTE: a status/notification endpoint is *OPTIONAL* but we | |
641 | * don't treat it that way. It's simpler, and some newer CDC | |
642 | * profiles (wireless handsets) no longer treat it as optional. | |
643 | */ | |
33376c1c | 644 | ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_notify_desc); |
da741b8c DB |
645 | if (!ep) |
646 | goto fail; | |
647 | ecm->notify = ep; | |
648 | ep->driver_data = cdev; /* claim */ | |
649 | ||
650 | status = -ENOMEM; | |
651 | ||
652 | /* allocate notification request and buffer */ | |
653 | ecm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL); | |
654 | if (!ecm->notify_req) | |
655 | goto fail; | |
33376c1c | 656 | ecm->notify_req->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL); |
da741b8c DB |
657 | if (!ecm->notify_req->buf) |
658 | goto fail; | |
659 | ecm->notify_req->context = ecm; | |
660 | ecm->notify_req->complete = ecm_notify_complete; | |
661 | ||
662 | /* copy descriptors, and track endpoint copies */ | |
33376c1c | 663 | f->descriptors = usb_copy_descriptors(ecm_fs_function); |
da741b8c DB |
664 | if (!f->descriptors) |
665 | goto fail; | |
666 | ||
33376c1c DB |
667 | ecm->fs.in = usb_find_endpoint(ecm_fs_function, |
668 | f->descriptors, &fs_ecm_in_desc); | |
669 | ecm->fs.out = usb_find_endpoint(ecm_fs_function, | |
670 | f->descriptors, &fs_ecm_out_desc); | |
671 | ecm->fs.notify = usb_find_endpoint(ecm_fs_function, | |
672 | f->descriptors, &fs_ecm_notify_desc); | |
da741b8c DB |
673 | |
674 | /* support all relevant hardware speeds... we expect that when | |
675 | * hardware is dual speed, all bulk-capable endpoints work at | |
676 | * both speeds | |
677 | */ | |
678 | if (gadget_is_dualspeed(c->cdev->gadget)) { | |
33376c1c DB |
679 | hs_ecm_in_desc.bEndpointAddress = |
680 | fs_ecm_in_desc.bEndpointAddress; | |
681 | hs_ecm_out_desc.bEndpointAddress = | |
682 | fs_ecm_out_desc.bEndpointAddress; | |
683 | hs_ecm_notify_desc.bEndpointAddress = | |
684 | fs_ecm_notify_desc.bEndpointAddress; | |
da741b8c DB |
685 | |
686 | /* copy descriptors, and track endpoint copies */ | |
33376c1c | 687 | f->hs_descriptors = usb_copy_descriptors(ecm_hs_function); |
da741b8c DB |
688 | if (!f->hs_descriptors) |
689 | goto fail; | |
690 | ||
33376c1c DB |
691 | ecm->hs.in = usb_find_endpoint(ecm_hs_function, |
692 | f->hs_descriptors, &hs_ecm_in_desc); | |
693 | ecm->hs.out = usb_find_endpoint(ecm_hs_function, | |
694 | f->hs_descriptors, &hs_ecm_out_desc); | |
695 | ecm->hs.notify = usb_find_endpoint(ecm_hs_function, | |
696 | f->hs_descriptors, &hs_ecm_notify_desc); | |
da741b8c DB |
697 | } |
698 | ||
699 | /* NOTE: all that is done without knowing or caring about | |
700 | * the network link ... which is unavailable to this code | |
701 | * until we're activated via set_alt(). | |
702 | */ | |
703 | ||
704 | ecm->port.open = ecm_open; | |
705 | ecm->port.close = ecm_close; | |
706 | ||
707 | DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", | |
708 | gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", | |
709 | ecm->port.in_ep->name, ecm->port.out_ep->name, | |
710 | ecm->notify->name); | |
711 | return 0; | |
712 | ||
713 | fail: | |
714 | if (f->descriptors) | |
715 | usb_free_descriptors(f->descriptors); | |
716 | ||
717 | if (ecm->notify_req) { | |
718 | kfree(ecm->notify_req->buf); | |
719 | usb_ep_free_request(ecm->notify, ecm->notify_req); | |
720 | } | |
721 | ||
722 | /* we might as well release our claims on endpoints */ | |
723 | if (ecm->notify) | |
724 | ecm->notify->driver_data = NULL; | |
725 | if (ecm->port.out) | |
726 | ecm->port.out_ep->driver_data = NULL; | |
727 | if (ecm->port.in) | |
728 | ecm->port.in_ep->driver_data = NULL; | |
729 | ||
730 | ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); | |
731 | ||
732 | return status; | |
733 | } | |
734 | ||
735 | static void | |
736 | ecm_unbind(struct usb_configuration *c, struct usb_function *f) | |
737 | { | |
738 | struct f_ecm *ecm = func_to_ecm(f); | |
739 | ||
740 | DBG(c->cdev, "ecm unbind\n"); | |
741 | ||
742 | if (gadget_is_dualspeed(c->cdev->gadget)) | |
743 | usb_free_descriptors(f->hs_descriptors); | |
744 | usb_free_descriptors(f->descriptors); | |
745 | ||
746 | kfree(ecm->notify_req->buf); | |
747 | usb_ep_free_request(ecm->notify, ecm->notify_req); | |
748 | ||
749 | ecm_string_defs[1].s = NULL; | |
750 | kfree(ecm); | |
751 | } | |
752 | ||
753 | /** | |
754 | * ecm_bind_config - add CDC Ethernet network link to a configuration | |
755 | * @c: the configuration to support the network link | |
756 | * @ethaddr: a buffer in which the ethernet address of the host side | |
757 | * side of the link was recorded | |
758 | * Context: single threaded during gadget setup | |
759 | * | |
760 | * Returns zero on success, else negative errno. | |
761 | * | |
762 | * Caller must have called @gether_setup(). Caller is also responsible | |
763 | * for calling @gether_cleanup() before module unload. | |
764 | */ | |
765 | int __init ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) | |
766 | { | |
767 | struct f_ecm *ecm; | |
768 | int status; | |
769 | ||
770 | if (!can_support_ecm(c->cdev->gadget) || !ethaddr) | |
771 | return -EINVAL; | |
772 | ||
773 | /* maybe allocate device-global string IDs */ | |
774 | if (ecm_string_defs[0].id == 0) { | |
775 | ||
776 | /* control interface label */ | |
777 | status = usb_string_id(c->cdev); | |
778 | if (status < 0) | |
779 | return status; | |
780 | ecm_string_defs[0].id = status; | |
781 | ecm_control_intf.iInterface = status; | |
782 | ||
783 | /* data interface label */ | |
784 | status = usb_string_id(c->cdev); | |
785 | if (status < 0) | |
786 | return status; | |
787 | ecm_string_defs[2].id = status; | |
788 | ecm_data_intf.iInterface = status; | |
789 | ||
790 | /* MAC address */ | |
791 | status = usb_string_id(c->cdev); | |
792 | if (status < 0) | |
793 | return status; | |
794 | ecm_string_defs[1].id = status; | |
33376c1c | 795 | ecm_desc.iMACAddress = status; |
da741b8c DB |
796 | } |
797 | ||
798 | /* allocate and initialize one new instance */ | |
799 | ecm = kzalloc(sizeof *ecm, GFP_KERNEL); | |
800 | if (!ecm) | |
801 | return -ENOMEM; | |
802 | ||
803 | /* export host's Ethernet address in CDC format */ | |
804 | snprintf(ecm->ethaddr, sizeof ecm->ethaddr, | |
805 | "%02X%02X%02X%02X%02X%02X", | |
806 | ethaddr[0], ethaddr[1], ethaddr[2], | |
807 | ethaddr[3], ethaddr[4], ethaddr[5]); | |
808 | ecm_string_defs[1].s = ecm->ethaddr; | |
809 | ||
810 | ecm->port.cdc_filter = DEFAULT_FILTER; | |
811 | ||
812 | ecm->port.func.name = "cdc_ethernet"; | |
813 | ecm->port.func.strings = ecm_strings; | |
814 | /* descriptors are per-instance copies */ | |
815 | ecm->port.func.bind = ecm_bind; | |
816 | ecm->port.func.unbind = ecm_unbind; | |
817 | ecm->port.func.set_alt = ecm_set_alt; | |
818 | ecm->port.func.get_alt = ecm_get_alt; | |
819 | ecm->port.func.setup = ecm_setup; | |
820 | ecm->port.func.disable = ecm_disable; | |
821 | ||
822 | status = usb_add_function(c, &ecm->port.func); | |
823 | if (status) { | |
824 | ecm_string_defs[1].s = NULL; | |
825 | kfree(ecm); | |
826 | } | |
827 | return status; | |
828 | } |