int umsm_match(struct device *parent, void *match, void *aux) { struct usb_attach_arg *uaa = aux; usb_interface_descriptor_t *id; uint16_t flag; if (uaa->iface == NULL) return UMATCH_NONE; /* * Some devices (eg Huawei E220) have multiple interfaces and some * of them are of class umass. Don't claim ownership in such case. */ if (umsm_lookup(uaa->vendor, uaa->product) != NULL) { id = usbd_get_interface_descriptor(uaa->iface); flag = umsm_lookup(uaa->vendor, uaa->product)->umsm_flag; if (id == NULL || id->bInterfaceClass == UICLASS_MASS) { /* * Some high-speed modems require special care. */ if (flag & DEV_HUAWEI) { if (uaa->ifaceno != 2) return UMATCH_VENDOR_IFACESUBCLASS; else return UMATCH_NONE; } else if (flag & DEV_UMASS) { return UMATCH_VENDOR_IFACESUBCLASS; } else if (flag & DEV_TRUINSTALL) { return UMATCH_VENDOR_IFACESUBCLASS; } else return UMATCH_NONE; /* * Some devices have interfaces which fail to attach but in * addition seem to make the remaining interfaces unusable. Only * attach whitelisted interfaces in this case. */ } else if ((uaa->vendor == USB_VENDOR_MEDIATEK && uaa->product == USB_PRODUCT_MEDIATEK_DC_4COM) && !(id->bInterfaceClass == UICLASS_VENDOR && ((id->bInterfaceSubClass == 0x02 && id->bInterfaceProtocol == 0x01) || (id->bInterfaceSubClass == 0x00 && id->bInterfaceProtocol == 0x00)))) { return UMATCH_NONE; } else return UMATCH_VENDOR_IFACESUBCLASS; } return UMATCH_NONE; }
int umsm_match(struct device *parent, void *match, void *aux) { struct usb_attach_arg *uaa = aux; usb_interface_descriptor_t *id; uint16_t flag; if (uaa->iface == NULL) return UMATCH_NONE; /* * Some devices (eg Huawei E220) have multiple interfaces and some * of them are of class umass. Don't claim ownership in such case. */ if (umsm_lookup(uaa->vendor, uaa->product) != NULL) { id = usbd_get_interface_descriptor(uaa->iface); flag = umsm_lookup(uaa->vendor, uaa->product)->umsm_flag; if (id == NULL || id->bInterfaceClass == UICLASS_MASS) { /* * Some high-speed modems require special care. */ if (flag & DEV_HUAWEI) { if (uaa->ifaceno != 2) return UMATCH_VENDOR_IFACESUBCLASS; else return UMATCH_NONE; } else if (flag & DEV_UMASS) { return UMATCH_VENDOR_IFACESUBCLASS; } else if (flag & DEV_TRUINSTALL) { return UMATCH_VENDOR_IFACESUBCLASS; } else return UMATCH_NONE; } else return UMATCH_VENDOR_IFACESUBCLASS; } return UMATCH_NONE; }
void umsm_attach(struct device *parent, struct device *self, void *aux) { struct umsm_softc *sc = (struct umsm_softc *)self; struct usb_attach_arg *uaa = aux; struct ucom_attach_args uca; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; int i; bzero(&uca, sizeof(uca)); sc->sc_udev = uaa->device; sc->sc_iface = uaa->iface; sc->sc_flag = umsm_lookup(uaa->vendor, uaa->product)->umsm_flag; id = usbd_get_interface_descriptor(sc->sc_iface); /* * Some 3G modems have multiple interfaces and some of them * are umass class. Don't claim ownership in such case. */ if (id == NULL || id->bInterfaceClass == UICLASS_MASS) { /* * Some 3G modems require a special request to * enable their modem function. */ if ((sc->sc_flag & DEV_HUAWEI) && uaa->ifaceno == 0) { umsm_huawei_changemode(uaa->device); printf("%s: umass only mode. need to reattach\n", sc->sc_dev.dv_xname); } else if ((sc->sc_flag & DEV_TRUINSTALL) && uaa->ifaceno == 0) { umsm_truinstall_changemode(uaa->device); printf("%s: truinstall mode. need to reattach\n", sc->sc_dev.dv_xname); } else if ((sc->sc_flag & DEV_UMASS) && uaa->ifaceno == 0) { umsm_umass_changemode(sc); } /* * The device will reset its own bus from the device side * when its mode was changed, so just return. */ return; } sc->sc_iface_no = id->bInterfaceNumber; uca.bulkin = uca.bulkout = -1; sc->sc_intr_number = sc->sc_isize = -1; for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); if (ed == NULL) { printf("%s: no endpoint descriptor found for %d\n", sc->sc_dev.dv_xname, i); usbd_deactivate(sc->sc_udev); return; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { sc->sc_intr_number = ed->bEndpointAddress; sc->sc_isize = UGETW(ed->wMaxPacketSize); DPRINTF(("%s: find interrupt endpoint for %s\n", __func__, sc->sc_dev.dv_xname)); } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) uca.bulkin = ed->bEndpointAddress; else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) uca.bulkout = ed->bEndpointAddress; } if (uca.bulkin == -1 || uca.bulkout == -1) { printf("%s: missing endpoint\n", sc->sc_dev.dv_xname); usbd_deactivate(sc->sc_udev); return; } sc->sc_dtr = sc->sc_rts = -1; /* We need to force size as some devices lie */ uca.ibufsize = UMSMBUFSZ; uca.obufsize = UMSMBUFSZ; uca.ibufsizepad = UMSMBUFSZ; uca.opkthdrlen = 0; uca.device = sc->sc_udev; uca.iface = sc->sc_iface; uca.methods = &umsm_methods; uca.arg = sc; uca.info = NULL; uca.portno = UCOM_UNK_PORTNO; sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch); }