Takashi Iwai wrote:
> could you resend the patch if finished?

The new parsing code works with my device (UA-1A), but I couldn't test the
changes for the mixer and the UA-20.


- removed buffer allocation for class-specific descriptors; get them from
  intf->extra and ep->extra.
- accept USB_CLASS_VENDOR_SPECIFIC when parsing audio interfaces
- added quirk type for interfaces having standard descriptors
- added quirk for UA-20


Index: alsa-kernel/usb/usbaudio.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbaudio.c,v
retrieving revision 1.45
diff -u -r1.45 usbaudio.c
--- alsa-kernel/usb/usbaudio.c  25 Feb 2003 12:35:45 -0000      1.45
+++ alsa-kernel/usb/usbaudio.c  28 Feb 2003 10:34:19 -0000
@@ -1556,15 +1556,11 @@

 /*
  * parse descriptor buffer and return the pointer starting the given
- * descriptor type and interface.
- * if altsetting is not -1, seek the buffer until the matching alternate
- * setting is found.
+ * descriptor type.
  */
-void *snd_usb_find_desc(void *descstart, int desclen, void *after,
-                       u8 dtype, int iface, int altsetting)
+void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype)
 {
        u8 *p, *end, *next;
-       int ifc = -1, as = -1;

        p = descstart;
        end = p + desclen;
@@ -1574,15 +1570,7 @@
                next = p + p[0];
                if (next > end)
                        return NULL;
-               if (p[1] == USB_DT_INTERFACE) {
-                       /* minimum length of interface descriptor */
-                       if (p[0] < 9)
-                               return NULL;
-                       ifc = p[2];
-                       as = p[3];
-               }
-               if (p[1] == dtype && (!after || (void *)p > after) &&
-                   (iface == -1 || iface == ifc) && (altsetting == -1 || altsetting 
== as)) {
+               if (p[1] == dtype && (!after || (void *)p > after)) {
                        return p;
                }
                p = next;
@@ -1593,12 +1581,12 @@
 /*
  * find a class-specified interface descriptor with the given subtype.
  */
-void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype, int 
iface, int altsetting)
+void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype)
 {
        unsigned char *p = after;

        while ((p = snd_usb_find_desc(buffer, buflen, p,
-                                     USB_DT_CS_INTERFACE, iface, altsetting)) != 
NULL) {
+                                     USB_DT_CS_INTERFACE)) != NULL) {
                if (p[0] >= 3 && p[2] == dsubtype)
                        return p;
        }
@@ -1950,7 +1938,7 @@
 }


-static int parse_audio_endpoints(snd_usb_audio_t *chip, unsigned char *buffer, int 
buflen, int iface_no)
+static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
 {
        struct usb_device *dev;
        struct usb_host_config *config;
@@ -1971,7 +1959,8 @@
                alts = &iface->altsetting[i];
                altsd = get_iface_desc(alts);
                /* skip invalid one */
-               if (altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+               if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
+                    altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
                    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING ||
                    altsd->bNumEndpoints < 1)
                        continue;
@@ -1985,7 +1974,7 @@
                altno = altsd->bAlternateSetting;

                /* get audio formats */
-               fmt = snd_usb_find_csint_desc(buffer, buflen, NULL, AS_GENERAL, 
iface_no, altno);
+               fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, 
AS_GENERAL);
                if (!fmt) {
                        snd_printk(KERN_ERR "%d:%u:%d : AS_GENERAL descriptor not 
found\n",
                                   dev->devnum, iface_no, altno);
@@ -2001,7 +1990,7 @@
                format = (fmt[6] << 8) | fmt[5]; /* remember the format value */

                /* get format type */
-               fmt = snd_usb_find_csint_desc(buffer, buflen, NULL, FORMAT_TYPE, 
iface_no, altno);
+               fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, 
FORMAT_TYPE);
                if (!fmt) {
                        snd_printk(KERN_ERR "%d:%u:%d : no FORMAT_TYPE desc\n",
                                   dev->devnum, iface_no, altno);
@@ -2031,7 +2020,7 @@
                        continue;
                }

-               csep = snd_usb_find_desc(buffer, buflen, NULL, USB_DT_CS_ENDPOINT, 
iface_no, altno);
+               csep = snd_usb_find_desc(alts->endpoint[0].extra, 
alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT);
                if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) {
                        snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific 
endpoint descriptor\n",
                                   dev->devnum, iface_no, altno);
