summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/usb/umodem.c112
1 files changed, 64 insertions, 48 deletions
diff --git a/sys/dev/usb/umodem.c b/sys/dev/usb/umodem.c
index 707123f80e1..4b55568eff1 100644
--- a/sys/dev/usb/umodem.c
+++ b/sys/dev/usb/umodem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: umodem.c,v 1.38 2010/09/24 08:33:59 yuo Exp $ */
+/* $OpenBSD: umodem.c,v 1.39 2010/12/02 01:37:45 jakemsr Exp $ */
/* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */
/*
@@ -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 *, struct device *, void *);
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 *match, void *aux)
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, struct device *self, void *aux)
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, struct device *self, void *aux)
// 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, struct device *self, void *aux)
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;
}