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 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 int32_t usbd_func_selconf(irp *ip) { device_t dev = IRP_NDIS_DEV(ip); int i, j; struct ndis_softc *sc = device_get_softc(dev); struct usb_device *udev = sc->ndisusb_dev; struct usb_endpoint *ep = NULL; struct usbd_interface_information *intf; struct usbd_pipe_information *pipe; struct usbd_urb_select_configuration *selconf; union usbd_urb *urb; usb_config_descriptor_t *conf; usb_endpoint_descriptor_t *edesc; usb_error_t ret; urb = usbd_geturb(ip); selconf = &urb->uu_selconf; conf = selconf->usc_conf; if (conf == NULL) { device_printf(dev, "select configuration is NULL\n"); return usbd_usb2urb(USB_ERR_NORMAL_COMPLETION); } intf = &selconf->usc_intf; for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) { ret = usbd_set_alt_interface_index(udev, intf->uii_intfnum, intf->uii_altset); if (ret != USB_ERR_NORMAL_COMPLETION && ret != USB_ERR_IN_USE) { device_printf(dev, "setting alternate interface failed: %s\n", usbd_errstr(ret)); return usbd_usb2urb(ret); } for (j = 0; (ep = usb_endpoint_foreach(udev, ep)); j++) { if (j >= intf->uii_numeps) { device_printf(dev, "endpoint %d and above are ignored", intf->uii_numeps); break; } edesc = ep->edesc; pipe = &intf->uii_pipes[j]; pipe->upi_handle = edesc; pipe->upi_epaddr = edesc->bEndpointAddress; pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize); pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes); ret = usbd_setup_endpoint(ip, intf->uii_intfnum, edesc); if (ret != USB_ERR_NORMAL_COMPLETION) return usbd_usb2urb(ret); if (pipe->upi_type != UE_INTERRUPT) continue; /* XXX we're following linux USB's interval policy. */ if (udev->speed == USB_SPEED_LOW) pipe->upi_interval = edesc->bInterval + 5; else if (udev->speed == USB_SPEED_FULL) pipe->upi_interval = edesc->bInterval; else { int k0 = 0, k1 = 1; do { k1 = k1 * 2; k0 = k0 + 1; } while (k1 < edesc->bInterval); pipe->upi_interval = k0; } } intf = (struct usbd_interface_information *)(((char *)intf) + intf->uii_len); } return (USBD_STATUS_SUCCESS); }
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 */