static usb_interface_descriptor_t * USBD_ParseConfigurationDescriptorEx(usb_config_descriptor_t *conf, void *start, int32_t intfnum, int32_t altset, int32_t intfclass, int32_t intfsubclass, int32_t intfproto) { struct usb_descriptor *next = NULL; usb_interface_descriptor_t *desc; while ((next = usb_desc_foreach(conf, next)) != NULL) { desc = (usb_interface_descriptor_t *)next; if (desc->bDescriptorType != UDESC_INTERFACE) continue; if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum)) continue; if (!(altset == -1 || desc->bAlternateSetting == altset)) continue; if (!(intfclass == -1 || desc->bInterfaceClass == intfclass)) continue; if (!(intfsubclass == -1 || desc->bInterfaceSubClass == intfsubclass)) continue; if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto)) continue; return (desc); } return (NULL); }
/*------------------------------------------------------------------------* * usbd_get_no_alts * * Return value: * Number of alternate settings for the given interface descriptor * pointer. If the USB descriptor is corrupt, the returned value can * be greater than the actual number of alternate settings. *------------------------------------------------------------------------*/ uint8_t usbd_get_no_alts(struct usb_config_descriptor *cd, struct usb_interface_descriptor *id) { struct usb_descriptor *desc; uint8_t n; uint8_t ifaceno; /* Reset interface count */ n = 0; /* Get the interface number */ ifaceno = id->bInterfaceNumber; /* Iterate all the USB descriptors */ desc = NULL; while ((desc = usb_desc_foreach(cd, desc))) { if ((desc->bDescriptorType == UDESC_INTERFACE) && (desc->bLength >= sizeof(*id))) { id = (struct usb_interface_descriptor *)desc; if (id->bInterfaceNumber == ifaceno) { n++; if (n == 0xFF) break; /* crazy */ } } } return (n); }
/*------------------------------------------------------------------------* * usb_idesc_foreach * * This function will iterate the interface descriptors in the config * descriptor. The parse state structure should be zeroed before * calling this function the first time. * * Return values: * NULL: End of descriptors * Else: A valid interface descriptor *------------------------------------------------------------------------*/ struct usb_interface_descriptor * usb_idesc_foreach(struct usb_config_descriptor *cd, struct usb_idesc_parse_state *ps) { struct usb_interface_descriptor *id; uint8_t new_iface; /* retrieve current descriptor */ id = (struct usb_interface_descriptor *)ps->desc; /* default is to start a new interface */ new_iface = 1; while (1) { id = (struct usb_interface_descriptor *) usb_desc_foreach(cd, (struct usb_descriptor *)id); if (id == NULL) break; if ((id->bDescriptorType == UDESC_INTERFACE) && (id->bLength >= sizeof(*id))) { if (ps->iface_no_last == id->bInterfaceNumber) new_iface = 0; ps->iface_no_last = id->bInterfaceNumber; break; } } if (ps->desc == NULL) { /* first time or zero descriptors */ } else if (new_iface) { /* new interface */ ps->iface_index ++; ps->iface_index_alt = 0; } else { /* new alternate interface */ ps->iface_index_alt ++; } #if (USB_IFACE_MAX <= 0) #error "USB_IFACE_MAX must be defined greater than zero" #endif /* check for too many interfaces */ if (ps->iface_index >= USB_IFACE_MAX) { DPRINTF("Interface limit reached\n"); id = NULL; } /* store and return current descriptor */ ps->desc = (struct usb_descriptor *)id; return (id); }
/*------------------------------------------------------------------------* * usbd_get_no_descriptors * * This function will count the total number of descriptors in the * configuration descriptor of type "type". *------------------------------------------------------------------------*/ uint8_t usbd_get_no_descriptors(struct usb_config_descriptor *cd, uint8_t type) { struct usb_descriptor *desc = NULL; uint8_t count = 0; while ((desc = usb_desc_foreach(cd, desc))) { if (desc->bDescriptorType == type) { count++; if (count == 0xFF) break; /* crazy */ } } return (count); }
/*------------------------------------------------------------------------* * usb_idesc_foreach * * This function will iterate the interface descriptors in the config * descriptor. The parse state structure should be zeroed before * calling this function the first time. * * Return values: * NULL: End of descriptors * Else: A valid interface descriptor *------------------------------------------------------------------------*/ struct usb_interface_descriptor * usb_idesc_foreach(struct usb_config_descriptor *cd, struct usb_idesc_parse_state *ps) { struct usb_interface_descriptor *id; uint8_t new_iface; /* retrieve current descriptor */ id = (struct usb_interface_descriptor *)ps->desc; /* default is to start a new interface */ new_iface = 1; while (1) { id = (struct usb_interface_descriptor *) usb_desc_foreach(cd, (struct usb_descriptor *)id); if (id == NULL) break; if ((id->bDescriptorType == UDESC_INTERFACE) && (id->bLength >= sizeof(*id))) { if (ps->iface_no_last == id->bInterfaceNumber) new_iface = 0; ps->iface_no_last = id->bInterfaceNumber; break; } } if (ps->desc == NULL) { /* first time */ } else if (new_iface) { /* new interface */ ps->iface_index ++; ps->iface_index_alt = 0; } else { /* new alternate interface */ ps->iface_index_alt ++; } /* store and return current descriptor */ ps->desc = (struct usb_descriptor *)id; return (id); }
/*------------------------------------------------------------------------* * usb_edesc_foreach * * This function will iterate all the endpoint descriptors within an * interface descriptor. Starting value for the "ped" argument should * be a valid interface descriptor. * * Return values: * NULL: End of descriptors * Else: A valid endpoint descriptor *------------------------------------------------------------------------*/ struct usb_endpoint_descriptor * usb_edesc_foreach(struct usb_config_descriptor *cd, struct usb_endpoint_descriptor *ped) { struct usb_descriptor *desc; desc = ((struct usb_descriptor *)ped); while ((desc = usb_desc_foreach(cd, desc))) { if (desc->bDescriptorType == UDESC_INTERFACE) { break; } if (desc->bDescriptorType == UDESC_ENDPOINT) { if (desc->bLength < sizeof(*ped)) { /* endpoint descriptor is invalid */ break; } return ((struct usb_endpoint_descriptor *)desc); } } return (NULL); }
/*------------------------------------------------------------------------* * usb_hw_ep_get_needs * * This function will figure out the type and number of endpoints * which are needed for an USB configuration. * * Return values: * 0: Success. * Else: Failure. *------------------------------------------------------------------------*/ static uint8_t usb_hw_ep_get_needs(struct usb_hw_ep_scratch *ues, uint8_t ep_type, uint8_t is_complete) { const struct usb_hw_ep_profile *pf; struct usb_hw_ep_scratch_sub *ep_iface; struct usb_hw_ep_scratch_sub *ep_curr; struct usb_hw_ep_scratch_sub *ep_max; struct usb_hw_ep_scratch_sub *ep_end; struct usb_descriptor *desc; struct usb_interface_descriptor *id; struct usb_endpoint_descriptor *ed; enum usb_dev_speed speed; uint16_t wMaxPacketSize; uint16_t temp; uint8_t ep_no; ep_iface = ues->ep_max; ep_curr = ues->ep_max; ep_end = ues->ep + USB_EP_MAX; ep_max = ues->ep_max; desc = NULL; speed = usbd_get_speed(ues->udev); repeat: while ((desc = usb_desc_foreach(ues->cd, desc))) { if ((desc->bDescriptorType == UDESC_INTERFACE) && (desc->bLength >= sizeof(*id))) { id = (void *)desc; if (id->bAlternateSetting == 0) { /* going forward */ ep_iface = ep_max; } else { /* reset */ ep_curr = ep_iface; } } if ((desc->bDescriptorType == UDESC_ENDPOINT) && (desc->bLength >= sizeof(*ed))) { ed = (void *)desc; goto handle_endpoint_desc; } } ues->ep_max = ep_max; return (0); handle_endpoint_desc: temp = (ed->bmAttributes & UE_XFERTYPE); if (temp == ep_type) { if (ep_curr == ep_end) { /* too many endpoints */ return (1); /* failure */ } wMaxPacketSize = UGETW(ed->wMaxPacketSize); if ((wMaxPacketSize & 0xF800) && (speed == USB_SPEED_HIGH)) { /* handle packet multiplier */ temp = (wMaxPacketSize >> 11) & 3; wMaxPacketSize &= 0x7FF; if (temp == 1) { wMaxPacketSize *= 2; } else { wMaxPacketSize *= 3; } } /* * Check if we have a fixed endpoint number, else the * endpoint number is allocated dynamically: */ ep_no = (ed->bEndpointAddress & UE_ADDR); if (ep_no != 0) { /* get HW endpoint profile */ (ues->methods->get_hw_ep_profile) (ues->udev, &pf, ep_no); if (pf == NULL) { /* HW profile does not exist - failure */ DPRINTFN(0, "Endpoint profile %u " "does not exist\n", ep_no); return (1); } /* reserve fixed endpoint number */ if (ep_type == UE_CONTROL) { ues->bmInAlloc[ep_no / 8] |= (1 << (ep_no % 8)); ues->bmOutAlloc[ep_no / 8] |= (1 << (ep_no % 8)); if ((pf->max_in_frame_size < wMaxPacketSize) || (pf->max_out_frame_size < wMaxPacketSize)) { DPRINTFN(0, "Endpoint profile %u " "has too small buffer\n", ep_no); return (1); } } else if (ed->bEndpointAddress & UE_DIR_IN) { ues->bmInAlloc[ep_no / 8] |= (1 << (ep_no % 8)); if (pf->max_in_frame_size < wMaxPacketSize) { DPRINTFN(0, "Endpoint profile %u " "has too small buffer\n", ep_no); return (1); } } else { ues->bmOutAlloc[ep_no / 8] |= (1 << (ep_no % 8)); if (pf->max_out_frame_size < wMaxPacketSize) { DPRINTFN(0, "Endpoint profile %u " "has too small buffer\n", ep_no); return (1); } } } else if (is_complete) { /* check if we have enough buffer space */ if (wMaxPacketSize > ep_curr->max_frame_size) { return (1); /* failure */ } if (ed->bEndpointAddress & UE_DIR_IN) { ed->bEndpointAddress = ep_curr->hw_endpoint_in; } else { ed->bEndpointAddress = ep_curr->hw_endpoint_out; } } else { /* compute the maximum frame size */ if (ep_curr->max_frame_size < wMaxPacketSize) { ep_curr->max_frame_size = wMaxPacketSize; } if (temp == UE_CONTROL) { ep_curr->needs_in = 1; ep_curr->needs_out = 1; } else { if (ed->bEndpointAddress & UE_DIR_IN) { ep_curr->needs_in = 1; } else { ep_curr->needs_out = 1; } } ep_curr->needs_ep_type = ep_type; } ep_curr++; if (ep_max < ep_curr) { ep_max = ep_curr; } }
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 */