umodem(4) doesn't support devices that don't have a data interface. this patch moves a chunk of code from the driver's attach function that iterates over the usb descriptors to find the data endpoint and other capabilities to a separate function. this function is then used in the match function, and if the data interface isn't found, returns UMATCH_NONE.
this keeps umodem from attaching to the MSP430 on the TI Launchapd, which has no data interface. (jasper@ has a port for mspdebug which can be used with the Launchpad through ugen(4)). this is like what I did before with umidi/uaudio ... except I don't have a umodem(4) to actually test that I didn't break this. please test this if you have a umodem(4). thanks. -- [email protected] SDF Public Access UNIX System - http://sdf.lonestar.org Index: umodem.c =================================================================== RCS file: /cvs/src/sys/dev/usb/umodem.c,v retrieving revision 1.38 diff -u -p -r1.38 umodem.c --- umodem.c 24 Sep 2010 08:33:59 -0000 1.38 +++ umodem.c 30 Nov 2010 01:04:08 -0000 @@ -91,7 +91,6 @@ struct umodem_softc { int sc_ctl_iface_no; usbd_interface_handle sc_ctl_iface; /* control interface */ - int sc_data_iface_no; usbd_interface_handle sc_data_iface; /* data interface */ int sc_cm_cap; /* CM capabilities */ @@ -148,6 +147,8 @@ void umodem_attach(struct device *, stru int umodem_detach(struct device *, int); int umodem_activate(struct device *, int); +void umodem_get_caps(struct usb_attach_arg *, int, int *, int *, int *); + struct cfdriver umodem_cd = { NULL, "umodem", DV_DULL }; @@ -160,21 +161,63 @@ const struct cfattach umodem_ca = { umodem_activate, }; +void +umodem_get_caps(struct usb_attach_arg *uaa, int ctl_iface_no, + int *data_iface_no, int *cm_cap, int *acm_cap) +{ + const usb_descriptor_t *desc; + const usb_interface_descriptor_t *id; + const usb_cdc_cm_descriptor_t *cmd; + const usb_cdc_acm_descriptor_t *acmd; + const usb_cdc_union_descriptor_t *uniond; + usbd_desc_iter_t iter; + int current_iface_no = -1; + + *cm_cap = *acm_cap = 0; + usb_desc_iter_init(uaa->device, &iter); + desc = usb_desc_iter_next(&iter); + while (desc) { + if (desc->bDescriptorType == UDESC_INTERFACE) { + id = (usb_interface_descriptor_t *)desc; + current_iface_no = id->bInterfaceNumber; + } + if (current_iface_no == ctl_iface_no && + desc->bDescriptorType == UDESC_CS_INTERFACE) { + switch(desc->bDescriptorSubtype) { + case UDESCSUB_CDC_CM: + cmd = (usb_cdc_cm_descriptor_t *)desc; + *cm_cap = cmd->bmCapabilities; + *data_iface_no = cmd->bDataInterface; + break; + case UDESCSUB_CDC_ACM: + acmd = (usb_cdc_acm_descriptor_t *)desc; + *acm_cap = acmd->bmCapabilities; + break; + case UDESCSUB_CDC_UNION: + uniond = (usb_cdc_union_descriptor_t *)desc; + *data_iface_no = uniond->bSlaveInterface[0]; + break; + } + } + desc = usb_desc_iter_next(&iter); + } +} + int umodem_match(struct device *parent, void *match, void *aux) { struct usb_attach_arg *uaa = aux; usb_interface_descriptor_t *id; usb_device_descriptor_t *dd; - int ret; + int data_iface_no, cm_cap, acm_cap, ret = UMATCH_NONE; if (uaa->iface == NULL) - return (UMATCH_NONE); + return (ret); id = usbd_get_interface_descriptor(uaa->iface); dd = usbd_get_device_descriptor(uaa->device); if (id == NULL || dd == NULL) - return (UMATCH_NONE); + return (ret); ret = UMATCH_NONE; if (UGETW(dd->idVendor) == USB_VENDOR_KYOCERA && @@ -188,6 +231,15 @@ umodem_match(struct device *parent, void id->bInterfaceProtocol == UIPROTO_CDC_AT) ret = UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; + if (ret == UMATCH_NONE) + return (ret); + + /* umodem doesn't yet support devices without a data iface */ + umodem_get_caps(uaa, id->bInterfaceNumber, &data_iface_no, + &cm_cap, &acm_cap); + if (data_iface_no == 0) + ret = UMATCH_NONE; + return (ret); } @@ -199,14 +251,8 @@ umodem_attach(struct device *parent, str usbd_device_handle dev = uaa->device; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; - usb_cdc_cm_descriptor_t *cmd; - usb_interface_descriptor_t *idesc; - const usb_cdc_acm_descriptor_t *acmd; - const usb_cdc_union_descriptor_t *uniond; - const usb_descriptor_t *desc; - usbd_desc_iter_t iter; usbd_status err; - int current_iface_no = -1; + int data_iface_no = 0; int i; struct ucom_attach_args uca; @@ -218,47 +264,17 @@ umodem_attach(struct device *parent, str // id->bInterfaceClass, id->bInterfaceSubClass); sc->sc_ctl_iface_no = id->bInterfaceNumber; - /* Get the data interface no. and capabilities */ - sc->sc_cm_cap = 0; - sc->sc_data_iface_no = 0; - sc->sc_acm_cap = 0; - usb_desc_iter_init(dev, &iter); - desc = usb_desc_iter_next(&iter); - while (desc) { - if (desc->bDescriptorType == UDESC_INTERFACE) { - idesc = (usb_interface_descriptor_t *)desc; - current_iface_no = idesc->bInterfaceNumber; - } - if (current_iface_no == sc->sc_ctl_iface_no && - 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); - } - - if (sc->sc_data_iface_no == 0) { + /* Get the capabilities. */ + umodem_get_caps(uaa, id->bInterfaceNumber, &data_iface_no, + &sc->sc_cm_cap, &sc->sc_acm_cap); + if (data_iface_no == 0) { printf("%s: no pointer to data interface\n", sc->sc_dev.dv_xname); goto bad; } printf("%s: data interface %d, has %sCM over data, has %sbreak\n", - sc->sc_dev.dv_xname, sc->sc_data_iface_no, + sc->sc_dev.dv_xname, data_iface_no, sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); @@ -267,7 +283,7 @@ umodem_attach(struct device *parent, str if (uaa->ifaces[i] != NULL) { id = usbd_get_interface_descriptor(uaa->ifaces[i]); if (id != NULL && - id->bInterfaceNumber == sc->sc_data_iface_no) { + id->bInterfaceNumber == data_iface_no) { sc->sc_data_iface = uaa->ifaces[i]; uaa->ifaces[i] = NULL; }