@@ -2119,17 +2108,19 @@
 /*
  * parse audio control descriptor and create pcm/midi streams
  */
-static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif,
-                                 unsigned char *buffer, int buflen)
+static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif)
 {
        struct usb_device *dev = chip->dev;
        struct usb_host_config *config;
+       struct usb_host_interface *host_iface;
        struct usb_interface *iface;
        unsigned char *p1;
        int i, j;

        /* find audiocontrol interface */
-       if (!(p1 = snd_usb_find_csint_desc(buffer, buflen, NULL, HEADER, ctrlif, -1))) 
{
+       config = dev->actconfig;
+       host_iface = &config->interface[ctrlif].altsetting[0];
+       if (!(p1 = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, 
NULL, HEADER))) {
                snd_printk(KERN_ERR "cannot find HEADER\n");
                return -EINVAL;
        }
@@ -2141,7 +2132,6 @@
        /*
         * parse all USB audio streaming interfaces
         */
-       config = dev->actconfig;
        for (i = 0; i < p1[7]; i++) {
                struct usb_host_interface *alts;
                struct usb_interface_descriptor *altsd;
@@ -2158,7 +2148,8 @@
                }
                alts = &iface->altsetting[0];
                altsd = get_iface_desc(alts);
-               if (altsd->bInterfaceClass == USB_CLASS_AUDIO &&
+               if ((altsd->bInterfaceClass == USB_CLASS_AUDIO ||
+                    altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
                    altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
                        if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) {
                                snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer 
device\n", dev->devnum, ctrlif, j);
@@ -2167,13 +2158,14 @@
                        usb_driver_claim_interface(&usb_audio_driver, iface, (void 
*)-1L);
                        continue;
                }
-               if (altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+               if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
+                    altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
                    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) {
                        snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported 
interface %d\n", dev->devnum, ctrlif, j, altsd->bInterfaceClass);
                        /* skip non-supported classes */
                        continue;
                }
-               if (! parse_audio_endpoints(chip, buffer, buflen, j)) {
+               if (! parse_audio_endpoints(chip, j)) {
                        usb_set_interface(dev, j, 0); /* reset the current interface */
                        usb_driver_claim_interface(&usb_audio_driver, iface, (void 
*)-1L);
                }
@@ -2213,6 +2205,40 @@
        return 0;
 }

+/*
+ * create a stream for an interface with proper descriptors
+ */
+static int create_standard_interface_quirk(snd_usb_audio_t *chip,
+                                          struct usb_interface *iface)
+{
+       struct usb_host_interface *alts;
+       struct usb_interface_descriptor *altsd;
+       int err;
+
+       alts = &iface->altsetting[0];
+       altsd = get_iface_desc(alts);
+       switch (altsd->bInterfaceSubClass) {
+       case USB_SUBCLASS_AUDIO_STREAMING:
+               err = parse_audio_endpoints(chip, altsd->bInterfaceNumber);
+               if (!err)
+                       usb_set_interface(chip->dev, altsd->bInterfaceNumber, 0); /* 
reset the current interface */
+               break;
+       case USB_SUBCLASS_MIDI_STREAMING:
+               err = snd_usb_create_midi_interface(chip, iface, NULL);
+               break;
+       default:
+               snd_printk(KERN_ERR "if %d: non-supported subclass %d\n",
+                          altsd->bInterfaceNumber, altsd->bInterfaceSubClass);
+               return -ENODEV;
+       }
+       if (err < 0) {
+               snd_printk(KERN_ERR "cannot setup if %d: error %d\n",
+                          altsd->bInterfaceNumber, err);
+               return err;
+       }
+       return 0;
+}
+
 static int snd_usb_create_quirk(snd_usb_audio_t *chip,
                                struct usb_interface *iface,
                                const snd_usb_audio_quirk_t *quirk);
@@ -2296,6 +2322,8 @@
                return create_composite_quirk(chip, iface, quirk);
        case QUIRK_AUDIO_FIXED_ENDPOINT:
                return create_fixed_stream_quirk(chip, iface, quirk);
+       case QUIRK_STANDARD_INTERFACE:
+               return create_standard_interface_quirk(chip, iface);
        default:
                snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
                return -ENXIO;
@@ -2413,42 +2441,6 @@


 /*
- * allocate and get description buffer
- * must be freed later.
- */
-static int alloc_desc_buffer(struct usb_device *dev, int index, unsigned char 
**bufptr)
-{
-       int err, buflen;
-       unsigned char buf[8];
-       unsigned char *buffer;
-
-       *bufptr = 0;
-       err = usb_get_descriptor(dev, USB_DT_CONFIG, index, buf, 8);
-       if (err < 0) {
-               snd_printk(KERN_ERR "%d:%d: cannot get first 8 bytes\n", index, 
dev->devnum);
-               return err;
-       }
-       if (buf[1] != USB_DT_CONFIG || buf[0] < 9) {
-               snd_printk(KERN_ERR "%d:%d: invalid config desc\n", index, 
dev->devnum);
-               return -EINVAL;
-       }
-       buflen = combine_word(&buf[2]);
-       if (!(buffer = kmalloc(buflen, GFP_KERNEL))) {
-               snd_printk(KERN_ERR "cannot malloc descriptor (size = %d)\n", buflen);
-               return -ENOMEM;
-       }
-       err = usb_get_descriptor(dev, USB_DT_CONFIG, index, buffer, buflen);
-       if (err < 0) {
-               snd_printk(KERN_ERR "%d:%d: cannot get DT_CONFIG: error %d\n", index, 
dev->devnum, err);
-               kfree(buffer);
-               return err;
-       }
-       *bufptr = buffer;
-       return buflen;
-}
-
-
-/*
  * probe the active usb device
  *
  * note that this can be called multiple times per a device, when it
@@ -2540,20 +2532,10 @@

        if (err > 0) {
                /* create normal USB audio interfaces */
-               unsigned char *buffer;
-               unsigned int index;
-               int buflen;
-
-               index = dev->actconfig - config;
-               buflen = alloc_desc_buffer(dev, index, &buffer);
-               if (buflen <= 0)
-                       goto __error;
-               if (snd_usb_create_streams(chip, ifnum, buffer, buflen) < 0 ||
-                   snd_usb_create_mixer(chip, ifnum, buffer, buflen) < 0) {
-                       kfree(buffer);
+               if (snd_usb_create_streams(chip, ifnum) < 0 ||
+                   snd_usb_create_mixer(chip, ifnum) < 0) {
                        goto __error;
                }
-               kfree(buffer);
        }

        /* we are allowed to call snd_card_register() many times */
Index: alsa-kernel/usb/usbaudio.h
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbaudio.h,v
retrieving revision 1.15
diff -u -r1.15 usbaudio.h
--- alsa-kernel/usb/usbaudio.h  10 Feb 2003 17:59:50 -0000      1.15
+++ alsa-kernel/usb/usbaudio.h  28 Feb 2003 10:34:19 -0000
@@ -146,6 +146,7 @@
 /*
  * Information about devices with broken descriptors
  */
+
 #define QUIRK_ANY_INTERFACE -1

 #define QUIRK_MIDI_FIXED_ENDPOINT      0
@@ -153,6 +154,7 @@
 #define QUIRK_MIDI_MIDIMAN             2
 #define QUIRK_COMPOSITE                        3
 #define QUIRK_AUDIO_FIXED_ENDPOINT     4
+#define QUIRK_STANDARD_INTERFACE       5

 #define QUIRK_BOOT_MASK                        0x80
 #define QUIRK_BOOT_EXTIGY              (QUIRK_BOOT_MASK | 0)
@@ -185,6 +187,8 @@

 /* for QUIRK_AUDIO_FIXED_ENDPOINT, data points to an audioformat structure */

+/* for QUIRK_STANDARD_INTERFACE, data is NULL */
+
 /*
  */

@@ -194,10 +198,10 @@

 unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size);

-void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype, int 
iface, int altsetting);
-void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype, 
int iface, int altsetting);
+void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype);
+void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype);

