Subject: kern/29754: umodem doesn't support devices without CM or ACM
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <rix@estpak.ee>
List: netbsd-bugs
Date: 03/21/2005 14:38:00
>Number: 29754
>Category: kern
>Synopsis: umodem doesn't support devices without CM or ACM
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Mar 21 14:38:00 +0000 2005
>Originator: rivo nurges
>Release: NetBSD 2.99.16
>Organization:
>Environment:
System: NetBSD anarchy.estpak.ee 2.99.16 NetBSD 2.99.16 (ANARCHY) #56: Mon Mar 21 14:03:29 UTC 2005 rix@anarchy.estpak.ee:/export/src/sys/arch/i386/compile/ANARCHY i386
Architecture: i386
Machine: i386
>Description:
Nokia 9300 with DKU-2 usb cable doesn't have CM and ACM descriptors but
has UNION descriptor pointing to data interface. NetBSD's current
driver doesn't handle this.
>How-To-Repeat:
>Fix:
Here is a patch.
Index: sys/dev/usb/umodem.c
===================================================================
RCS file: /NetBSD/src/sys/dev/usb/umodem.c,v
retrieving revision 1.49
diff -u -3 -p -r1.49 umodem.c
--- sys/dev/usb/umodem.c 23 Oct 2004 13:28:26 -0000 1.49
+++ sys/dev/usb/umodem.c 21 Mar 2005 14:10:51 -0000
@@ -129,8 +129,6 @@ Static usbd_status umodem_set_comm_featu
Static usbd_status umodem_set_line_coding(struct umodem_softc *sc,
usb_cdc_line_state_t *state);
-Static void umodem_get_caps(usbd_device_handle, int *, int *);
-
Static void umodem_get_status(void *, int portno, u_char *lsr, u_char *msr);
Static void umodem_set(void *, int, int, int);
Static void umodem_dtr(struct umodem_softc *, int);
@@ -160,7 +158,6 @@ USB_MATCH(umodem)
{
USB_MATCH_START(umodem, uaa);
usb_interface_descriptor_t *id;
- int cm, acm;
if (uaa->iface == NULL)
return (UMATCH_NONE);
@@ -172,12 +169,6 @@ USB_MATCH(umodem)
id->bInterfaceProtocol != UIPROTO_CDC_AT)
return (UMATCH_NONE);
- umodem_get_caps(uaa->device, &cm, &acm);
- if (!(cm & USB_CDC_CM_DOES_CM) ||
- !(cm & USB_CDC_CM_OVER_DATA) ||
- !(acm & USB_CDC_ACM_HAS_LINE))
- return (UMATCH_NONE);
-
return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO);
}
@@ -188,9 +179,12 @@ USB_ATTACH(umodem)
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
const usb_cdc_cm_descriptor_t *cmd;
+ const usb_cdc_acm_descriptor_t *acmd;
+ const usb_cdc_union_descriptor_t *uniond;
+ const usb_descriptor_t *desc;
+ usbd_desc_iter_t iter;
char devinfo[1024];
usbd_status err;
- int data_ifcno;
int i;
struct ucom_attach_args uca;
@@ -205,19 +199,38 @@ USB_ATTACH(umodem)
devinfo, id->bInterfaceClass, id->bInterfaceSubClass);
sc->sc_ctl_iface_no = id->bInterfaceNumber;
- umodem_get_caps(dev, &sc->sc_cm_cap, &sc->sc_acm_cap);
+ /* Get the data interface no. and capabilities*/
+ usb_desc_iter_init(dev, &iter);
+ desc = usb_desc_iter_next(&iter);
+ while(desc) {
+ if(desc->bDescriptorType == UDESC_CS_INTERFACE) {
+ switch(desc->bDescriptorSubtype) {
+ case UDESCSUB_CDC_CM:
+ cmd = (usb_cdc_cm_descriptor_t *)desc;
+ sc->sc_cm_cap = cmd->bmCapabilities;
+ sc->sc_data_iface_no = cmd->bDataInterface;
+ break;
+ case UDESCSUB_CDC_ACM:
+ acmd = (usb_cdc_acm_descriptor_t *)desc;
+ sc->sc_acm_cap = acmd->bmCapabilities;
+ break;
+ case UDESCSUB_CDC_UNION:
+ uniond = (usb_cdc_union_descriptor_t *)desc;
+ sc->sc_data_iface_no = uniond->bSlaveInterface[0];
+ break;
+ }
+ }
+ desc = usb_desc_iter_next(&iter);
+ }
- /* Get the data interface no. */
- cmd = (usb_cdc_cm_descriptor_t *)usb_find_desc(dev, UDESC_CS_INTERFACE,
- UDESCSUB_CDC_CM);
- if (cmd == NULL) {
- printf("%s: no CM descriptor\n", USBDEVNAME(sc->sc_dev));
+ if (sc->sc_data_iface_no == 0) {
+ printf("%s: no pointer to data interface\n",
+ USBDEVNAME(sc->sc_dev));
goto bad;
}
- sc->sc_data_iface_no = data_ifcno = cmd->bDataInterface;
printf("%s: data interface %d, has %sCM over data, has %sbreak\n",
- USBDEVNAME(sc->sc_dev), data_ifcno,
+ USBDEVNAME(sc->sc_dev), sc->sc_data_iface_no,
sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ",
sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no ");
@@ -225,7 +238,8 @@ USB_ATTACH(umodem)
for (i = 0; i < uaa->nifaces; i++) {
if (uaa->ifaces[i] != NULL) {
id = usbd_get_interface_descriptor(uaa->ifaces[i]);
- if (id != NULL && id->bInterfaceNumber == data_ifcno) {
+ if (id != NULL &&
+ id->bInterfaceNumber == sc->sc_data_iface_no) {
sc->sc_data_iface = uaa->ifaces[i];
uaa->ifaces[i] = NULL;
}
@@ -443,31 +457,6 @@ umodem_intr(usbd_xfer_handle xfer, usbd_
sc->sc_notify_buf.bNotification));
break;
}
-}
-
-void
-umodem_get_caps(usbd_device_handle dev, int *cm, int *acm)
-{
- const usb_cdc_cm_descriptor_t *cmd;
- const usb_cdc_acm_descriptor_t *cad;
-
- *cm = *acm = 0;
-
- cmd = (usb_cdc_cm_descriptor_t *)usb_find_desc(dev, UDESC_CS_INTERFACE,
- UDESCSUB_CDC_CM);
- if (cmd == NULL) {
- DPRINTF(("umodem_get_desc: no CM desc\n"));
- return;
- }
- *cm = cmd->bmCapabilities;
-
- cad = (usb_cdc_acm_descriptor_t *)usb_find_desc(dev, UDESC_CS_INTERFACE,
- UDESCSUB_CDC_ACM);
- if (cad == NULL) {
- DPRINTF(("umodem_get_desc: no ACM desc\n"));
- return;
- }
- *acm = cad->bmCapabilities;
}
void