Browse Source

[ecm] Add support for CDC-ECM USB Ethernet devices

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
1bb9e88ba0
2 changed files with 750 additions and 1 deletions
  1. 657
    0
      src/drivers/net/ecm.c
  2. 93
    1
      src/drivers/net/ecm.h

+ 657
- 0
src/drivers/net/ecm.c View File

@@ -21,8 +21,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
21 21
 
22 22
 #include <stdint.h>
23 23
 #include <errno.h>
24
+#include <ipxe/netdevice.h>
25
+#include <ipxe/ethernet.h>
24 26
 #include <ipxe/if_ether.h>
25 27
 #include <ipxe/base16.h>
28
+#include <ipxe/profile.h>
26 29
 #include <ipxe/usb.h>
27 30
 #include "ecm.h"
28 31
 
@@ -32,6 +35,29 @@ FILE_LICENCE ( GPL2_OR_LATER );
32 35
  *
33 36
  */
34 37
 
38
+/** Refill profiler */
39
+static struct profiler ecm_refill_profiler __profiler =
40
+	{ .name = "ecm.refill" };
41
+
42
+/** Interrupt completion profiler */
43
+static struct profiler ecm_intr_profiler __profiler =
44
+	{ .name = "ecm.intr" };
45
+
46
+/** Bulk IN completion profiler */
47
+static struct profiler ecm_in_profiler __profiler =
48
+	{ .name = "ecm.in" };
49
+
50
+/** Bulk OUT profiler */
51
+static struct profiler ecm_out_profiler __profiler =
52
+	{ .name = "ecm.out" };
53
+
54
+/******************************************************************************
55
+ *
56
+ * Ethernet functional descriptor
57
+ *
58
+ ******************************************************************************
59
+ */
60
+
35 61
 /**
36 62
  * Locate Ethernet functional descriptor
37 63
  *
@@ -87,3 +113,634 @@ int ecm_fetch_mac ( struct usb_device *usb,
87 113
 
88 114
 	return 0;
89 115
 }
116
+
117
+/******************************************************************************
118
+ *
119
+ * Ring management
120
+ *
121
+ ******************************************************************************
122
+ */
123
+
124
+/**
125
+ * Transcribe receive ring name (for debugging)
126
+ *
127
+ * @v ecm		CDC-ECM device
128
+ * @v ring		Receive ring
129
+ * @ret name		Receive ring name
130
+ */
131
+static inline const char * ecm_rx_name ( struct ecm_device *ecm,
132
+					 struct ecm_rx_ring *ring ) {
133
+	if ( ring == &ecm->intr ) {
134
+		return "interrupt";
135
+	} else if ( ring == &ecm->in ) {
136
+		return "bulk IN";
137
+	} else {
138
+		return "UNKNOWN";
139
+	}
140
+}
141
+
142
+/**
143
+ * Refill receive ring
144
+ *
145
+ * @v ecm		CDC-ECM device
146
+ * @v ring		Receive ring
147
+ */
148
+static void ecm_rx_refill ( struct ecm_device *ecm, struct ecm_rx_ring *ring ) {
149
+	struct net_device *netdev = ecm->netdev;
150
+	struct io_buffer *iobuf;
151
+	int rc;
152
+
153
+	/* Refill ring */
154
+	while ( ring->fill < ring->max ) {
155
+
156
+		/* Profile refill */
157
+		profile_start ( &ecm_refill_profiler );
158
+
159
+		/* Allocate I/O buffer */
160
+		iobuf = alloc_iob ( ring->mtu );
161
+		if ( ! iobuf ) {
162
+			/* Wait for next refill */
163
+			break;
164
+		}
165
+		iob_put ( iobuf, ring->mtu );
166
+
167
+		/* Enqueue I/O buffer */
168
+		if ( ( rc = usb_stream ( &ring->ep, iobuf, 0 ) ) != 0 ) {
169
+			netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
170
+			break;
171
+		}
172
+
173
+		/* Increment fill level */
174
+		ring->fill++;
175
+		profile_stop ( &ecm_refill_profiler );
176
+	}
177
+}
178
+
179
+/******************************************************************************
180
+ *
181
+ * CDC-ECM communications interface
182
+ *
183
+ ******************************************************************************
184
+ */
185
+
186
+/**
187
+ * Complete interrupt transfer
188
+ *
189
+ * @v ep		USB endpoint
190
+ * @v iobuf		I/O buffer
191
+ * @v rc		Completion status code
192
+ */
193
+static void ecm_intr_complete ( struct usb_endpoint *ep,
194
+				struct io_buffer *iobuf, int rc ) {
195
+	struct ecm_device *ecm = container_of ( ep, struct ecm_device, intr.ep);
196
+	struct net_device *netdev = ecm->netdev;
197
+	struct usb_setup_packet *message;
198
+	size_t len = iob_len ( iobuf );
199
+
200
+	/* Profile completions */
201
+	profile_start ( &ecm_intr_profiler );
202
+
203
+	/* Decrement fill level */
204
+	assert ( ecm->intr.fill > 0 );
205
+	ecm->intr.fill--;
206
+
207
+	/* Ignore packets cancelled when the endpoint closes */
208
+	if ( ! ep->open )
209
+		goto ignore;
210
+
211
+	/* Drop packets with errors */
212
+	if ( rc != 0 ) {
213
+		DBGC ( ecm, "ECM %p interrupt failed: %s\n",
214
+		       ecm, strerror ( rc ) );
215
+		DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
216
+		goto error;
217
+	}
218
+
219
+	/* Extract message header */
220
+	if ( len < sizeof ( *message ) ) {
221
+		DBGC ( ecm, "ECM %p underlength interrupt:\n", ecm );
222
+		DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
223
+		goto error;
224
+	}
225
+	message = iobuf->data;
226
+
227
+	/* Parse message header */
228
+	switch ( message->request ) {
229
+
230
+	case cpu_to_le16 ( CDC_NETWORK_CONNECTION ) :
231
+		if ( message->value && ! netdev_link_ok ( netdev ) ) {
232
+			DBGC ( ecm, "ECM %p link up\n", ecm );
233
+			netdev_link_up ( netdev );
234
+		} else if ( netdev_link_ok ( netdev ) && ! message->value ) {
235
+			DBGC ( ecm, "ECM %p link down\n", ecm );
236
+			netdev_link_down ( netdev );
237
+		}
238
+		break;
239
+
240
+	case cpu_to_le16 ( CDC_CONNECTION_SPEED_CHANGE ) :
241
+		/* Ignore */
242
+		break;
243
+
244
+	default:
245
+		DBGC ( ecm, "ECM %p unrecognised interrupt:\n", ecm );
246
+		DBGC_HDA ( ecm, 0, iobuf->data, iob_len ( iobuf ) );
247
+		goto error;
248
+	}
249
+
250
+	/* Free I/O buffer */
251
+	free_iob ( iobuf );
252
+	profile_stop ( &ecm_intr_profiler );
253
+
254
+	return;
255
+
256
+ error:
257
+	netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
258
+ ignore:
259
+	free_iob ( iobuf );
260
+	return;
261
+}
262
+
263
+/** Interrupt endpoint operations */
264
+static struct usb_endpoint_driver_operations ecm_intr_operations = {
265
+	.complete = ecm_intr_complete,
266
+};
267
+
268
+/**
269
+ * Open communications interface
270
+ *
271
+ * @v ecm		CDC-ECM device
272
+ * @ret rc		Return status code
273
+ */
274
+static int ecm_comms_open ( struct ecm_device *ecm ) {
275
+	int rc;
276
+
277
+	/* Open interrupt endpoint */
278
+	if ( ( rc = usb_endpoint_open ( &ecm->intr.ep ) ) != 0 ) {
279
+		DBGC ( ecm, "ECM %p could not open interrupt: %s\n",
280
+		       ecm, strerror ( rc ) );
281
+		goto err_open;
282
+	}
283
+
284
+	/* Refill interrupt ring */
285
+	ecm_rx_refill ( ecm, &ecm->intr );
286
+
287
+	return 0;
288
+
289
+	usb_endpoint_close ( &ecm->intr.ep );
290
+	assert ( ecm->intr.fill == 0 );
291
+ err_open:
292
+	return rc;
293
+}
294
+
295
+/**
296
+ * Close communications interface
297
+ *
298
+ * @v ecm		CDC-ECM device
299
+ */
300
+static void ecm_comms_close ( struct ecm_device *ecm ) {
301
+
302
+	/* Close interrupt endpoint */
303
+	usb_endpoint_close ( &ecm->intr.ep );
304
+	assert ( ecm->intr.fill == 0 );
305
+}
306
+
307
+/******************************************************************************
308
+ *
309
+ * CDC-ECM data interface
310
+ *
311
+ ******************************************************************************
312
+ */
313
+
314
+/**
315
+ * Complete bulk IN transfer
316
+ *
317
+ * @v ep		USB endpoint
318
+ * @v iobuf		I/O buffer
319
+ * @v rc		Completion status code
320
+ */
321
+static void ecm_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
322
+			      int rc ) {
323
+	struct ecm_device *ecm = container_of ( ep, struct ecm_device, in.ep );
324
+	struct net_device *netdev = ecm->netdev;
325
+
326
+	/* Profile receive completions */
327
+	profile_start ( &ecm_in_profiler );
328
+
329
+	/* Decrement fill level */
330
+	assert ( ecm->in.fill > 0 );
331
+	ecm->in.fill--;
332
+
333
+	/* Ignore packets cancelled when the endpoint closes */
334
+	if ( ! ep->open )
335
+		goto ignore;
336
+
337
+	/* Record USB errors against the network device */
338
+	if ( rc != 0 ) {
339
+		DBGC ( ecm, "ECM %p bulk IN failed: %s\n",
340
+		       ecm, strerror ( rc ) );
341
+		goto error;
342
+	}
343
+
344
+	/* Hand off to network stack */
345
+	netdev_rx ( netdev, iob_disown ( iobuf ) );
346
+
347
+	profile_stop ( &ecm_in_profiler );
348
+	return;
349
+
350
+ error:
351
+	netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
352
+ ignore:
353
+	free_iob ( iobuf );
354
+}
355
+
356
+/** Bulk IN endpoint operations */
357
+static struct usb_endpoint_driver_operations ecm_in_operations = {
358
+	.complete = ecm_in_complete,
359
+};
360
+
361
+/**
362
+ * Transmit packet
363
+ *
364
+ * @v ecm		CDC-ECM device
365
+ * @v iobuf		I/O buffer
366
+ * @ret rc		Return status code
367
+ */
368
+static int ecm_out_transmit ( struct ecm_device *ecm,
369
+			      struct io_buffer *iobuf ) {
370
+	int rc;
371
+
372
+	/* Profile transmissions */
373
+	profile_start ( &ecm_out_profiler );
374
+
375
+	/* Enqueue I/O buffer */
376
+	if ( ( rc = usb_stream ( &ecm->out.ep, iobuf, 1 ) ) != 0 )
377
+		return rc;
378
+
379
+	profile_stop ( &ecm_out_profiler );
380
+	return 0;
381
+}
382
+
383
+/**
384
+ * Complete bulk OUT transfer
385
+ *
386
+ * @v ep		USB endpoint
387
+ * @v iobuf		I/O buffer
388
+ * @v rc		Completion status code
389
+ */
390
+static void ecm_out_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf,
391
+			       int rc ) {
392
+	struct ecm_device *ecm = container_of ( ep, struct ecm_device, out.ep );
393
+	struct net_device *netdev = ecm->netdev;
394
+
395
+	/* Report TX completion */
396
+	netdev_tx_complete_err ( netdev, iobuf, rc );
397
+}
398
+
399
+/** Bulk OUT endpoint operations */
400
+static struct usb_endpoint_driver_operations ecm_out_operations = {
401
+	.complete = ecm_out_complete,
402
+};
403
+
404
+/**
405
+ * Open data interface
406
+ *
407
+ * @v ecm		CDC-ECM device
408
+ * @ret rc		Return status code
409
+ */
410
+static int ecm_data_open ( struct ecm_device *ecm ) {
411
+	struct usb_device *usb = ecm->usb;
412
+	int rc;
413
+
414
+	/* Select alternate setting for data interface */
415
+	if ( ( rc = usb_set_interface ( usb, ecm->data,
416
+					ECM_DATA_ALTERNATE ) ) != 0 ) {
417
+		DBGC ( ecm, "ECM %p could not set alternate interface: %s\n",
418
+		       ecm, strerror ( rc ) );
419
+		goto err_set_interface;
420
+	}
421
+
422
+	/* Open bulk IN endpoint */
423
+	if ( ( rc = usb_endpoint_open ( &ecm->in.ep ) ) != 0 ) {
424
+		DBGC ( ecm, "ECM %p could not open bulk IN: %s\n",
425
+		       ecm, strerror ( rc ) );
426
+		goto err_open_in;
427
+	}
428
+
429
+	/* Open bulk OUT endpoint */
430
+	if ( ( rc = usb_endpoint_open ( &ecm->out.ep ) ) != 0 ) {
431
+		DBGC ( ecm, "ECM %p could not open bulk OUT: %s\n",
432
+		       ecm, strerror ( rc ) );
433
+		goto err_open_out;
434
+	}
435
+
436
+	/* Refill bulk IN ring */
437
+	ecm_rx_refill ( ecm, &ecm->in );
438
+
439
+	return 0;
440
+
441
+	usb_endpoint_close ( &ecm->out.ep );
442
+ err_open_out:
443
+	usb_endpoint_close ( &ecm->in.ep );
444
+	assert ( ecm->in.fill == 0 );
445
+ err_open_in:
446
+	usb_set_interface ( usb, ecm->data, 0 );
447
+ err_set_interface:
448
+	return rc;
449
+}
450
+
451
+/**
452
+ * Close data interface
453
+ *
454
+ * @v ecm		CDC-ECM device
455
+ */
456
+static void ecm_data_close ( struct ecm_device *ecm ) {
457
+	struct usb_device *usb = ecm->usb;
458
+
459
+	/* Close endpoints */
460
+	usb_endpoint_close ( &ecm->out.ep );
461
+	usb_endpoint_close ( &ecm->in.ep );
462
+	assert ( ecm->in.fill == 0 );
463
+
464
+	/* Reset data interface */
465
+	usb_set_interface ( usb, ecm->data, 0 );
466
+}
467
+
468
+/******************************************************************************
469
+ *
470
+ * Network device interface
471
+ *
472
+ ******************************************************************************
473
+ */
474
+
475
+/**
476
+ * Open network device
477
+ *
478
+ * @v netdev		Network device
479
+ * @ret rc		Return status code
480
+ */
481
+static int ecm_open ( struct net_device *netdev ) {
482
+	struct ecm_device *ecm = netdev->priv;
483
+	struct usb_device *usb = ecm->usb;
484
+	unsigned int filter;
485
+	int rc;
486
+
487
+	/* Open communications interface */
488
+	if ( ( rc = ecm_comms_open ( ecm ) ) != 0 )
489
+		goto err_comms_open;
490
+
491
+	/* Open data interface */
492
+	if ( ( rc = ecm_data_open ( ecm ) ) != 0 )
493
+		goto err_data_open;
494
+
495
+	/* Set packet filter */
496
+	filter = ( ECM_PACKET_TYPE_PROMISCUOUS |
497
+		   ECM_PACKET_TYPE_ALL_MULTICAST |
498
+		   ECM_PACKET_TYPE_DIRECTED |
499
+		   ECM_PACKET_TYPE_BROADCAST );
500
+	if ( ( rc = usb_control ( usb, ECM_SET_ETHERNET_PACKET_FILTER,
501
+				  filter, ecm->comms, NULL, 0 ) ) != 0 ) {
502
+		DBGC ( ecm, "ECM %p could not set packet filter: %s\n",
503
+		       ecm, strerror ( rc ) );
504
+		goto err_set_filter;
505
+	}
506
+
507
+	return 0;
508
+
509
+ err_set_filter:
510
+	ecm_data_close ( ecm );
511
+ err_data_open:
512
+	ecm_comms_close ( ecm );
513
+ err_comms_open:
514
+	return rc;
515
+}
516
+
517
+/**
518
+ * Close network device
519
+ *
520
+ * @v netdev		Network device
521
+ */
522
+static void ecm_close ( struct net_device *netdev ) {
523
+	struct ecm_device *ecm = netdev->priv;
524
+
525
+	/* Close data interface */
526
+	ecm_data_close ( ecm );
527
+
528
+	/* Close communications interface */
529
+	ecm_comms_close ( ecm );
530
+}
531
+
532
+/**
533
+ * Transmit packet
534
+ *
535
+ * @v netdev		Network device
536
+ * @v iobuf		I/O buffer
537
+ * @ret rc		Return status code
538
+ */
539
+static int ecm_transmit ( struct net_device *netdev,
540
+			  struct io_buffer *iobuf ) {
541
+	struct ecm_device *ecm = netdev->priv;
542
+	int rc;
543
+
544
+	/* Transmit packet */
545
+	if ( ( rc = ecm_out_transmit ( ecm, iobuf ) ) != 0 )
546
+		return rc;
547
+
548
+	return 0;
549
+}
550
+
551
+/**
552
+ * Poll for completed and received packets
553
+ *
554
+ * @v netdev		Network device
555
+ */
556
+static void ecm_poll ( struct net_device *netdev ) {
557
+	struct ecm_device *ecm = netdev->priv;
558
+
559
+	/* Poll USB bus */
560
+	usb_poll ( ecm->bus );
561
+
562
+	/* Refill interrupt ring */
563
+	ecm_rx_refill ( ecm, &ecm->intr );
564
+
565
+	/* Refill bulk IN ring */
566
+	ecm_rx_refill ( ecm, &ecm->in );
567
+}
568
+
569
+/** CDC-ECM network device operations */
570
+static struct net_device_operations ecm_operations = {
571
+	.open		= ecm_open,
572
+	.close		= ecm_close,
573
+	.transmit	= ecm_transmit,
574
+	.poll		= ecm_poll,
575
+};
576
+
577
+/******************************************************************************
578
+ *
579
+ * USB interface
580
+ *
581
+ ******************************************************************************
582
+ */
583
+
584
+/**
585
+ * Probe device
586
+ *
587
+ * @v func		USB function
588
+ * @v config		Configuration descriptor
589
+ * @ret rc		Return status code
590
+ */
591
+static int ecm_probe ( struct usb_function *func,
592
+		       struct usb_configuration_descriptor *config ) {
593
+	struct usb_device *usb = func->usb;
594
+	struct net_device *netdev;
595
+	struct ecm_device *ecm;
596
+	struct usb_interface_descriptor *comms;
597
+	struct usb_interface_descriptor *data;
598
+	struct ecm_ethernet_descriptor *ethernet;
599
+	int rc;
600
+
601
+	/* Allocate and initialise structure */
602
+	netdev = alloc_etherdev ( sizeof ( *ecm ) );
603
+	if ( ! netdev ) {
604
+		rc = -ENOMEM;
605
+		goto err_alloc;
606
+	}
607
+	netdev_init ( netdev, &ecm_operations );
608
+	netdev->dev = &func->dev;
609
+	ecm = netdev->priv;
610
+	memset ( ecm, 0, sizeof ( *ecm ) );
611
+	ecm->usb = usb;
612
+	ecm->bus = usb->port->hub->bus;
613
+	ecm->netdev = netdev;
614
+	usb_endpoint_init ( &ecm->intr.ep, usb, &ecm_intr_operations );
615
+	usb_endpoint_init ( &ecm->in.ep, usb, &ecm_in_operations );
616
+	usb_endpoint_init ( &ecm->out.ep, usb, &ecm_out_operations );
617
+	DBGC ( ecm, "ECM %p on %s\n", ecm, func->name );
618
+
619
+	/* Identify interfaces */
620
+	if ( func->count < ECM_INTERFACE_COUNT ) {
621
+		DBGC ( ecm, "ECM %p has only %d interfaces\n",
622
+		       ecm, func->count );
623
+		rc = -EINVAL;
624
+		goto err_count;
625
+	}
626
+	ecm->comms = func->interface[ECM_INTERFACE_COMMS];
627
+	ecm->data = func->interface[ECM_INTERFACE_DATA];
628
+
629
+	/* Locate communications interface descriptor */
630
+	comms = usb_interface_descriptor ( config, ecm->comms, 0 );
631
+	if ( ! comms ) {
632
+		DBGC ( ecm, "ECM %p has no communications interface\n", ecm );
633
+		rc = -EINVAL;
634
+		goto err_comms;
635
+	}
636
+
637
+	/* Locate data interface descriptor */
638
+	data = usb_interface_descriptor ( config, ecm->data,
639
+					  ECM_DATA_ALTERNATE );
640
+	if ( ! data ) {
641
+		DBGC ( ecm, "ECM %p has no data interface\n", ecm );
642
+		rc = -EINVAL;
643
+		goto err_data;
644
+	}
645
+
646
+	/* Describe interrupt endpoint */
647
+	if ( ( rc = usb_endpoint_described ( &ecm->intr.ep, config, comms,
648
+					     USB_INTERRUPT, 0 ) ) != 0 ) {
649
+		DBGC ( ecm, "ECM %p could not describe interrupt endpoint: "
650
+		       "%s\n", ecm, strerror ( rc ) );
651
+		goto err_interrupt;
652
+	}
653
+	ecm->intr.mtu = ecm->intr.ep.mtu;
654
+	ecm->intr.max = ECM_INTR_MAX_FILL;
655
+
656
+	/* Describe bulk IN endpoint */
657
+	if ( ( rc = usb_endpoint_described ( &ecm->in.ep, config, data,
658
+					     USB_BULK_IN, 0 ) ) != 0 ) {
659
+		DBGC ( ecm, "ECM %p could not describe bulk IN endpoint: "
660
+		       "%s\n", ecm, strerror ( rc ) );
661
+		goto err_bulk_in;
662
+	}
663
+	ecm->in.mtu = ECM_IN_MTU;
664
+	ecm->in.max = ECM_IN_MAX_FILL;
665
+
666
+	/* Describe bulk OUT endpoint */
667
+	if ( ( rc = usb_endpoint_described ( &ecm->out.ep, config, data,
668
+					     USB_BULK_OUT, 0 ) ) != 0 ) {
669
+		DBGC ( ecm, "ECM %p could not describe bulk OUT endpoint: "
670
+		       "%s\n", ecm, strerror ( rc ) );
671
+		goto err_bulk_out;
672
+	}
673
+
674
+	/* Locate Ethernet descriptor */
675
+	ethernet = ecm_ethernet_descriptor ( config, comms );
676
+	if ( ! ethernet ) {
677
+		DBGC ( ecm, "ECM %p has no Ethernet descriptor\n", ecm );
678
+		rc = -EINVAL;
679
+		goto err_ethernet;
680
+	}
681
+
682
+	/* Fetch MAC address */
683
+	if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
684
+		DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
685
+		       ecm, strerror ( rc ) );
686
+		goto err_fetch_mac;
687
+	}
688
+
689
+	/* Register network device */
690
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
691
+		goto err_register;
692
+
693
+	usb_func_set_drvdata ( func, ecm );
694
+	return 0;
695
+
696
+	unregister_netdev ( netdev );
697
+ err_register:
698
+ err_fetch_mac:
699
+ err_ethernet:
700
+ err_bulk_out:
701
+ err_bulk_in:
702
+ err_interrupt:
703
+ err_data:
704
+ err_comms:
705
+ err_count:
706
+	netdev_nullify ( netdev );
707
+	netdev_put ( netdev );
708
+ err_alloc:
709
+	return rc;
710
+}
711
+
712
+/**
713
+ * Remove device
714
+ *
715
+ * @v func		USB function
716
+ */
717
+static void ecm_remove ( struct usb_function *func ) {
718
+	struct ecm_device *ecm = usb_func_get_drvdata ( func );
719
+	struct net_device *netdev = ecm->netdev;
720
+
721
+	unregister_netdev ( netdev );
722
+	netdev_nullify ( netdev );
723
+	netdev_put ( netdev );
724
+}
725
+
726
+/** CDC-ECM device IDs */
727
+static struct usb_device_id ecm_ids[] = {
728
+	{
729
+		.name = "cdc-ecm",
730
+		.vendor = USB_ANY_ID,
731
+		.product = USB_ANY_ID,
732
+		.class = {
733
+			.class = USB_CLASS_CDC,
734
+			.subclass = USB_SUBCLASS_CDC_ECM,
735
+			.protocol = 0,
736
+		},
737
+	},
738
+};
739
+
740
+/** CDC-ECM driver */
741
+struct usb_driver ecm_driver __usb_driver = {
742
+	.ids = ecm_ids,
743
+	.id_count = ( sizeof ( ecm_ids ) / sizeof ( ecm_ids[0] ) ),
744
+	.probe = ecm_probe,
745
+	.remove = ecm_remove,
746
+};

