diff options
author | David Brownell <david-b@pacbell.net> | 2005-08-31 12:54:20 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-09-08 19:28:32 -0400 |
commit | 4324fd493430c0ab99dd7e89d50540b5e70f8098 (patch) | |
tree | 66f1d16d895fd660ad8d5c7279e8bd08e6787eb8 /drivers/usb/net/usbnet.c | |
parent | 0aa599c5644fddd3052433c5335260108a8a39a2 (diff) |
[PATCH] USB: usbnet (7/9) module for CDC Ethernet
Makes the CDC Ethernet support live in a separate driver module.
This module is a bit special since it exports utility functions
that are reused by the the Zaurus and RNDIS drivers, but it's
not "core" like usbnet itself.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/net/usbnet.c')
-rw-r--r-- | drivers/usb/net/usbnet.c | 392 |
1 files changed, 0 insertions, 392 deletions
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 75a05ab0a642..7703725327d2 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c | |||
@@ -301,377 +301,6 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb) | |||
301 | EXPORT_SYMBOL_GPL(usbnet_skb_return); | 301 | EXPORT_SYMBOL_GPL(usbnet_skb_return); |
302 | 302 | ||
303 | 303 | ||
304 | /*------------------------------------------------------------------------- | ||
305 | * | ||
306 | * Communications Device Class declarations. | ||
307 | * Used by CDC Ethernet, and some CDC variants | ||
308 | * | ||
309 | *-------------------------------------------------------------------------*/ | ||
310 | |||
311 | #ifdef CONFIG_USB_CDCETHER | ||
312 | #define NEED_GENERIC_CDC | ||
313 | #endif | ||
314 | |||
315 | #if defined(CONFIG_USB_ZAURUS) || defined(CONFIG_USB_ZAURUS_MODULE) | ||
316 | /* Ethernet variant uses funky framing, broken ethernet addressing */ | ||
317 | #define NEED_GENERIC_CDC | ||
318 | #endif | ||
319 | |||
320 | #ifdef CONFIG_USB_RNDIS | ||
321 | /* ACM variant uses even funkier framing, complex control RPC scheme */ | ||
322 | #define NEED_GENERIC_CDC | ||
323 | #endif | ||
324 | |||
325 | |||
326 | #ifdef NEED_GENERIC_CDC | ||
327 | |||
328 | #include <linux/usb_cdc.h> | ||
329 | |||
330 | static struct usb_driver usbnet_driver; | ||
331 | |||
332 | /* | ||
333 | * probes control interface, claims data interface, collects the bulk | ||
334 | * endpoints, activates data interface (if needed), maybe sets MTU. | ||
335 | * all pure cdc, except for certain firmware workarounds. | ||
336 | */ | ||
337 | int usbnet_generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf) | ||
338 | { | ||
339 | u8 *buf = intf->cur_altsetting->extra; | ||
340 | int len = intf->cur_altsetting->extralen; | ||
341 | struct usb_interface_descriptor *d; | ||
342 | struct cdc_state *info = (void *) &dev->data; | ||
343 | int status; | ||
344 | int rndis; | ||
345 | |||
346 | if (sizeof dev->data < sizeof *info) | ||
347 | return -EDOM; | ||
348 | |||
349 | /* expect strict spec conformance for the descriptors, but | ||
350 | * cope with firmware which stores them in the wrong place | ||
351 | */ | ||
352 | if (len == 0 && dev->udev->actconfig->extralen) { | ||
353 | /* Motorola SB4100 (and others: Brad Hards says it's | ||
354 | * from a Broadcom design) put CDC descriptors here | ||
355 | */ | ||
356 | buf = dev->udev->actconfig->extra; | ||
357 | len = dev->udev->actconfig->extralen; | ||
358 | if (len) | ||
359 | dev_dbg (&intf->dev, | ||
360 | "CDC descriptors on config\n"); | ||
361 | } | ||
362 | |||
363 | /* this assumes that if there's a non-RNDIS vendor variant | ||
364 | * of cdc-acm, it'll fail RNDIS requests cleanly. | ||
365 | */ | ||
366 | rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff); | ||
367 | |||
368 | memset (info, 0, sizeof *info); | ||
369 | info->control = intf; | ||
370 | while (len > 3) { | ||
371 | if (buf [1] != USB_DT_CS_INTERFACE) | ||
372 | goto next_desc; | ||
373 | |||
374 | /* use bDescriptorSubType to identify the CDC descriptors. | ||
375 | * We expect devices with CDC header and union descriptors. | ||
376 | * For CDC Ethernet we need the ethernet descriptor. | ||
377 | * For RNDIS, ignore two (pointless) CDC modem descriptors | ||
378 | * in favor of a complicated OID-based RPC scheme doing what | ||
379 | * CDC Ethernet achieves with a simple descriptor. | ||
380 | */ | ||
381 | switch (buf [2]) { | ||
382 | case USB_CDC_HEADER_TYPE: | ||
383 | if (info->header) { | ||
384 | dev_dbg (&intf->dev, "extra CDC header\n"); | ||
385 | goto bad_desc; | ||
386 | } | ||
387 | info->header = (void *) buf; | ||
388 | if (info->header->bLength != sizeof *info->header) { | ||
389 | dev_dbg (&intf->dev, "CDC header len %u\n", | ||
390 | info->header->bLength); | ||
391 | goto bad_desc; | ||
392 | } | ||
393 | break; | ||
394 | case USB_CDC_UNION_TYPE: | ||
395 | if (info->u) { | ||
396 | dev_dbg (&intf->dev, "extra CDC union\n"); | ||
397 | goto bad_desc; | ||
398 | } | ||
399 | info->u = (void *) buf; | ||
400 | if (info->u->bLength != sizeof *info->u) { | ||
401 | dev_dbg (&intf->dev, "CDC union len %u\n", | ||
402 | info->u->bLength); | ||
403 | goto bad_desc; | ||
404 | } | ||
405 | |||
406 | /* we need a master/control interface (what we're | ||
407 | * probed with) and a slave/data interface; union | ||
408 | * descriptors sort this all out. | ||
409 | */ | ||
410 | info->control = usb_ifnum_to_if(dev->udev, | ||
411 | info->u->bMasterInterface0); | ||
412 | info->data = usb_ifnum_to_if(dev->udev, | ||
413 | info->u->bSlaveInterface0); | ||
414 | if (!info->control || !info->data) { | ||
415 | dev_dbg (&intf->dev, | ||
416 | "master #%u/%p slave #%u/%p\n", | ||
417 | info->u->bMasterInterface0, | ||
418 | info->control, | ||
419 | info->u->bSlaveInterface0, | ||
420 | info->data); | ||
421 | goto bad_desc; | ||
422 | } | ||
423 | if (info->control != intf) { | ||
424 | dev_dbg (&intf->dev, "bogus CDC Union\n"); | ||
425 | /* Ambit USB Cable Modem (and maybe others) | ||
426 | * interchanges master and slave interface. | ||
427 | */ | ||
428 | if (info->data == intf) { | ||
429 | info->data = info->control; | ||
430 | info->control = intf; | ||
431 | } else | ||
432 | goto bad_desc; | ||
433 | } | ||
434 | |||
435 | /* a data interface altsetting does the real i/o */ | ||
436 | d = &info->data->cur_altsetting->desc; | ||
437 | if (d->bInterfaceClass != USB_CLASS_CDC_DATA) { | ||
438 | dev_dbg (&intf->dev, "slave class %u\n", | ||
439 | d->bInterfaceClass); | ||
440 | goto bad_desc; | ||
441 | } | ||
442 | break; | ||
443 | case USB_CDC_ETHERNET_TYPE: | ||
444 | if (info->ether) { | ||
445 | dev_dbg (&intf->dev, "extra CDC ether\n"); | ||
446 | goto bad_desc; | ||
447 | } | ||
448 | info->ether = (void *) buf; | ||
449 | if (info->ether->bLength != sizeof *info->ether) { | ||
450 | dev_dbg (&intf->dev, "CDC ether len %u\n", | ||
451 | info->ether->bLength); | ||
452 | goto bad_desc; | ||
453 | } | ||
454 | dev->hard_mtu = le16_to_cpu( | ||
455 | info->ether->wMaxSegmentSize); | ||
456 | /* because of Zaurus, we may be ignoring the host | ||
457 | * side link address we were given. | ||
458 | */ | ||
459 | break; | ||
460 | } | ||
461 | next_desc: | ||
462 | len -= buf [0]; /* bLength */ | ||
463 | buf += buf [0]; | ||
464 | } | ||
465 | |||
466 | if (!info->header || !info->u || (!rndis && !info->ether)) { | ||
467 | dev_dbg (&intf->dev, "missing cdc %s%s%sdescriptor\n", | ||
468 | info->header ? "" : "header ", | ||
469 | info->u ? "" : "union ", | ||
470 | info->ether ? "" : "ether "); | ||
471 | goto bad_desc; | ||
472 | } | ||
473 | |||
474 | /* claim data interface and set it up ... with side effects. | ||
475 | * network traffic can't flow until an altsetting is enabled. | ||
476 | */ | ||
477 | status = usb_driver_claim_interface (&usbnet_driver, info->data, dev); | ||
478 | if (status < 0) | ||
479 | return status; | ||
480 | status = usbnet_get_endpoints (dev, info->data); | ||
481 | if (status < 0) { | ||
482 | /* ensure immediate exit from usbnet_disconnect */ | ||
483 | usb_set_intfdata(info->data, NULL); | ||
484 | usb_driver_release_interface (&usbnet_driver, info->data); | ||
485 | return status; | ||
486 | } | ||
487 | |||
488 | /* status endpoint: optional for CDC Ethernet, not RNDIS (or ACM) */ | ||
489 | dev->status = NULL; | ||
490 | if (info->control->cur_altsetting->desc.bNumEndpoints == 1) { | ||
491 | struct usb_endpoint_descriptor *desc; | ||
492 | |||
493 | dev->status = &info->control->cur_altsetting->endpoint [0]; | ||
494 | desc = &dev->status->desc; | ||
495 | if (desc->bmAttributes != USB_ENDPOINT_XFER_INT | ||
496 | || !(desc->bEndpointAddress & USB_DIR_IN) | ||
497 | || (le16_to_cpu(desc->wMaxPacketSize) | ||
498 | < sizeof (struct usb_cdc_notification)) | ||
499 | || !desc->bInterval) { | ||
500 | dev_dbg (&intf->dev, "bad notification endpoint\n"); | ||
501 | dev->status = NULL; | ||
502 | } | ||
503 | } | ||
504 | if (rndis && !dev->status) { | ||
505 | dev_dbg (&intf->dev, "missing RNDIS status endpoint\n"); | ||
506 | usb_set_intfdata(info->data, NULL); | ||
507 | usb_driver_release_interface (&usbnet_driver, info->data); | ||
508 | return -ENODEV; | ||
509 | } | ||
510 | return 0; | ||
511 | |||
512 | bad_desc: | ||
513 | dev_info (&dev->udev->dev, "bad CDC descriptors\n"); | ||
514 | return -ENODEV; | ||
515 | } | ||
516 | EXPORT_SYMBOL_GPL(usbnet_generic_cdc_bind); | ||
517 | |||
518 | void usbnet_cdc_unbind (struct usbnet *dev, struct usb_interface *intf) | ||
519 | { | ||
520 | struct cdc_state *info = (void *) &dev->data; | ||
521 | |||
522 | /* disconnect master --> disconnect slave */ | ||
523 | if (intf == info->control && info->data) { | ||
524 | /* ensure immediate exit from usbnet_disconnect */ | ||
525 | usb_set_intfdata(info->data, NULL); | ||
526 | usb_driver_release_interface (&usbnet_driver, info->data); | ||
527 | info->data = NULL; | ||
528 | } | ||
529 | |||
530 | /* and vice versa (just in case) */ | ||
531 | else if (intf == info->data && info->control) { | ||
532 | /* ensure immediate exit from usbnet_disconnect */ | ||
533 | usb_set_intfdata(info->control, NULL); | ||
534 | usb_driver_release_interface (&usbnet_driver, info->control); | ||
535 | info->control = NULL; | ||
536 | } | ||
537 | } | ||
538 | EXPORT_SYMBOL_GPL(usbnet_cdc_unbind); | ||
539 | |||
540 | #endif /* NEED_GENERIC_CDC */ | ||
541 | |||
542 | |||
543 | #ifdef CONFIG_USB_CDCETHER | ||
544 | #define HAVE_HARDWARE | ||
545 | |||
546 | /*------------------------------------------------------------------------- | ||
547 | * | ||
548 | * Communications Device Class, Ethernet Control model | ||
549 | * | ||
550 | * Takes two interfaces. The DATA interface is inactive till an altsetting | ||
551 | * is selected. Configuration data includes class descriptors. | ||
552 | * | ||
553 | * This should interop with whatever the 2.4 "CDCEther.c" driver | ||
554 | * (by Brad Hards) talked with. | ||
555 | * | ||
556 | *-------------------------------------------------------------------------*/ | ||
557 | |||
558 | #include <linux/ctype.h> | ||
559 | |||
560 | |||
561 | static void dumpspeed (struct usbnet *dev, __le32 *speeds) | ||
562 | { | ||
563 | if (netif_msg_timer (dev)) | ||
564 | devinfo (dev, "link speeds: %u kbps up, %u kbps down", | ||
565 | __le32_to_cpu(speeds[0]) / 1000, | ||
566 | __le32_to_cpu(speeds[1]) / 1000); | ||
567 | } | ||
568 | |||
569 | static void cdc_status (struct usbnet *dev, struct urb *urb) | ||
570 | { | ||
571 | struct usb_cdc_notification *event; | ||
572 | |||
573 | if (urb->actual_length < sizeof *event) | ||
574 | return; | ||
575 | |||
576 | /* SPEED_CHANGE can get split into two 8-byte packets */ | ||
577 | if (test_and_clear_bit (EVENT_STS_SPLIT, &dev->flags)) { | ||
578 | dumpspeed (dev, (__le32 *) urb->transfer_buffer); | ||
579 | return; | ||
580 | } | ||
581 | |||
582 | event = urb->transfer_buffer; | ||
583 | switch (event->bNotificationType) { | ||
584 | case USB_CDC_NOTIFY_NETWORK_CONNECTION: | ||
585 | if (netif_msg_timer (dev)) | ||
586 | devdbg (dev, "CDC: carrier %s", | ||
587 | event->wValue ? "on" : "off"); | ||
588 | if (event->wValue) | ||
589 | netif_carrier_on(dev->net); | ||
590 | else | ||
591 | netif_carrier_off(dev->net); | ||
592 | break; | ||
593 | case USB_CDC_NOTIFY_SPEED_CHANGE: /* tx/rx rates */ | ||
594 | if (netif_msg_timer (dev)) | ||
595 | devdbg (dev, "CDC: speed change (len %d)", | ||
596 | urb->actual_length); | ||
597 | if (urb->actual_length != (sizeof *event + 8)) | ||
598 | set_bit (EVENT_STS_SPLIT, &dev->flags); | ||
599 | else | ||
600 | dumpspeed (dev, (__le32 *) &event[1]); | ||
601 | break; | ||
602 | // case USB_CDC_NOTIFY_RESPONSE_AVAILABLE: /* RNDIS; or unsolicited */ | ||
603 | default: | ||
604 | deverr (dev, "CDC: unexpected notification %02x!", | ||
605 | event->bNotificationType); | ||
606 | break; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | static u8 nibble (unsigned char c) | ||
611 | { | ||
612 | if (likely (isdigit (c))) | ||
613 | return c - '0'; | ||
614 | c = toupper (c); | ||
615 | if (likely (isxdigit (c))) | ||
616 | return 10 + c - 'A'; | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static inline int | ||
621 | get_ethernet_addr (struct usbnet *dev, struct usb_cdc_ether_desc *e) | ||
622 | { | ||
623 | int tmp, i; | ||
624 | unsigned char buf [13]; | ||
625 | |||
626 | tmp = usb_string (dev->udev, e->iMACAddress, buf, sizeof buf); | ||
627 | if (tmp != 12) { | ||
628 | dev_dbg (&dev->udev->dev, | ||
629 | "bad MAC string %d fetch, %d\n", e->iMACAddress, tmp); | ||
630 | if (tmp >= 0) | ||
631 | tmp = -EINVAL; | ||
632 | return tmp; | ||
633 | } | ||
634 | for (i = tmp = 0; i < 6; i++, tmp += 2) | ||
635 | dev->net->dev_addr [i] = | ||
636 | (nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]); | ||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static int cdc_bind (struct usbnet *dev, struct usb_interface *intf) | ||
641 | { | ||
642 | int status; | ||
643 | struct cdc_state *info = (void *) &dev->data; | ||
644 | |||
645 | status = usbnet_generic_cdc_bind (dev, intf); | ||
646 | if (status < 0) | ||
647 | return status; | ||
648 | |||
649 | status = get_ethernet_addr (dev, info->ether); | ||
650 | if (status < 0) { | ||
651 | usb_set_intfdata(info->data, NULL); | ||
652 | usb_driver_release_interface (&usbnet_driver, info->data); | ||
653 | return status; | ||
654 | } | ||
655 | |||
656 | /* FIXME cdc-ether has some multicast code too, though it complains | ||
657 | * in routine cases. info->ether describes the multicast support. | ||
658 | */ | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static const struct driver_info cdc_info = { | ||
663 | .description = "CDC Ethernet Device", | ||
664 | .flags = FLAG_ETHER, | ||
665 | // .check_connect = cdc_check_connect, | ||
666 | .bind = cdc_bind, | ||
667 | .unbind = usbnet_cdc_unbind, | ||
668 | .status = cdc_status, | ||
669 | }; | ||
670 | |||
671 | #endif /* CONFIG_USB_CDCETHER */ | ||
672 | |||
673 | |||
674 | |||
675 | #ifdef CONFIG_USB_PL2301 | 304 | #ifdef CONFIG_USB_PL2301 |
676 | #define HAVE_HARDWARE | 305 | #define HAVE_HARDWARE |
677 | 306 | ||
@@ -1754,23 +1383,6 @@ static const struct usb_device_id products [] = { | |||
1754 | .driver_info = (unsigned long) &rndis_info, | 1383 | .driver_info = (unsigned long) &rndis_info, |
1755 | }, | 1384 | }, |
1756 | #endif | 1385 | #endif |
1757 | |||
1758 | #ifdef CONFIG_USB_CDCETHER | ||
1759 | { | ||
1760 | /* CDC Ether uses two interfaces, not necessarily consecutive. | ||
1761 | * We match the main interface, ignoring the optional device | ||
1762 | * class so we could handle devices that aren't exclusively | ||
1763 | * CDC ether. | ||
1764 | * | ||
1765 | * NOTE: this match must come AFTER entries working around | ||
1766 | * bugs/quirks in a given product (like Zaurus, above). | ||
1767 | */ | ||
1768 | USB_INTERFACE_INFO (USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, | ||
1769 | USB_CDC_PROTO_NONE), | ||
1770 | .driver_info = (unsigned long) &cdc_info, | ||
1771 | }, | ||
1772 | #endif | ||
1773 | |||
1774 | { }, // END | 1386 | { }, // END |
1775 | }; | 1387 | }; |
1776 | MODULE_DEVICE_TABLE (usb, products); | 1388 | MODULE_DEVICE_TABLE (usb, products); |
@@ -1792,10 +1404,6 @@ static int __init usbnet_init(void) | |||
1792 | // compiler should optimize these out | 1404 | // compiler should optimize these out |
1793 | BUG_ON (sizeof (((struct sk_buff *)0)->cb) | 1405 | BUG_ON (sizeof (((struct sk_buff *)0)->cb) |
1794 | < sizeof (struct skb_data)); | 1406 | < sizeof (struct skb_data)); |
1795 | #ifdef CONFIG_USB_CDCETHER | ||
1796 | BUG_ON ((sizeof (((struct usbnet *)0)->data) | ||
1797 | < sizeof (struct cdc_state))); | ||
1798 | #endif | ||
1799 | 1407 | ||
1800 | random_ether_addr(node_id); | 1408 | random_ether_addr(node_id); |
1801 | 1409 | ||