static int ipheth_attach(device_t dev) { struct ipheth_softc *sc = device_get_softc(dev); struct usb_ether *ue = &sc->sc_ue; struct usb_attach_arg *uaa = device_get_ivars(dev); int error; sc->sc_iface_no = uaa->info.bIfaceIndex; device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); error = usbd_set_alt_interface_index(uaa->device, uaa->info.bIfaceIndex, IPHETH_ALT_INTFNUM); if (error) { device_printf(dev, "Cannot set alternate setting\n"); goto detach; } error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); if (error) { device_printf(dev, "Cannot setup USB transfers\n"); goto detach; } ue->ue_sc = sc; ue->ue_dev = dev; ue->ue_udev = uaa->device; ue->ue_mtx = &sc->sc_mtx; ue->ue_methods = &ipheth_ue_methods; error = ipheth_get_mac_addr(sc); if (error) { device_printf(dev, "Cannot get MAC address\n"); goto detach; } error = uether_ifattach(ue); if (error) { device_printf(dev, "could not attach interface\n"); goto detach; } return (0); /* success */ detach: ipheth_detach(dev); return (ENXIO); /* failure */ }
static int rtwn_usb_attach(device_t self) { struct usb_attach_arg *uaa = device_get_ivars(self); struct rtwn_usb_softc *uc = device_get_softc(self); struct rtwn_softc *sc = &uc->uc_sc; struct ieee80211com *ic = &sc->sc_ic; int error; device_set_usb_desc(self); uc->uc_udev = uaa->device; sc->sc_dev = self; ic->ic_name = device_get_nameunit(self); /* Need to be initialized early. */ rtwn_sysctlattach(sc); rtwn_usb_sysctlattach(sc); mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); rtwn_usb_attach_methods(sc); rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); error = rtwn_usb_setup_endpoints(uc); if (error != 0) goto detach; /* Allocate Tx/Rx buffers. */ error = rtwn_usb_alloc_rx_list(sc); if (error != 0) goto detach; error = rtwn_usb_alloc_tx_list(sc); if (error != 0) goto detach; /* Generic attach. */ error = rtwn_attach(sc); if (error != 0) goto detach; return (0); detach: rtwn_usb_detach(self); /* failure */ return (ENXIO); }
static int ndisusb_attach(device_t self) { const struct drvdb_ent *db; struct ndisusb_softc *dummy = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); struct ndis_softc *sc; struct ndis_usb_type *t; driver_object *drv; int devidx = 0; device_set_usb_desc(self); db = uaa->driver_ivar; sc = (struct ndis_softc *)dummy; sc->ndis_dev = self; mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF); sc->ndis_dobj = db->windrv_object; sc->ndis_regvals = db->windrv_regvals; sc->ndis_iftype = PNPBus; sc->ndisusb_dev = uaa->device; /* Create PDO for this device instance */ drv = windrv_lookup(0, "USB Bus"); windrv_create_pdo(drv, self); /* Figure out exactly which device we matched. */ t = db->windrv_devlist; while (t->ndis_name != NULL) { if ((uaa->info.idVendor == t->ndis_vid) && (uaa->info.idProduct == t->ndis_did)) { sc->ndis_devidx = devidx; break; } t++; devidx++; } if (ndis_attach(self) != 0) return (ENXIO); return (0); }
static int g_modem_attach(device_t dev) { struct g_modem_softc *sc = device_get_softc(dev); struct usb_attach_arg *uaa = device_get_ivars(dev); int error; uint8_t iface_index[2]; DPRINTFN(11, "\n"); device_set_usb_desc(dev); lockinit(&sc->sc_lock, "g_modem", 0, 0); usb_callout_init_mtx(&sc->sc_callout, &sc->sc_lock, 0); usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_lock, 0); sc->sc_mode = G_MODEM_MODE_SILENT; iface_index[0] = uaa->info.bIfaceIndex; iface_index[1] = uaa->info.bIfaceIndex + 1; error = usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer, g_modem_config, G_MODEM_N_TRANSFER, sc, &sc->sc_lock); if (error) { DPRINTF("error=%s\n", usbd_errstr(error)); goto detach; } usbd_set_parent_iface(uaa->device, iface_index[1], iface_index[0]); lockmgr(&sc->sc_lock, LK_EXCLUSIVE); g_modem_timeout_reset(sc); g_modem_watchdog_reset(sc); lockmgr(&sc->sc_lock, LK_RELEASE); return (0); /* success */ detach: g_modem_detach(dev); return (ENXIO); /* error */ }
static int ndis_attach_usb(device_t dev) { const struct drvdb_ent *db; struct ndisusb_softc *dummy; struct usb_attach_arg *uaa; struct ndis_softc *sc; struct ndis_device_type *t; struct driver_object *drv; int devidx = 0; device_set_usb_desc(dev); dummy = device_get_softc(dev); uaa = device_get_ivars(dev); db = uaa->driver_ivar; sc = (struct ndis_softc *)dummy; sc->ndis_dev = dev; mtx_init(&sc->ndisusb_mtx, "NDIS USB", MTX_NETWORK_LOCK, MTX_DEF); sc->ndis_dobj = db->windrv_object; sc->ndis_regvals = db->windrv_regvals; sc->ndis_bus_type = NDIS_PNPBUS; sc->ndisusb_dev = uaa->device; drv = windrv_lookup(0, "USB Bus"); windrv_create_pdo(drv, dev); /* Figure out exactly which device we matched. */ for (t = db->windrv_devlist; t->name != NULL; t++, devidx++) { if ((uaa->info.idVendor == t->vendor) && (uaa->info.idProduct == t->device)) { sc->ndis_devidx = devidx; break; } } if (ndis_attach(dev) != 0) return (ENXIO); return (0); }
static int usie_attach(device_t self) { struct usie_softc *sc = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); struct ifnet *ifp; struct usb_interface *iface; struct usb_interface_descriptor *id; struct usb_device_request req; int err; uint16_t fwattr; uint8_t iface_index; uint8_t ifidx; uint8_t start; device_set_usb_desc(self); sc->sc_udev = uaa->device; sc->sc_dev = self; mtx_init(&sc->sc_mtx, "usie", MTX_NETWORK_LOCK, MTX_DEF); TASK_INIT(&sc->sc_if_status_task, 0, usie_if_status_cb, sc); TASK_INIT(&sc->sc_if_sync_task, 0, usie_if_sync_cb, sc); usb_callout_init_mtx(&sc->sc_if_sync_ch, &sc->sc_mtx, 0); mtx_lock(&sc->sc_mtx); /* set power mode to D0 */ req.bmRequestType = UT_WRITE_VENDOR_DEVICE; req.bRequest = USIE_POWER; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, 0); if (usie_do_request(sc, &req, NULL)) { mtx_unlock(&sc->sc_mtx); goto detach; } /* read fw attr */ fwattr = 0; req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = USIE_FW_ATTR; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, sizeof(fwattr)); if (usie_do_request(sc, &req, &fwattr)) { mtx_unlock(&sc->sc_mtx); goto detach; } mtx_unlock(&sc->sc_mtx); /* check DHCP supports */ DPRINTF("fwattr=%x\n", fwattr); if (!(fwattr & USIE_FW_DHCP)) { device_printf(self, "DHCP is not supported. A firmware upgrade might be needed.\n"); } /* find available interfaces */ sc->sc_nucom = 0; for (ifidx = 0; ifidx < USIE_IFACE_MAX; ifidx++) { iface = usbd_get_iface(uaa->device, ifidx); if (iface == NULL) break; id = usbd_get_interface_descriptor(iface); if ((id == NULL) || (id->bInterfaceClass != UICLASS_VENDOR)) continue; /* setup Direct IP transfer */ if (id->bInterfaceNumber >= 7 && id->bNumEndpoints == 3) { sc->sc_if_ifnum = id->bInterfaceNumber; iface_index = ifidx; DPRINTF("ifnum=%d, ifidx=%d\n", sc->sc_if_ifnum, ifidx); err = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_if_xfer, usie_if_config, USIE_IF_N_XFER, sc, &sc->sc_mtx); if (err == 0) continue; device_printf(self, "could not allocate USB transfers on " "iface_index=%d, err=%s\n", iface_index, usbd_errstr(err)); goto detach; } /* setup ucom */ if (sc->sc_nucom >= USIE_UCOM_MAX) continue; usbd_set_parent_iface(uaa->device, ifidx, uaa->info.bIfaceIndex); DPRINTF("NumEndpoints=%d bInterfaceNumber=%d\n", id->bNumEndpoints, id->bInterfaceNumber); if (id->bNumEndpoints == 2) { sc->sc_uc_xfer[sc->sc_nucom][0] = NULL; start = 1; } else start = 0; err = usbd_transfer_setup(uaa->device, &ifidx, sc->sc_uc_xfer[sc->sc_nucom] + start, usie_uc_config + start, USIE_UC_N_XFER - start, &sc->sc_ucom[sc->sc_nucom], &sc->sc_mtx); if (err != 0) { DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(err)); continue; } mtx_lock(&sc->sc_mtx); for (; start < USIE_UC_N_XFER; start++) usbd_xfer_set_stall(sc->sc_uc_xfer[sc->sc_nucom][start]); mtx_unlock(&sc->sc_mtx); sc->sc_uc_ifnum[sc->sc_nucom] = id->bInterfaceNumber; sc->sc_nucom++; /* found a port */ } if (sc->sc_nucom == 0) { device_printf(self, "no comports found\n"); goto detach; } err = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom, sc->sc_nucom, sc, &usie_uc_callback, &sc->sc_mtx); if (err != 0) { DPRINTF("ucom_attach failed\n"); goto detach; } DPRINTF("Found %d interfaces.\n", sc->sc_nucom); /* setup ifnet (Direct IP) */ sc->sc_ifp = ifp = if_alloc(IFT_OTHER); if (ifp == NULL) { device_printf(self, "Could not allocate a network interface\n"); goto detach; } if_initname(ifp, "usie", device_get_unit(self)); ifp->if_softc = sc; ifp->if_mtu = USIE_MTU_MAX; ifp->if_flags |= IFF_NOARP; ifp->if_init = usie_if_init; ifp->if_ioctl = usie_if_ioctl; ifp->if_start = usie_if_start; ifp->if_output = usie_if_output; IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_snd.ifq_drv_maxlen = ifqmaxlen; IFQ_SET_READY(&ifp->if_snd); if_attach(ifp); bpfattach(ifp, DLT_RAW, 0); if (fwattr & USIE_PM_AUTO) { usbd_set_power_mode(uaa->device, USB_POWER_MODE_SAVE); DPRINTF("enabling automatic suspend and resume\n"); } else { usbd_set_power_mode(uaa->device, USB_POWER_MODE_ON); DPRINTF("USB power is always ON\n"); } DPRINTF("device attached\n"); return (0); detach: usie_detach(self); return (ENOMEM); }
static int cdce_attach(device_t dev) { struct cdce_softc *sc = device_get_softc(dev); struct usb_ether *ue = &sc->sc_ue; struct usb_attach_arg *uaa = device_get_ivars(dev); struct usb_interface *iface; const struct usb_cdc_union_descriptor *ud; const struct usb_interface_descriptor *id; const struct usb_cdc_ethernet_descriptor *ued; const struct usb_config *pcfg; int error; uint8_t i; uint8_t data_iface_no; char eaddr_str[5 * ETHER_ADDR_LEN]; /* approx */ sc->sc_flags = USB_GET_DRIVER_INFO(uaa); sc->sc_ue.ue_udev = uaa->device; device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); ud = usbd_find_descriptor (uaa->device, NULL, uaa->info.bIfaceIndex, UDESC_CS_INTERFACE, 0 - 1, UDESCSUB_CDC_UNION, 0 - 1); if ((ud == NULL) || (ud->bLength < sizeof(*ud)) || (sc->sc_flags & CDCE_FLAG_NO_UNION)) { DPRINTFN(1, "No union descriptor!\n"); sc->sc_ifaces_index[0] = uaa->info.bIfaceIndex; sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; goto alloc_transfers; } data_iface_no = ud->bSlaveInterface[0]; for (i = 0;; i++) { iface = usbd_get_iface(uaa->device, i); if (iface) { id = usbd_get_interface_descriptor(iface); if (id && (id->bInterfaceNumber == data_iface_no)) { sc->sc_ifaces_index[0] = i; sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); break; } } else { device_printf(dev, "no data interface found\n"); goto detach; } } /* * <quote> * * The Data Class interface of a networking device shall have * a minimum of two interface settings. The first setting * (the default interface setting) includes no endpoints and * therefore no networking traffic is exchanged whenever the * default interface setting is selected. One or more * additional interface settings are used for normal * operation, and therefore each includes a pair of endpoints * (one IN, and one OUT) to exchange network traffic. Select * an alternate interface setting to initialize the network * aspects of the device and to enable the exchange of * network traffic. * * </quote> * * Some devices, most notably cable modems, include interface * settings that have no IN or OUT endpoint, therefore loop * through the list of all available interface settings * looking for one with both IN and OUT endpoints. */ alloc_transfers: pcfg = cdce_config; /* Default Configuration */ for (i = 0; i != 32; i++) { error = usbd_set_alt_interface_index(uaa->device, sc->sc_ifaces_index[0], i); if (error) break; #if CDCE_HAVE_NCM if ((i == 0) && (cdce_ncm_init(sc) == 0)) pcfg = cdce_ncm_config; #endif error = usbd_transfer_setup(uaa->device, sc->sc_ifaces_index, sc->sc_xfer, pcfg, CDCE_N_TRANSFER, sc, &sc->sc_mtx); if (error == 0) break; } if (error || (i == 32)) { device_printf(dev, "No valid alternate " "setting found\n"); goto detach; } ued = usbd_find_descriptor (uaa->device, NULL, uaa->info.bIfaceIndex, UDESC_CS_INTERFACE, 0 - 1, UDESCSUB_CDC_ENF, 0 - 1); if ((ued == NULL) || (ued->bLength < sizeof(*ued))) { error = USB_ERR_INVAL; } else { error = usbd_req_get_string_any(uaa->device, NULL, eaddr_str, sizeof(eaddr_str), ued->iMacAddress); } if (error) { /* fake MAC address */ device_printf(dev, "faking MAC address\n"); sc->sc_ue.ue_eaddr[0] = 0x2a; memcpy(&sc->sc_ue.ue_eaddr[1], &ticks, sizeof(uint32_t)); sc->sc_ue.ue_eaddr[5] = device_get_unit(dev); } else { memset(sc->sc_ue.ue_eaddr, 0, sizeof(sc->sc_ue.ue_eaddr)); for (i = 0; i != (ETHER_ADDR_LEN * 2); i++) { char c = eaddr_str[i]; if ('0' <= c && c <= '9') c -= '0'; else if (c != 0) c -= 'A' - 10; else break; c &= 0xf; if ((i & 1) == 0) c <<= 4; sc->sc_ue.ue_eaddr[i / 2] |= c; } if (uaa->usb_mode == USB_MODE_DEVICE) { /* * Do not use the same MAC address like the peer ! */ sc->sc_ue.ue_eaddr[5] ^= 0xFF; } } ue->ue_sc = sc; ue->ue_dev = dev; ue->ue_udev = uaa->device; ue->ue_mtx = &sc->sc_mtx; ue->ue_methods = &cdce_ue_methods; error = uether_ifattach(ue); if (error) { device_printf(dev, "could not attach interface\n"); goto detach; } return (0); /* success */ detach: cdce_detach(dev); return (ENXIO); /* failure */ }
static int g_audio_attach(device_t dev) { struct g_audio_softc *sc = device_get_softc(dev); struct usb_attach_arg *uaa = device_get_ivars(dev); int error; int i; uint8_t iface_index[3]; DPRINTFN(11, "\n"); device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, "g_audio", NULL, MTX_DEF); usb_callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0); usb_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0); sc->sc_mode = G_AUDIO_MODE_SILENT; sc->sc_noise_rem = 1; for (i = 0; i != G_AUDIO_FRAMES; i++) { sc->sc_data_len[0][i] = G_AUDIO_BUFSIZE / G_AUDIO_FRAMES; sc->sc_data_len[1][i] = G_AUDIO_BUFSIZE / G_AUDIO_FRAMES; } iface_index[0] = uaa->info.bIfaceIndex; iface_index[1] = uaa->info.bIfaceIndex + 1; iface_index[2] = uaa->info.bIfaceIndex + 2; error = usbd_set_alt_interface_index(uaa->device, iface_index[1], 1); if (error) { DPRINTF("alt iface setting error=%s\n", usbd_errstr(error)); goto detach; } error = usbd_set_alt_interface_index(uaa->device, iface_index[2], 1); if (error) { DPRINTF("alt iface setting error=%s\n", usbd_errstr(error)); goto detach; } error = usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer, g_audio_config, G_AUDIO_N_TRANSFER, sc, &sc->sc_mtx); if (error) { DPRINTF("error=%s\n", usbd_errstr(error)); goto detach; } usbd_set_parent_iface(uaa->device, iface_index[1], iface_index[0]); usbd_set_parent_iface(uaa->device, iface_index[2], iface_index[0]); mtx_lock(&sc->sc_mtx); usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_RD]); usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_RD]); usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC0_WR]); usbd_transfer_start(sc->sc_xfer[G_AUDIO_ISOC1_WR]); g_audio_timeout_reset(sc); g_audio_watchdog_reset(sc); mtx_unlock(&sc->sc_mtx); return (0); /* success */ detach: g_audio_detach(dev); return (ENXIO); /* error */ }
static int ubt_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct ubt_softc *sc = device_get_softc(dev); struct usb_endpoint_descriptor *ed; struct usb_interface_descriptor *id; struct usb_interface *iface; uint16_t wMaxPacketSize; uint8_t alt_index, i, j; uint8_t iface_index[2] = { 0, 1 }; device_set_usb_desc(dev); sc->sc_dev = dev; sc->sc_debug = NG_UBT_WARN_LEVEL; /* * Create Netgraph node */ if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) { UBT_ALERT(sc, "could not create Netgraph node\n"); return (ENXIO); } /* Name Netgraph node */ if (ng_name_node(sc->sc_node, device_get_nameunit(dev)) != 0) { UBT_ALERT(sc, "could not name Netgraph node\n"); NG_NODE_UNREF(sc->sc_node); return (ENXIO); } NG_NODE_SET_PRIVATE(sc->sc_node, sc); NG_NODE_FORCE_WRITER(sc->sc_node); /* * Initialize device softc structure */ /* initialize locks */ mtx_init(&sc->sc_ng_mtx, "ubt ng", NULL, MTX_DEF); mtx_init(&sc->sc_if_mtx, "ubt if", NULL, MTX_DEF | MTX_RECURSE); /* initialize packet queues */ NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN); NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN); NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN); /* initialize glue task */ TASK_INIT(&sc->sc_task, 0, ubt_task, sc); /* * Configure Bluetooth USB device. Discover all required USB * interfaces and endpoints. * * USB device must present two interfaces: * 1) Interface 0 that has 3 endpoints * 1) Interrupt endpoint to receive HCI events * 2) Bulk IN endpoint to receive ACL data * 3) Bulk OUT endpoint to send ACL data * * 2) Interface 1 then has 2 endpoints * 1) Isochronous IN endpoint to receive SCO data * 2) Isochronous OUT endpoint to send SCO data * * Interface 1 (with isochronous endpoints) has several alternate * configurations with different packet size. */ /* * For interface #1 search alternate settings, and find * the descriptor with the largest wMaxPacketSize */ wMaxPacketSize = 0; alt_index = 0; i = 0; j = 0; ed = NULL; /* * Search through all the descriptors looking for the largest * packet size: */ while ((ed = (struct usb_endpoint_descriptor *)usb_desc_foreach( usbd_get_config_descriptor(uaa->device), (struct usb_descriptor *)ed))) { if ((ed->bDescriptorType == UDESC_INTERFACE) && (ed->bLength >= sizeof(*id))) { id = (struct usb_interface_descriptor *)ed; i = id->bInterfaceNumber; j = id->bAlternateSetting; } if ((ed->bDescriptorType == UDESC_ENDPOINT) && (ed->bLength >= sizeof(*ed)) && (i == 1)) { uint16_t temp; temp = UGETW(ed->wMaxPacketSize); if (temp > wMaxPacketSize) { wMaxPacketSize = temp; alt_index = j; } } } /* Set alt configuration on interface #1 only if we found it */ if (wMaxPacketSize > 0 && usbd_set_alt_interface_index(uaa->device, 1, alt_index)) { UBT_ALERT(sc, "could not set alternate setting %d " \ "for interface 1!\n", alt_index); goto detach; } /* Setup transfers for both interfaces */ if (usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer, ubt_config, UBT_N_TRANSFER, sc, &sc->sc_if_mtx)) { UBT_ALERT(sc, "could not allocate transfers\n"); goto detach; } /* Claim all interfaces belonging to the Bluetooth part */ for (i = 1;; i++) { iface = usbd_get_iface(uaa->device, i); if (iface == NULL) break; id = usbd_get_interface_descriptor(iface); if ((id != NULL) && (id->bInterfaceClass == UICLASS_WIRELESS) && (id->bInterfaceSubClass == UISUBCLASS_RF) && (id->bInterfaceProtocol == UIPROTO_BLUETOOTH)) { usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); } } return (0); /* success */ detach: ubt_detach(dev); return (ENXIO); } /* ubt_attach */
static int uhid_attach(device_t dev) { struct usb_attach_arg *uaa = device_get_ivars(dev); struct uhid_softc *sc = device_get_softc(dev); int unit = device_get_unit(dev); int error = 0; DPRINTFN(10, "sc=%p\n", sc); device_set_usb_desc(dev); mtx_init(&sc->sc_mtx, "uhid lock", NULL, MTX_DEF | MTX_RECURSE); sc->sc_udev = uaa->device; sc->sc_iface_no = uaa->info.bIfaceNum; sc->sc_iface_index = uaa->info.bIfaceIndex; error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, sc->sc_xfer, uhid_config, UHID_N_TRANSFER, sc, &sc->sc_mtx); if (error) { DPRINTF("error=%s\n", usbd_errstr(error)); goto detach; } if (uaa->info.idVendor == USB_VENDOR_WACOM) { /* the report descriptor for the Wacom Graphire is broken */ if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE) { sc->sc_repdesc_size = sizeof(uhid_graphire_report_descr); sc->sc_repdesc_ptr = (void *)&uhid_graphire_report_descr; sc->sc_flags |= UHID_FLAG_STATIC_DESC; } else if (uaa->info.idProduct == USB_PRODUCT_WACOM_GRAPHIRE3_4X5) { static uint8_t reportbuf[] = {2, 2, 2}; /* * The Graphire3 needs 0x0202 to be written to * feature report ID 2 before it'll start * returning digitizer data. */ error = usbd_req_set_report(uaa->device, NULL, reportbuf, sizeof(reportbuf), uaa->info.bIfaceIndex, UHID_FEATURE_REPORT, 2); if (error) { DPRINTF("set report failed, error=%s (ignored)\n", usbd_errstr(error)); } sc->sc_repdesc_size = sizeof(uhid_graphire3_4x5_report_descr); sc->sc_repdesc_ptr = (void *)&uhid_graphire3_4x5_report_descr; sc->sc_flags |= UHID_FLAG_STATIC_DESC; } } else if ((uaa->info.bInterfaceClass == UICLASS_VENDOR) && (uaa->info.bInterfaceSubClass == UISUBCLASS_XBOX360_CONTROLLER) && (uaa->info.bInterfaceProtocol == UIPROTO_XBOX360_GAMEPAD)) { /* the Xbox 360 gamepad has no report descriptor */ sc->sc_repdesc_size = sizeof(uhid_xb360gp_report_descr); sc->sc_repdesc_ptr = (void *)&uhid_xb360gp_report_descr; sc->sc_flags |= UHID_FLAG_STATIC_DESC; } if (sc->sc_repdesc_ptr == NULL) { error = usbd_req_get_hid_desc(uaa->device, NULL, &sc->sc_repdesc_ptr, &sc->sc_repdesc_size, M_USBDEV, uaa->info.bIfaceIndex); if (error) { device_printf(dev, "no report descriptor\n"); goto detach; } } error = usbd_req_set_idle(uaa->device, NULL, uaa->info.bIfaceIndex, 0, 0); if (error) { DPRINTF("set idle failed, error=%s (ignored)\n", usbd_errstr(error)); } sc->sc_isize = hid_report_size (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_input, &sc->sc_iid); sc->sc_osize = hid_report_size (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_output, &sc->sc_oid); sc->sc_fsize = hid_report_size (sc->sc_repdesc_ptr, sc->sc_repdesc_size, hid_feature, &sc->sc_fid); if (sc->sc_isize > UHID_BSIZE) { DPRINTF("input size is too large, " "%d bytes (truncating)\n", sc->sc_isize); sc->sc_isize = UHID_BSIZE; } if (sc->sc_osize > UHID_BSIZE) { DPRINTF("output size is too large, " "%d bytes (truncating)\n", sc->sc_osize); sc->sc_osize = UHID_BSIZE; } if (sc->sc_fsize > UHID_BSIZE) { DPRINTF("feature size is too large, " "%d bytes (truncating)\n", sc->sc_fsize); sc->sc_fsize = UHID_BSIZE; } error = usb_fifo_attach(uaa->device, sc, &sc->sc_mtx, &uhid_fifo_methods, &sc->sc_fifo, unit, -1, uaa->info.bIfaceIndex, UID_ROOT, GID_OPERATOR, 0644); if (error) { goto detach; } return (0); /* success */ detach: uhid_detach(dev); return (ENOMEM); }