+ 93
- 1
src/drivers/net/ecm.h View File

@@ -12,13 +12,47 @@ FILE_LICENCE ( GPL2_OR_LATER );
12 12
 #include <ipxe/usb.h>
13 13
 #include <ipxe/cdc.h>
14 14
 
15
+/** CDC-ECM subclass */
16
+#define USB_SUBCLASS_CDC_ECM 0x06
17
+
18
+/** CDC-ECM interfaces */
19
+enum ecm_interfaces {
20
+	/** Communications interface */
21
+	ECM_INTERFACE_COMMS = 0,
22
+	/** Data interface */
23
+	ECM_INTERFACE_DATA,
24
+	ECM_INTERFACE_COUNT
25
+};
26
+
27
+/** Alternate setting for CDC-ECM data interface */
28
+#define ECM_DATA_ALTERNATE 1
29
+
30
+/** Set Ethernet packet filter */
31
+#define ECM_SET_ETHERNET_PACKET_FILTER					\
32
+	( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE |		\
33
+	  USB_REQUEST_TYPE ( 0x43 ) )
34
+
35
+/** Ethernet packet types */
36
+enum ecm_ethernet_packet_filter {
37
+	/** Promiscuous mode */
38
+	ECM_PACKET_TYPE_PROMISCUOUS = 0x0001,
39
+	/** All multicast packets */
40
+	ECM_PACKET_TYPE_ALL_MULTICAST = 0x0002,
41
+	/** Unicast packets */
42
+	ECM_PACKET_TYPE_DIRECTED = 0x0004,
43
+	/** Broadcast packets */
44
+	ECM_PACKET_TYPE_BROADCAST = 0x0008,
45
+	/** Specified multicast packets */
46
+	ECM_PACKET_TYPE_MULTICAST = 0x0010,
47
+};
48
+
15 49
 /** An Ethernet Functional Descriptor */
