static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting) { struct btusb_data *data = hdev->driver_data; struct usb_interface *intf = data->isoc; struct usb_endpoint_descriptor *ep_desc; int i, err; if (!data->isoc) return -ENODEV; err = usb_set_interface(data->udev, 1, altsetting); if (err < 0) { BT_ERR("%s setting interface failed (%d)", hdev->name, -err); return err; } data->isoc_altsetting = altsetting; data->isoc_tx_ep = NULL; data->isoc_rx_ep = NULL; for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { ep_desc = &intf->cur_altsetting->endpoint[i].desc; if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) { data->isoc_tx_ep = ep_desc; continue; } if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) { data->isoc_rx_ep = ep_desc; continue; } } if (!data->isoc_tx_ep || !data->isoc_rx_ep) { BT_ERR("%s invalid SCO descriptors", hdev->name); return -ENODEV; } return 0; }
static void find_usb_pipe(struct baseband_usb *usb) { struct usb_device *usbdev = usb->usb.device; struct usb_interface *intf = usb->usb.interface; unsigned char numendpoint = intf->cur_altsetting->desc.bNumEndpoints; struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint; unsigned char n; for (n = 0; n < numendpoint; n++) { if (usb_endpoint_is_isoc_in(&endpoint[n].desc)) { pr_debug("endpoint[%d] isochronous in\n", n); usb->usb.pipe.isoch.in = usb_rcvisocpipe(usbdev, endpoint[n].desc.bEndpointAddress); } else if (usb_endpoint_is_isoc_out(&endpoint[n].desc)) { pr_debug("endpoint[%d] isochronous out\n", n); usb->usb.pipe.isoch.out = usb_sndisocpipe(usbdev, endpoint[n].desc.bEndpointAddress); } else if (usb_endpoint_is_bulk_in(&endpoint[n].desc)) { pr_debug("endpoint[%d] bulk in\n", n); usb->usb.pipe.bulk.in = usb_rcvbulkpipe(usbdev, endpoint[n].desc.bEndpointAddress); } else if (usb_endpoint_is_bulk_out(&endpoint[n].desc)) { pr_debug("endpoint[%d] bulk out\n", n); usb->usb.pipe.bulk.out = usb_sndbulkpipe(usbdev, endpoint[n].desc.bEndpointAddress); } else if (usb_endpoint_is_int_in(&endpoint[n].desc)) { pr_debug("endpoint[%d] interrupt in\n", n); usb->usb.pipe.interrupt.in = usb_rcvintpipe(usbdev, endpoint[n].desc.bEndpointAddress); } else if (usb_endpoint_is_int_out(&endpoint[n].desc)) { pr_debug("endpoint[%d] interrupt out\n", n); usb->usb.pipe.interrupt.out = usb_sndintpipe(usbdev, endpoint[n].desc.bEndpointAddress); } else { pr_debug("endpoint[%d] skipped\n", n); } } }
static int detect_usb_format(struct ua101 *ua) { const struct uac_format_type_i_discrete_descriptor *fmt_capture; const struct uac_format_type_i_discrete_descriptor *fmt_playback; const struct usb_endpoint_descriptor *epd; unsigned int rate2; fmt_capture = find_format_descriptor(ua->intf[INTF_CAPTURE]); fmt_playback = find_format_descriptor(ua->intf[INTF_PLAYBACK]); if (!fmt_capture || !fmt_playback) return -ENXIO; switch (fmt_capture->bSubframeSize) { case 3: ua->format_bit = SNDRV_PCM_FMTBIT_S24_3LE; break; case 4: ua->format_bit = SNDRV_PCM_FMTBIT_S32_LE; break; default: dev_err(&ua->dev->dev, "sample width is not 24 or 32 bits\n"); return -ENXIO; } if (fmt_capture->bSubframeSize != fmt_playback->bSubframeSize) { dev_err(&ua->dev->dev, "playback/capture sample widths do not match\n"); return -ENXIO; } if (fmt_capture->bBitResolution != 24 || fmt_playback->bBitResolution != 24) { dev_err(&ua->dev->dev, "sample width is not 24 bits\n"); return -ENXIO; } ua->rate = combine_triple(fmt_capture->tSamFreq[0]); rate2 = combine_triple(fmt_playback->tSamFreq[0]); if (ua->rate != rate2) { dev_err(&ua->dev->dev, "playback/capture rates do not match: %u/%u\n", rate2, ua->rate); return -ENXIO; } switch (ua->dev->speed) { case USB_SPEED_FULL: ua->packets_per_second = 1000; break; case USB_SPEED_HIGH: ua->packets_per_second = 8000; break; default: dev_err(&ua->dev->dev, "unknown device speed\n"); return -ENXIO; } ua->capture.channels = fmt_capture->bNrChannels; ua->playback.channels = fmt_playback->bNrChannels; ua->capture.frame_bytes = fmt_capture->bSubframeSize * ua->capture.channels; ua->playback.frame_bytes = fmt_playback->bSubframeSize * ua->playback.channels; epd = &ua->intf[INTF_CAPTURE]->altsetting[1].endpoint[0].desc; if (!usb_endpoint_is_isoc_in(epd)) { dev_err(&ua->dev->dev, "invalid capture endpoint\n"); return -ENXIO; } ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd)); ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc; if (!usb_endpoint_is_isoc_out(epd)) { dev_err(&ua->dev->dev, "invalid playback endpoint\n"); return -ENXIO; } ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); return 0; }