-int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffer, 
int buflen);
+int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif);

 int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, 
const snd_usb_audio_quirk_t *quirk);
 void snd_usbmidi_disconnect(struct list_head *p);
Index: alsa-kernel/usb/usbquirks.h
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbquirks.h,v
retrieving revision 1.17
diff -u -r1.17 usbquirks.h
--- alsa-kernel/usb/usbquirks.h 25 Feb 2003 17:04:43 -0000      1.17
+++ alsa-kernel/usb/usbquirks.h 28 Feb 2003 10:34:19 -0000
@@ -26,6 +26,11 @@
  * In a perfect world, this file would be empty.
  */

+/*
+ * Use this for devices where other interfaces are standard compliant,
+ * to prevent the quirk being applied to those interfaces. (To work with
+ * hotplugging, bDeviceClass must be set to USB_CLASS_PER_INTERFACE.)
+ */
 #define USB_DEVICE_VENDOR_SPEC(vend, prod) \
        .match_flags = USB_DEVICE_ID_MATCH_VENDOR | \
                       USB_DEVICE_ID_MATCH_PRODUCT | \
@@ -226,16 +231,10 @@
 },

 /*
- * Once upon a time people thought, "Wouldn't it be nice if there was a
- * standard for USB MIDI devices, so that device drivers would not be forced
- * to know about the quirks of specific devices?"  So Roland went ahead and
- * wrote the USB Device Class Definition for MIDI Devices, and the USB-IF
- * endorsed it, and now everybody designing USB MIDI devices does so in
- * agreement with this standard (or at least tries to).
+ * Roland/RolandED/Edirol devices
  *
- * And if you prefer a happy end, you can imagine that Roland devices set a
- * good example. Instead of being completely fucked up due to the lack of
- * class-specific descriptors.
+ * The USB MIDI Specification has been written by Roland,
+ * but a 100% conforming Roland device has yet to be found.
  */
 {
        USB_DEVICE(0x0582, 0x0000),
@@ -507,15 +506,33 @@
        }
 },
 {
-       USB_DEVICE_VENDOR_SPEC(0x0582, 0x0025),
+       /*
+        * This quirk is for the "Advanced Driver" mode. If off, the UA-20
+        * has ID 0x0026 and is standard compliant, but has only 16-bit PCM
+        * and no MIDI.
+        */
+       USB_DEVICE(0x0582, 0x0025),
        .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
                .vendor_name = "EDIROL",
                .product_name = "UA-20",
-               .ifnum = 3,
-               .type = QUIRK_MIDI_FIXED_ENDPOINT,
-               .data = & (const snd_usb_midi_endpoint_info_t) {
-                       .out_cables = 0x0001,
-                       .in_cables  = 0x0001
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = & (const snd_usb_audio_quirk_t[]) {
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_STANDARD_INTERFACE
+                       },
+                       {
+                               .ifnum = -1
+                       }
                }
        }
 },