16 50
 struct ecm_ethernet_descriptor {
17 51
 	/** Descriptor header */
18 52
 	struct usb_descriptor_header header;
19 53
 	/** Descriptor subtype */
20 54
 	uint8_t subtype;
21
-	/** MAC addres string */
55
+	/** MAC address string */
22 56
 	uint8_t mac;
23 57
 	/** Ethernet statistics bitmap */
24 58
 	uint32_t statistics;
@@ -30,6 +64,64 @@ struct ecm_ethernet_descriptor {
30 64
 	uint8_t wol;
31 65
 } __attribute__ (( packed ));
32 66
 
67
+/** A CDC-ECM receive ring */
68
+struct ecm_rx_ring {
69
+	/** USB endpoint */
70
+	struct usb_endpoint ep;
71
+	/** I/O buffer size */
72
+	size_t mtu;
73
+	/** Fill level */
74
+	unsigned int fill;
75
+	/** Maximum fill level */
76
+	unsigned int max;
77
+};
78
+
79
+/** A CDC-ECM transmit ring */
80
+struct ecm_tx_ring {
81
+	/** USB endpoint */
82
+	struct usb_endpoint ep;
83
+};
84
+
85
+/** A CDC-ECM network device */
86
+struct ecm_device {
87
+	/** USB device */
88
+	struct usb_device *usb;
89
+	/** USB bus */
90
+	struct usb_bus *bus;
91
+	/** Network device */
92
+	struct net_device *netdev;
93
+
94
+	/** Communications interface */
95
+	unsigned int comms;
96
+	/** Data interface */
97
+	unsigned int data;
98
+
99
+	/** Interrupt ring */
100
+	struct ecm_rx_ring intr;
101
+	/** Bulk IN ring */
102
+	struct ecm_rx_ring in;
103
+	/** Bulk OUT ring */
104
+	struct ecm_tx_ring out;
105
+};
106
+
107
+/** Interrupt maximum fill level
108
+ *
109
+ * This is a policy decision.
110
+ */
111
+#define ECM_INTR_MAX_FILL 2
112
+
113
+/** Bulk IN maximum fill level
114
+ *
115
+ * This is a policy decision.
116
+ */
117
+#define ECM_IN_MAX_FILL 8
118
+
119
+/** Bulk IN buffer size
120
+ *
121
+ * This is a policy decision.
122
+ */
123
+#define ECM_IN_MTU ( ETH_FRAME_LEN + 4 /* possible VLAN header */ )
124
+
33 125
 extern struct ecm_ethernet_descriptor *
34 126
 ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
35 127
 			  struct usb_interface_descriptor *interface );

Loading…
Cancel
Save