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