/*
* add this endpoint to the chip instance.
* if a stream with the same endpoint already exists, append to it.
- * if not, create a new pcm stream.
+ * if not, create a new pcm stream. note, fp is added to the substream
+ * fmt_list and will be freed on the chip instance release. do not free
+ * fp or do remove it from the substream fmt_list to avoid double-free.
*/
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
int stream,
if (!csep && altsd->bNumEndpoints >= 2)
csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT);
+ /*
+ * If we can't locate the USB_DT_CS_ENDPOINT descriptor in the extra
+ * bytes after the first endpoint, go search the entire interface.
+ * Some devices have it directly *before* the standard endpoint.
+ */
+ if (!csep)
+ csep = snd_usb_find_desc(alts->extra, alts->extralen, NULL, USB_DT_CS_ENDPOINT);
+
if (!csep || csep->bLength < 7 ||
csep->bDescriptorSubtype != UAC_EP_GENERAL) {
snd_printk(KERN_WARNING "%d:%u:%d : no or invalid"
* (fp->maxpacksize & 0x7ff);
fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
fp->clock = clock;
+ INIT_LIST_HEAD(&fp->list);
/* some quirks for attributes here */
snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint %#x\n", dev->devnum, iface_no, altno, fp->endpoint);
err = snd_usb_add_audio_stream(chip, stream, fp);
if (err < 0) {
+ list_del(&fp->list); /* unlink for avoiding double-free */
kfree(fp->rate_table);
kfree(fp);
return err;