Index: alsa-kernel/usb/usbmixer.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/usb/usbmixer.c,v
retrieving revision 1.16
diff -u -r1.16 usbmixer.c
--- alsa-kernel/usb/usbmixer.c  31 Jan 2003 15:21:32 -0000      1.16
+++ alsa-kernel/usb/usbmixer.c  28 Feb 2003 11:28:08 -0000
@@ -182,7 +182,7 @@

        p = NULL;
        while ((p = snd_usb_find_desc(state->buffer, state->buflen, p,
-                                     USB_DT_CS_INTERFACE, state->ctrlif, -1)) != 
NULL) {
+                                     USB_DT_CS_INTERFACE)) != NULL) {
                if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && 
p[3] == unit)
                        return p;
        }
@@ -1462,20 +1462,21 @@
  *
  * walk through all OUTPUT_TERMINAL descriptors to search for mixers
  */
-int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif, unsigned char *buffer, 
int buflen)
+int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif)
 {
        unsigned char *desc;
        mixer_build_t state;
        int err;
        const struct usbmix_ctl_map *map;
        struct usb_device_descriptor *dev = &chip->dev->descriptor;
+       struct usb_host_interface *hostif = 
&chip->dev->actconfig->interface[ctrlif].altsetting[0];

        strcpy(chip->card->mixername, "USB Mixer");

        memset(&state, 0, sizeof(state));
        state.chip = chip;
-       state.buffer = buffer;
-       state.buflen = buflen;
+       state.buffer = hostif->extra;
+       state.buflen = hostif->extralen;
        state.ctrlif = ctrlif;
        state.vendor = dev->idVendor;
        state.product = dev->idProduct;
@@ -1489,7 +1490,7 @@
        }

        desc = NULL;
-       while ((desc = snd_usb_find_csint_desc(buffer, buflen, desc, OUTPUT_TERMINAL, 
ctrlif, -1)) != NULL) {
+       while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, 
OUTPUT_TERMINAL)) != NULL) {
                if (desc[0] < 9)
                        continue; /* invalid descriptor? */
                set_bit(desc[3], state.unitbitmap);  /* mark terminal ID as visited */




-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
Alsa-devel mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-devel

Reply via email to