NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/40049: Openmoko Freerunner CDC Ethernet emulation does not work



>Number:         40049
>Category:       kern
>Synopsis:       Support more USB CDC Ethernet devices (eg Openmoko Freerunner)
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Nov 27 18:05:00 +0000 2008
>Originator:     Pierre Pronchery <ppronchery%bearstech.com@localhost>
>Release:        NetBSD 5.0_BETA
>Organization:
Bearstech
>Environment:
System: NetBSD syn.defora.rom 5.0_BETA NetBSD 5.0_BETA (GENERIC) #11: Thu Nov 
27 17:41:49 CET 2008 
khorben%syn.defora.rom@localhost:/usr/obj/sys/arch/amd64/compile/GENERIC amd64
Architecture: x86_64
Machine: amd64
>Description:

The Openmoko Freerunner is not successfully recognized as a CDC Ethernet 
device. FreeBSD has code for USB cable modems that makes this work (patch 
attached).

>How-To-Repeat:

Plug an Openmoko Freerunner into the USB port:
$ dmesg | grep cdce0
cdce0 at uhub0 port 2 configuration 1 interface 0
cdce0: Linux 2.6.24/s3c2410_udc RNDIS/Ethernet Gadget, rev 2.00/2.12, addr 2
cdce0: could not find data bulk in

And then the cdce0 interface does not exist.

>Fix:

With the following patch from FreeBSD:

$ ifconfig cdce0
cdce0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        address: 2a:27:01:00:00:00
        inet 192.168.0.200 netmask 0xffffff00 broadcast 192.168.0.255

Index: sys/dev/usb/if_cdce.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_cdce.c,v
retrieving revision 1.18
diff -p -u -r1.18 if_cdce.c
--- sys/dev/usb/if_cdce.c       24 Sep 2008 07:19:18 -0000      1.18
+++ sys/dev/usb/if_cdce.c       27 Nov 2008 16:54:55 -0000
@@ -154,8 +154,9 @@ USB_ATTACH(cdce)
        usb_interface_descriptor_t      *id;
        usb_endpoint_descriptor_t       *ed;
        const usb_cdc_union_descriptor_t *ud;
+       usb_config_descriptor_t         *cd;
        int                              data_ifcno;
-       int                              i;
+       int                              i, j, numalts;
        u_char                           eaddr[ETHER_ADDR_LEN];
        const usb_cdc_ethernet_descriptor_t *ue;
        char                             eaddr_str[USB_MAX_ENCODED_STRING_LEN];
@@ -202,29 +203,61 @@ USB_ATTACH(cdce)
                USB_ATTACH_ERROR_RETURN;
        }
 
-       /* Find endpoints. */
+       /*
+        * <quote>
+        *  The Data Class interface of a networking device shall have a minimum
+        *  of two interface settings. The first setting (the default interface
+        *  setting) includes no endpoints and therefore no networking traffic 
is
+        *  exchanged whenever the default interface setting is selected. One or
+        *  more additional interface settings are used for normal operation, 
and
+        *  therefore each includes a pair of endpoints (one IN, and one OUT) to
+        *  exchange network traffic. Select an alternate interface setting to
+        *  initialize the network aspects of the device and to enable the
+        *  exchange of network traffic.
+        * </quote>
+        *
+        * Some devices, most notably cable modems, include interface settings
+        * that have no IN or OUT endpoint, therefore loop through the list of 
all
+        * available interface settings looking for one with both IN and OUT
+        * endpoints.
+        */
        id = usbd_get_interface_descriptor(sc->cdce_data_iface);
-       sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
-       for (i = 0; i < id->bNumEndpoints; i++) {
-               ed = usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
-               if (!ed) {
-                       aprint_error_dev(self,
-                           "could not read endpoint descriptor\n");
+       cd = usbd_get_config_descriptor(sc->cdce_udev);
+       numalts = usbd_get_no_alts(cd, id->bInterfaceNumber);
+
+       for (j = 0; j < numalts; j++) {
+               if (usbd_set_interface(sc->cdce_data_iface, j)) {
+                       aprint_error_dev(sc->cdce_dev,
+                                       "setting alternate interface failed\n");
                        USB_ATTACH_ERROR_RETURN;
                }
-               if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
-                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
-                       sc->cdce_bulkin_no = ed->bEndpointAddress;
-               } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
-                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
-                       sc->cdce_bulkout_no = ed->bEndpointAddress;
-               } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
-                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
-                       /* XXX: CDC spec defines an interrupt pipe, but it is 
not
-                        * needed for simple host-to-host applications. */
-               } else {
-                       aprint_error_dev(self, "unexpected endpoint\n");
+               /* Find endpoints. */
+               id = usbd_get_interface_descriptor(sc->cdce_data_iface);
+               sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1;
+               for (i = 0; i < id->bNumEndpoints; i++) {
+                       ed = 
usbd_interface2endpoint_descriptor(sc->cdce_data_iface, i);
+                       if (!ed) {
+                               aprint_error_dev(self,
+                                               "could not read endpoint 
descriptor\n");
+                               USB_ATTACH_ERROR_RETURN;
+                       }
+                       if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+                                       UE_GET_XFERTYPE(ed->bmAttributes) == 
UE_BULK) {
+                               sc->cdce_bulkin_no = ed->bEndpointAddress;
+                       } else if (UE_GET_DIR(ed->bEndpointAddress) == 
UE_DIR_OUT &&
+                                       UE_GET_XFERTYPE(ed->bmAttributes) == 
UE_BULK) {
+                               sc->cdce_bulkout_no = ed->bEndpointAddress;
+                       } else if (UE_GET_DIR(ed->bEndpointAddress) == 
UE_DIR_IN &&
+                                       UE_GET_XFERTYPE(ed->bmAttributes) == 
UE_INTERRUPT) {
+                               /* XXX: CDC spec defines an interrupt pipe, but 
it is not
+                                * needed for simple host-to-host applications. 
*/
+                       } else {
+                               aprint_error_dev(self, "unexpected endpoint\n");
+                       }
                }
+               /* If we found something, try and use it... */
+               if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1))
+                       break;
        }
 
        if (sc->cdce_bulkin_no == -1) {



Home | Main Index | Thread Index | Old Index