[ecm] Use generic USB network device framework
[ipxe.git] / src / drivers / net / ecm.c
1 /*
2 * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdint.h>
23 #include <errno.h>
24 #include <ipxe/netdevice.h>
25 #include <ipxe/ethernet.h>
26 #include <ipxe/if_ether.h>
27 #include <ipxe/base16.h>
28 #include <ipxe/profile.h>
29 #include <ipxe/usb.h>
30 #include "ecm.h"
31
32 /** @file
33 *
34 * CDC-ECM USB Ethernet driver
35 *
36 */
37
38 /** Interrupt completion profiler */
39 static struct profiler ecm_intr_profiler __profiler =
40 { .name = "ecm.intr" };
41
42 /** Bulk IN completion profiler */
43 static struct profiler ecm_in_profiler __profiler =
44 { .name = "ecm.in" };
45
46 /** Bulk OUT profiler */
47 static struct profiler ecm_out_profiler __profiler =
48 { .name = "ecm.out" };
49
50 /******************************************************************************
51 *
52 * Ethernet functional descriptor
53 *
54 ******************************************************************************
55 */
56
57 /**
58 * Locate Ethernet functional descriptor
59 *
60 * @v config Configuration descriptor
61 * @v interface Interface descriptor
62 * @ret desc Descriptor, or NULL if not found
63 */
64 struct ecm_ethernet_descriptor *
65 ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
66 struct usb_interface_descriptor *interface ) {
67 struct ecm_ethernet_descriptor *desc;
68
69 for_each_interface_descriptor ( desc, config, interface ) {
70 if ( ( desc->header.type == USB_CS_INTERFACE_DESCRIPTOR ) &&
71 ( desc->subtype == CDC_SUBTYPE_ETHERNET ) )
72 return desc;
73 }
74 return NULL;
75 }
76
77 /**
78 * Get hardware MAC address
79 *
80 * @v usb USB device
81 * @v desc Ethernet functional descriptor
82 * @v hw_addr Hardware address to fill in
83 * @ret rc Return status code
84 */
85 int ecm_fetch_mac ( struct usb_device *usb,
86 struct ecm_ethernet_descriptor *desc, uint8_t *hw_addr ) {
87 char buf[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
88 int len;
89 int rc;
90
91 /* Fetch MAC address string */
92 len = usb_get_string_descriptor ( usb, desc->mac, 0, buf,
93 sizeof ( buf ) );
94 if ( len < 0 ) {
95 rc = len;
96 return rc;
97 }
98
99 /* Sanity check */
100 if ( len != ( ( int ) ( sizeof ( buf ) - 1 /* NUL */ ) ) )
101 return -EINVAL;
102
103 /* Decode MAC address */
104 len = base16_decode ( buf, hw_addr );
105 if ( len < 0 ) {
106 rc = len;
107 return rc;
108 }
109
110 return 0;
111 }
112
113 /******************************************************************************
114 *
115 * CDC-ECM communications interface
116 *
117 ******************************************************************************
118 */
119
120 /**
121 * Complete interrupt transfer
122 *
123 * @v ep USB endpoint
124 * @v iobuf I/O buffer
125 * @v rc Completion status code
126 */
127 static void ecm_intr_complete ( struct usb_endpoint *ep,
128 struct io_buffer *iobuf, int rc ) {
129 struct ecm_device *ecm = container_of ( ep, struct ecm_device,
130 usbnet.intr );
131 struct net_device *netdev = ecm->netdev;
132 struct usb_setup_packet *message;
133 size_t len = iob_len ( iobuf );
134
135 /* Profile completions */
136 profile_start ( &ecm_intr_profiler );
137
138 /* Ignore packets cancelled when the endpoint closes */
139 if ( ! ep->open )
140 goto ignore;
141
142 /* Drop packets with errors */
143 if ( rc != 0 ) {
144 DBGC ( ecm, "ECM %p interrupt failed: %s\n",
145 ecm, strerror ( rc ) );
146 DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
147 goto error;
148 }
149
150 /* Extract message header */
151 if ( len < sizeof ( *message ) ) {
152 DBGC ( ecm, "ECM %p underlength interrupt:\n", ecm );
153 DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
154 rc = -EINVAL;
155 goto error;
156 }
157 message = iobuf->data;
158
159 /* Parse message header */
160 switch ( message->request ) {
161
162 case cpu_to_le16 ( CDC_NETWORK_CONNECTION ) :
163 if ( message->value && ! netdev_link_ok ( netdev ) ) {
164 DBGC ( ecm, "ECM %p link up\n", ecm );
165 netdev_link_up ( netdev );
166 } else if ( netdev_link_ok ( netdev ) && ! message->value ) {
167 DBGC ( ecm, "ECM %p link down\n", ecm );
168 netdev_link_down ( netdev );
169 }
170 break;
171
172 case cpu_to_le16 ( CDC_CONNECTION_SPEED_CHANGE ) :
173 /* Ignore */
174 break;
175
176 default:
177 DBGC ( ecm, "ECM %p unrecognised interrupt:\n", ecm );
178 DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
179 rc = -ENOTSUP;
180 goto error;
181 }
182
183 /* Free I/O buffer */
184 free_iob ( iobuf );
185 profile_stop ( &ecm_intr_profiler );
186
187 return;
188
189 error:
190 netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
191 ignore:
192 free_iob ( iobuf );
193 return;
194 }
195
196 /** Interrupt endpoint operations */
197 static struct usb_endpoint_driver_operations ecm_intr_operations = {
198 .complete = ecm_intr_complete,
199 };
200
201 /******************************************************************************
202 *
203 * CDC-ECM data interface
204 *
205 ******************************************************************************
206 */
207
208 /**
209 * Complete bulk IN transfer
210 *
211 * @v ep USB endpoint
212 * @v iobuf I/O buffer
213 * @v rc Completion status code
214 */
215 static void ecm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
216 int rc ) {
217 struct ecm_device *ecm = container_of ( ep, struct ecm_device,
218 usbnet.in );
219 struct net_device *netdev = ecm->netdev;
220
221 /* Profile receive completions */
222 profile_start ( &ecm_in_profiler );
223
224 /* Ignore packets cancelled when the endpoint closes */
225 if ( ! ep->open )
226 goto ignore;
227
228 /* Record USB errors against the network device */
229 if ( rc != 0 ) {
230 DBGC ( ecm, "ECM %p bulk IN failed: %s\n",
231 ecm, strerror ( rc ) );
232 goto error;
233 }
234
235 /* Hand off to network stack */
236 netdev_rx ( netdev, iob_disown ( iobuf ) );
237
238 profile_stop ( &ecm_in_profiler );
239 return;
240
241 error:
242 netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
243 ignore:
244 free_iob ( iobuf );
245 }
246
247 /** Bulk IN endpoint operations */
248 static struct usb_endpoint_driver_operations ecm_in_operations = {
249 .complete = ecm_in_complete,
250 };
251
252 /**
253 * Transmit packet
254 *
255 * @v ecm CDC-ECM device
256 * @v iobuf I/O buffer
257 * @ret rc Return status code
258 */
259 static int ecm_out_transmit ( struct ecm_device *ecm,
260 struct io_buffer *iobuf ) {
261 int rc;
262
263 /* Profile transmissions */
264 profile_start ( &ecm_out_profiler );
265
266 /* Enqueue I/O buffer */
267 if ( ( rc = usb_stream ( &ecm->usbnet.out, iobuf, 1 ) ) != 0 )
268 return rc;
269
270 profile_stop ( &ecm_out_profiler );
271 return 0;
272 }
273
274 /**
275 * Complete bulk OUT transfer
276 *
277 * @v ep USB endpoint
278 * @v iobuf I/O buffer
279 * @v rc Completion status code
280 */
281 static void ecm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
282 int rc ) {
283 struct ecm_device *ecm = container_of ( ep, struct ecm_device,
284 usbnet.out );
285 struct net_device *netdev = ecm->netdev;
286
287 /* Report TX completion */
288 netdev_tx_complete_err ( netdev, iobuf, rc );
289 }
290
291 /** Bulk OUT endpoint operations */
292 static struct usb_endpoint_driver_operations ecm_out_operations = {
293 .complete = ecm_out_complete,
294 };
295
296 /******************************************************************************
297 *
298 * Network device interface
299 *
300 ******************************************************************************
301 */
302
303 /**
304 * Open network device
305 *
306 * @v netdev Network device
307 * @ret rc Return status code
308 */
309 static int ecm_open ( struct net_device *netdev ) {
310 struct ecm_device *ecm = netdev->priv;
311 struct usb_device *usb = ecm->usb;
312 unsigned int filter;
313 int rc;
314
315 /* Open USB network device */
316 if ( ( rc = usbnet_open ( &ecm->usbnet ) ) != 0 ) {
317 DBGC ( ecm, "ECM %p could not open: %s\n",
318 ecm, strerror ( rc ) );
319 goto err_open;
320 }
321
322 /* Set packet filter */
323 filter = ( ECM_PACKET_TYPE_PROMISCUOUS |
324 ECM_PACKET_TYPE_ALL_MULTICAST |
325 ECM_PACKET_TYPE_DIRECTED |
326 ECM_PACKET_TYPE_BROADCAST );
327 if ( ( rc = usb_control ( usb, ECM_SET_ETHERNET_PACKET_FILTER,
328 filter, ecm->usbnet.comms, NULL, 0 ) ) != 0 ){
329 DBGC ( ecm, "ECM %p could not set packet filter: %s\n",
330 ecm, strerror ( rc ) );
331 goto err_set_filter;
332 }
333
334 return 0;
335
336 err_set_filter:
337 usbnet_close ( &ecm->usbnet );
338 err_open:
339 return rc;
340 }
341
342 /**
343 * Close network device
344 *
345 * @v netdev Network device
346 */
347 static void ecm_close ( struct net_device *netdev ) {
348 struct ecm_device *ecm = netdev->priv;
349
350 /* Close USB network device */
351 usbnet_close ( &ecm->usbnet );
352 }
353
354 /**
355 * Transmit packet
356 *
357 * @v netdev Network device
358 * @v iobuf I/O buffer
359 * @ret rc Return status code
360 */
361 static int ecm_transmit ( struct net_device *netdev,
362 struct io_buffer *iobuf ) {
363 struct ecm_device *ecm = netdev->priv;
364 int rc;
365
366 /* Transmit packet */
367 if ( ( rc = ecm_out_transmit ( ecm, iobuf ) ) != 0 )
368 return rc;
369
370 return 0;
371 }
372
373 /**
374 * Poll for completed and received packets
375 *
376 * @v netdev Network device
377 */
378 static void ecm_poll ( struct net_device *netdev ) {
379 struct ecm_device *ecm = netdev->priv;
380 int rc;
381
382 /* Poll USB bus */
383 usb_poll ( ecm->bus );
384
385 /* Refill endpoints */
386 if ( ( rc = usbnet_refill ( &ecm->usbnet ) ) != 0 )
387 netdev_rx_err ( netdev, NULL, rc );
388 }
389
390 /** CDC-ECM network device operations */
391 static struct net_device_operations ecm_operations = {
392 .open = ecm_open,
393 .close = ecm_close,
394 .transmit = ecm_transmit,
395 .poll = ecm_poll,
396 };
397
398 /******************************************************************************
399 *
400 * USB interface
401 *
402 ******************************************************************************
403 */
404
405 /**
406 * Probe device
407 *
408 * @v func USB function
409 * @v config Configuration descriptor
410 * @ret rc Return status code
411 */
412 static int ecm_probe ( struct usb_function *func,
413 struct usb_configuration_descriptor *config ) {
414 struct usb_device *usb = func->usb;
415 struct net_device *netdev;
416 struct ecm_device *ecm;
417 struct usb_interface_descriptor *comms;
418 struct ecm_ethernet_descriptor *ethernet;
419 int rc;
420
421 /* Allocate and initialise structure */
422 netdev = alloc_etherdev ( sizeof ( *ecm ) );
423 if ( ! netdev ) {
424 rc = -ENOMEM;
425 goto err_alloc;
426 }
427 netdev_init ( netdev, &ecm_operations );
428 netdev->dev = &func->dev;
429 ecm = netdev->priv;
430 memset ( ecm, 0, sizeof ( *ecm ) );
431 ecm->usb = usb;
432 ecm->bus = usb->port->hub->bus;
433 ecm->netdev = netdev;
434 usbnet_init ( &ecm->usbnet, func, &ecm_intr_operations,
435 &ecm_in_operations, &ecm_out_operations );
436 usb_refill_init ( &ecm->usbnet.intr, 0, ECM_INTR_MAX_FILL );
437 usb_refill_init ( &ecm->usbnet.in, ECM_IN_MTU, ECM_IN_MAX_FILL );
438 DBGC ( ecm, "ECM %p on %s\n", ecm, func->name );
439
440 /* Describe USB network device */
441 if ( ( rc = usbnet_describe ( &ecm->usbnet, config ) ) != 0 ) {
442 DBGC ( ecm, "ECM %p could not describe: %s\n",
443 ecm, strerror ( rc ) );
444 goto err_describe;
445 }
446
447 /* Locate Ethernet descriptor */
448 comms = usb_interface_descriptor ( config, ecm->usbnet.comms, 0 );
449 assert ( comms != NULL );
450 ethernet = ecm_ethernet_descriptor ( config, comms );
451 if ( ! ethernet ) {
452 DBGC ( ecm, "ECM %p has no Ethernet descriptor\n", ecm );
453 rc = -EINVAL;
454 goto err_ethernet;
455 }
456
457 /* Fetch MAC address */
458 if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
459 DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
460 ecm, strerror ( rc ) );
461 goto err_fetch_mac;
462 }
463
464 /* Register network device */
465 if ( ( rc = register_netdev ( netdev ) ) != 0 )
466 goto err_register;
467
468 usb_func_set_drvdata ( func, ecm );
469 return 0;
470
471 unregister_netdev ( netdev );
472 err_register:
473 err_fetch_mac:
474 err_ethernet:
475 err_describe:
476 netdev_nullify ( netdev );
477 netdev_put ( netdev );
478 err_alloc:
479 return rc;
480 }
481
482 /**
483 * Remove device
484 *
485 * @v func USB function
486 */
487 static void ecm_remove ( struct usb_function *func ) {
488 struct ecm_device *ecm = usb_func_get_drvdata ( func );
489 struct net_device *netdev = ecm->netdev;
490
491 unregister_netdev ( netdev );
492 netdev_nullify ( netdev );
493 netdev_put ( netdev );
494 }
495
496 /** CDC-ECM device IDs */
497 static struct usb_device_id ecm_ids[] = {
498 {
499 .name = "cdc-ecm",
500 .vendor = USB_ANY_ID,
501 .product = USB_ANY_ID,
502 .class = {
503 .class = USB_CLASS_CDC,
504 .subclass = USB_SUBCLASS_CDC_ECM,
505 .protocol = 0,
506 },
507 },
508 };
509
510 /** CDC-ECM driver */
511 struct usb_driver ecm_driver __usb_driver = {
512 .ids = ecm_ids,
513 .id_count = ( sizeof ( ecm_ids ) / sizeof ( ecm_ids[0] ) ),
514 .probe = ecm_probe,
515 .remove = ecm_remove,
516 };