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 data_iface_idx, cm_cap, acm_cap, ret = UMATCH_NONE; if (uaa->iface == NULL) return (ret); id = usbd_get_interface_descriptor(uaa->iface); dd = usbd_get_device_descriptor(uaa->device); if (id == NULL || dd == NULL) return (ret); ret = UMATCH_NONE; /* protocol of 0 so won't match the test below */ if (UGETW(dd->idVendor) == USB_VENDOR_ATMEL && UGETW(dd->idProduct) == USB_PRODUCT_ATMEL_AT91_CDC_ACM) ret = UMATCH_VENDOR_PRODUCT; if (UGETW(dd->idVendor) == USB_VENDOR_KYOCERA && UGETW(dd->idProduct) == USB_PRODUCT_KYOCERA_AHK3001V && id->bInterfaceNumber == 0) ret = UMATCH_VENDOR_PRODUCT; if (ret == UMATCH_NONE && id->bInterfaceClass == UICLASS_CDC && id->bInterfaceSubClass == UISUBCLASS_ABSTRACT_CONTROL_MODEL && id->bInterfaceProtocol == UIPROTO_CDC_AT) ret = UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; if (ret == UMATCH_NONE) return (ret); /* umodem doesn't support devices without a data iface */ umodem_get_caps(uaa, id->bInterfaceNumber, &data_iface_idx, &cm_cap, &acm_cap); if (data_iface_idx == -1) ret = UMATCH_NONE; return (ret); }
int umodem_match(device_t parent, cfdata_t match, void *aux) { struct usbif_attach_arg *uiaa = aux; usb_interface_descriptor_t *id; int cm, acm; if (uiaa->uiaa_class != UICLASS_CDC || uiaa->uiaa_subclass != UISUBCLASS_ABSTRACT_CONTROL_MODEL || !(uiaa->uiaa_proto == UIPROTO_CDC_NOCLASS || uiaa->uiaa_proto == UIPROTO_CDC_AT)) return UMATCH_NONE; id = usbd_get_interface_descriptor(uiaa->uiaa_iface); if (umodem_get_caps(uiaa->uiaa_device, &cm, &acm, id) == -1) return UMATCH_NONE; return UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO; }
static int umodem_match(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); usb_interface_descriptor_t *id; int cm, acm; if (uaa->iface == NULL) return (UMATCH_NONE); id = usbd_get_interface_descriptor(uaa->iface); if (id == NULL || id->bInterfaceClass != UICLASS_CDC || id->bInterfaceSubClass != UISUBCLASS_ABSTRACT_CONTROL_MODEL || id->bInterfaceProtocol != UIPROTO_CDC_AT) return (UMATCH_NONE); if (umodem_get_caps(uaa->device, &cm, &acm, id) == -1) return (UMATCH_NONE); return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); }
static int umodem_attach(device_t self) { struct umodem_softc *sc = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); usbd_device_handle dev = uaa->device; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; const char *devname; usbd_status err; int data_ifcno; int i; struct ucom_softc *ucom; ucom = &sc->sc_ucom; ucom->sc_dev = self; sc->sc_dev = self; ucom->sc_udev = dev; ucom->sc_iface = uaa->iface; sc->sc_udev = dev; sc->sc_ctl_iface = uaa->iface; devname = device_get_nameunit(sc->sc_dev); /* XXX ? use something else ? XXX */ id = usbd_get_interface_descriptor(sc->sc_ctl_iface); sc->sc_ctl_iface_no = id->bInterfaceNumber; sc->sc_data_iface_no = data_ifcno = umodem_get_caps(dev, &sc->sc_cm_cap, &sc->sc_acm_cap, id); if (data_ifcno == -1) { kprintf("%s: no pointer to data interface\n", devname); goto bad; } kprintf("%s: data interface %d, has %sCM over data, has %sbreak\n", devname, data_ifcno, sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); /* Get the data interface too. */ 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) { sc->sc_data_iface = uaa->ifaces[i]; uaa->ifaces[i] = NULL; } } } if (sc->sc_data_iface == NULL) { kprintf("%s: no data interface\n", devname); goto bad; } ucom->sc_iface = sc->sc_data_iface; /* * Find the bulk endpoints. * Iterate over all endpoints in the data interface and take note. */ ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1; id = usbd_get_interface_descriptor(sc->sc_data_iface); for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i); if (ed == NULL) { kprintf("%s: no endpoint descriptor for %d\n", devname, i); goto bad; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { ucom->sc_bulkin_no = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { ucom->sc_bulkout_no = ed->bEndpointAddress; } } if (ucom->sc_bulkin_no == -1) { kprintf("%s: Could not find data bulk in\n", devname); goto bad; } if (ucom->sc_bulkout_no == -1) { kprintf("%s: Could not find data bulk out\n", devname); goto bad; } if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_ASSUME_CM_OVER_DATA) { DPRINTF(("Quirk says to assume CM over data\n")); sc->sc_cm_over_data = 1; } else { if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) { if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE) err = umodem_set_comm_feature(sc, UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED); else err = 0; if (err) { kprintf("%s: could not set data multiplex mode\n", devname); goto bad; } sc->sc_cm_over_data = 1; } } /* * The standard allows for notification messages (to indicate things * like a modem hangup) to come in via an interrupt endpoint * off of the control interface. Iterate over the endpoints on * the control interface and see if there are any interrupt * endpoints; if there are, then register it. */ sc->sc_ctl_notify = -1; sc->sc_notify_pipe = NULL; for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i); if (ed == NULL) continue; if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { kprintf("%s: status change notification available\n", devname); sc->sc_ctl_notify = ed->bEndpointAddress; } } sc->sc_dtr = -1; ucom->sc_parent = sc; ucom->sc_portno = UCOM_UNK_PORTNO; /* bulkin, bulkout set above */ ucom->sc_ibufsize = UMODEMIBUFSIZE; ucom->sc_obufsize = UMODEMOBUFSIZE; ucom->sc_ibufsizepad = UMODEMIBUFSIZE; ucom->sc_opkthdrlen = 0; ucom->sc_callback = &umodem_callback; ucom_attach(&sc->sc_ucom); return 0; bad: ucom->sc_dying = 1; return ENXIO; }
void umodem_attach(struct device *parent, struct device *self, void *aux) { struct umodem_softc *sc = (struct umodem_softc *)self; struct usb_attach_arg *uaa = aux; struct usbd_device *dev = uaa->device; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; usbd_status err; int data_iface_idx = -1; int i; struct ucom_attach_args uca; sc->sc_udev = dev; sc->sc_ctl_iface = uaa->iface; id = usbd_get_interface_descriptor(sc->sc_ctl_iface); //printf("%s: iclass %d/%d\n", sc->sc_dev.dv_xname, // id->bInterfaceClass, id->bInterfaceSubClass); sc->sc_ctl_iface_no = id->bInterfaceNumber; /* Get the capabilities. */ umodem_get_caps(uaa, id->bInterfaceNumber, &data_iface_idx, &sc->sc_cm_cap, &sc->sc_acm_cap); usbd_claim_iface(sc->sc_udev, data_iface_idx); sc->sc_data_iface = uaa->ifaces[data_iface_idx]; id = usbd_get_interface_descriptor(sc->sc_data_iface); printf("%s: data interface %d, has %sCM over data, has %sbreak\n", sc->sc_dev.dv_xname, id->bInterfaceNumber, sc->sc_cm_cap & USB_CDC_CM_OVER_DATA ? "" : "no ", sc->sc_acm_cap & USB_CDC_ACM_HAS_BREAK ? "" : "no "); /* * Find the bulk endpoints. * Iterate over all endpoints in the data interface and take note. */ uca.bulkin = uca.bulkout = -1; for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i); if (ed == NULL) { printf("%s: no endpoint descriptor for %d\n", sc->sc_dev.dv_xname, i); goto bad; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { uca.bulkin = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && (ed->bmAttributes & UE_XFERTYPE) == UE_BULK) { uca.bulkout = ed->bEndpointAddress; } } if (uca.bulkin == -1) { printf("%s: Could not find data bulk in\n", sc->sc_dev.dv_xname); goto bad; } if (uca.bulkout == -1) { printf("%s: Could not find data bulk out\n", sc->sc_dev.dv_xname); goto bad; } if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_ASSUME_CM_OVER_DATA) { sc->sc_cm_over_data = 1; } else { if (sc->sc_cm_cap & USB_CDC_CM_OVER_DATA) { if (sc->sc_acm_cap & USB_CDC_ACM_HAS_FEATURE) err = umodem_set_comm_feature(sc, UCDC_ABSTRACT_STATE, UCDC_DATA_MULTIPLEXED); else err = 0; if (err) { printf("%s: could not set data multiplex mode\n", sc->sc_dev.dv_xname); goto bad; } sc->sc_cm_over_data = 1; } } /* * The standard allows for notification messages (to indicate things * like a modem hangup) to come in via an interrupt endpoint * off of the control interface. Iterate over the endpoints on * the control interface and see if there are any interrupt * endpoints; if there are, then register it. */ sc->sc_ctl_notify = -1; sc->sc_notify_pipe = NULL; id = usbd_get_interface_descriptor(sc->sc_ctl_iface); for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i); if (ed == NULL) continue; if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { printf("%s: status change notification available\n", sc->sc_dev.dv_xname); sc->sc_ctl_notify = ed->bEndpointAddress; } } sc->sc_dtr = -1; uca.portno = UCOM_UNK_PORTNO; /* bulkin, bulkout set above */ uca.ibufsize = UMODEMIBUFSIZE; uca.obufsize = UMODEMOBUFSIZE; uca.ibufsizepad = UMODEMIBUFSIZE; uca.opkthdrlen = 0; uca.device = sc->sc_udev; uca.iface = sc->sc_data_iface; uca.methods = &umodem_methods; uca.arg = sc; uca.info = NULL; DPRINTF(("umodem_attach: sc=%p\n", sc)); sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); return; bad: usbd_deactivate(sc->sc_udev); }