patch-2.3.21 linux/drivers/usb/audio.c

Next file: linux/drivers/usb/mouse.c
Previous file: linux/drivers/sgi/char/shmiq.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.20/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
@@ -769,7 +769,7 @@
 
 static int usbin_completed(int status, void *__buffer, int rval, void *dev_id)
 {
-#if 0
+#if 1
         struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
         struct usb_audiodev *as = (struct usb_audiodev *)id->context;
 #else
@@ -777,10 +777,13 @@
         struct usb_isoc_desc *id;
 #endif
 	struct usbin *u = &as->usbin;
+	unsigned long flags;
 	unsigned int next, idmask;
 
+#if 0
 	printk(KERN_DEBUG "usbin_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
-	spin_lock(&as->lock);
+#endif
+	spin_lock_irqsave(&as->lock, flags);
 	next = !(u->flags & FLG_NEXTID);
 	idmask = FLG_ID1RUNNING >> next;
 	u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next;
@@ -794,7 +797,12 @@
 		u->flags &= ~FLG_RUNNING;
 		printk(KERN_DEBUG "usbin_completed: descriptor not restarted\n");
 	}
-	spin_unlock(&as->lock);
+	if (!(u->flags & idmask)) {
+		printk(KERN_DEBUG "usbin_completed: killing id\n");
+		usb_kill_isoc(id);
+		printk(KERN_DEBUG "usbin_completed: id killed\n");
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
@@ -833,7 +841,7 @@
 
 static int usbin_sync_completed(int status, void *__buffer, int rval, void *dev_id)
 {
-#if 0
+#if 1
         struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
         struct usb_audiodev *as = (struct usb_audiodev *)id->context;
 #else
@@ -841,13 +849,16 @@
         struct usb_isoc_desc *id;
 #endif
 	struct usbin *u = &as->usbin;
+	unsigned long flags;
 	unsigned int next, idmask;
 
+#if 0
 	printk(KERN_DEBUG "usbin_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
-	spin_lock(&as->lock);
+#endif
+	spin_lock_irqsave(&as->lock, flags);
 	next = !(u->flags & FLG_SYNCNEXTID);
 	idmask = FLG_SYNC1RUNNING >> next;
-	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | (-next & FLG_SYNCNEXTID);
+	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | ((-next) & FLG_SYNCNEXTID);
 	id = u->synciso[!next];
 	if (!usbin_sync_retire_desc(u, id) &&
 	    u->flags & FLG_RUNNING &&
@@ -858,7 +869,12 @@
 		u->flags &= ~FLG_RUNNING;
 		printk(KERN_DEBUG "usbin_sync_completed: descriptor not restarted\n");
 	}
-	spin_unlock(&as->lock);
+	if (!(u->flags & idmask)) {
+		printk(KERN_DEBUG "usbin_sync_completed: killing id\n");
+		usb_kill_isoc(id);
+		printk(KERN_DEBUG "usbin_sync_completed: id killed\n");
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
@@ -870,8 +886,10 @@
 	unsigned long flags;
 	unsigned int which, i;
 
-	printk(KERN_DEBUG "usbin_start: device %d ufmt %d dfmt %d srate %d\n",
+#if 0
+	printk(KERN_DEBUG "usbin_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
 	       dev->devnum, u->format, u->dma.format, u->dma.srate);
+#endif
 	/* allocate USB storage if not already done */
 	/* UHCI wants the data to be page aligned - this is silly */
 	if (!u->data[0])
@@ -980,15 +998,18 @@
         unsigned long flags;
 	unsigned int i;
 
+printk(KERN_DEBUG "usb_audio: usbout_stop (1) flags 0x%04x\n", u->flags);
         spin_lock_irqsave(&as->lock, flags);
 	u->flags &= ~FLG_RUNNING;
 	i = u->flags;
         spin_unlock_irqrestore(&as->lock, flags);
+printk(KERN_DEBUG "usb_audio: usbout_stop (2) flags 0x%04x\n", i);
 	while (i & (FLG_ID0RUNNING|FLG_ID1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) {
 		schedule_timeout(1);
 		spin_lock_irqsave(&as->lock, flags);
 		i = u->flags;
 		spin_unlock_irqrestore(&as->lock, flags);
+printk(KERN_DEBUG "usb_audio: usbout_stop (3) flags 0x%04x\n", i);
 	}
 	if (u->dataiso[0])
 		usb_free_isoc(u->dataiso[0]);
@@ -1219,7 +1240,7 @@
 
 static int usbout_completed(int status, void *__buffer, int rval, void *dev_id)
 {
-#if 0
+#if 1
         struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
         struct usb_audiodev *as = (struct usb_audiodev *)id->context;
 #else
@@ -1227,10 +1248,13 @@
 	struct usb_isoc_desc *id;
 #endif
 	struct usbout *u = &as->usbout;
+	unsigned long flags;
 	unsigned int next, idmask;
 
+#if 0
 	printk(KERN_DEBUG "usbout_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
-	spin_lock(&as->lock);
+#endif
+	spin_lock_irqsave(&as->lock, flags);
 	next = !(u->flags & FLG_NEXTID);
 	idmask = FLG_ID1RUNNING >> next;
 	u->flags = (u->flags & ~(FLG_NEXTID | idmask)) | next;
@@ -1244,7 +1268,12 @@
 		u->flags &= ~FLG_RUNNING;
 		printk(KERN_DEBUG "usbout_completed: descriptor not restarted\n");
 	}
-	spin_unlock(&as->lock);
+	if (!(u->flags & idmask)) {
+		printk(KERN_DEBUG "usbout_completed: killing id\n");
+		usb_kill_isoc(id);
+		printk(KERN_DEBUG "usbout_completed: id killed\n");
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
@@ -1286,7 +1315,7 @@
 
 static int usbout_sync_completed(int status, void *__buffer, int rval, void *dev_id)
 {
-#if 0
+#if 1
         struct usb_isoc_desc *id = (struct usb_isoc_desc *)dev_id;
         struct usb_audiodev *as = (struct usb_audiodev *)id->context;
 #else
@@ -1294,13 +1323,16 @@
 	struct usb_isoc_desc *id;
 #endif
 	struct usbout *u = &as->usbout;
+	unsigned long flags;
 	unsigned int next, idmask;
 
+#if 0
 	printk(KERN_DEBUG "usbout_sync_completed: status %d rval %d flags 0x%x\n", status, rval, u->flags);
-	spin_lock(&as->lock);
+#endif
+	spin_lock_irqsave(&as->lock, flags);
 	next = !(u->flags & FLG_SYNCNEXTID);
 	idmask = FLG_SYNC1RUNNING >> next;
-	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | (-next & FLG_SYNCNEXTID);
+	u->flags = (u->flags & ~(FLG_SYNCNEXTID | idmask)) | ((-next) & FLG_SYNCNEXTID);
 	id = u->synciso[!next];
 	if (!usbout_sync_retire_desc(u, id) &&
 	    u->flags & FLG_RUNNING &&
@@ -1311,7 +1343,12 @@
 		u->flags &= ~FLG_RUNNING;
 		printk(KERN_DEBUG "usbout_sync_completed: descriptor not restarted\n");
 	}
-	spin_unlock(&as->lock);
+	if (!(u->flags & idmask)) {
+		printk(KERN_DEBUG "usbout_sync_completed: killing id\n");
+		usb_kill_isoc(id);
+		printk(KERN_DEBUG "usbout_sync_completed: id killed\n");
+	}
+	spin_unlock_irqrestore(&as->lock, flags);
 	return 0;
 }
 
@@ -1323,8 +1360,10 @@
 	unsigned long flags;
 	unsigned int which, i;
 
-	printk(KERN_DEBUG "usbout_start: device %d ufmt %d dfmt %d srate %d\n",
+#if 0
+	printk(KERN_DEBUG "usbout_start: device %d ufmt 0x%08x dfmt 0x%08x srate %d\n",
 	       dev->devnum, u->format, u->dma.format, u->dma.srate);
+#endif
 	/* allocate USB storage if not already done */
 	/* UHCI wants the data to be page aligned - this is silly */
 	if (!u->data[0])
@@ -1459,7 +1498,7 @@
 	struct usbin *u = &as->usbin;
 	struct dmabuf *d = &u->dma;
 	struct audioformat *fmt;
-	unsigned int fmtnr;
+	unsigned int fmtnr, ep;
 	unsigned char data[3];
 
 	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
@@ -1474,7 +1513,7 @@
 	if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x08) {
 		if (alts->bNumEndpoints < 2 ||
 		    alts->endpoint[1].bmAttributes != 0x01 ||
-		    alts->endpoint[1].bSynchAddress == 0 ||
+		    alts->endpoint[1].bSynchAddress != 0 ||
 		    alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress & 0x7f)) {
 			printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n",
 			       dev->devnum, u->interface, fmt->altsetting);
@@ -1497,18 +1536,21 @@
 	data[0] = d->srate;
 	data[1] = d->srate >> 8;
 	data[2] = d->srate >> 16;
+	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
 	if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
-		printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n",
-		       dev->devnum, usb_pipeendpoint(u->datapipe));
+			    SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+		printk(KERN_ERR "usbaudio: failure to set input sampling frequency device %d endpoint 0x%x to %u\n",
+		       dev->devnum, ep, d->srate);
 		return -1;
 	}
 	if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
-		printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n",
-		       dev->devnum, usb_pipeendpoint(u->datapipe));
+			    SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+		printk(KERN_ERR "usbaudio: failure to get input sampling frequency device %d endpoint 0x%x\n",
+		       dev->devnum, ep);
 		return -1;
 	}
+	printk(KERN_DEBUG "usb_audio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n",
+	       dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16));
 	d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
 	return 0;
 }
@@ -1522,7 +1564,7 @@
 	struct usbout *u = &as->usbout;
 	struct dmabuf *d = &u->dma;
 	struct audioformat *fmt;
-	unsigned int fmtnr;
+	unsigned int fmtnr, ep;
 	unsigned char data[3];
 
 	if (u->interface < 0 || u->interface >= config->bNumInterfaces)
@@ -1537,7 +1579,7 @@
 	if ((alts->endpoint[0].bmAttributes & 0x0c) == 0x04) {
 		if (alts->bNumEndpoints < 2 ||
 		    alts->endpoint[1].bmAttributes != 0x01 ||
-		    alts->endpoint[1].bSynchAddress == 0 ||
+		    alts->endpoint[1].bSynchAddress != 0 ||
 		    alts->endpoint[1].bEndpointAddress != (alts->endpoint[0].bSynchAddress | 0x80)) {
 			printk(KERN_ERR "usb_audio: device %d interface %d altsetting %d invalid synch pipe\n",
 			       dev->devnum, u->interface, fmt->altsetting);
@@ -1560,18 +1602,21 @@
 	data[0] = d->srate;
 	data[1] = d->srate >> 8;
 	data[2] = d->srate >> 16;
+	ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
 	if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 
-			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
-		printk(KERN_ERR "usbaudio: failure to set sampling frequency device %d endpoint %d\n",
-		       dev->devnum, usb_pipeendpoint(u->datapipe));
+			    SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+		printk(KERN_ERR "usbaudio: failure to set output sampling frequency device %d endpoint 0x%x to %u\n",
+		       dev->devnum, ep, d->srate);
 		return -1;
 	}
 	if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
-			    SAMPLING_FREQ_CONTROL << 8, usb_pipeendpoint(u->datapipe), data, 3, HZ) != 3) {
-		printk(KERN_ERR "usbaudio: failure to get sampling frequency device %d endpoint %d\n",
-		       dev->devnum, usb_pipeendpoint(u->datapipe));
+			    SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ) < 0) {
+		printk(KERN_ERR "usbaudio: failure to get output sampling frequency device %d endpoint 0x%x\n",
+		       dev->devnum, ep);
 		return -1;
 	}
+	printk(KERN_DEBUG "usb_audio: set_format_out: device %d interface %d altsetting %d srate req: %u real %u\n",
+	       dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16));
 	d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
 	return 0;
 }
@@ -1642,7 +1687,7 @@
 		data[0] = v1;
 		data[1] = v1 >> 8;
                 if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+                                    (ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
                         goto err;
 		if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
 			return 0;
@@ -1650,7 +1695,7 @@
 		data[1] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
 				    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-				    ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+				    ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
                         goto err;
 		return 0;
 
@@ -1659,14 +1704,14 @@
 		data[0] = v1;
 		data[1] = v1 >> 8;
                 if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
                         goto err;
 		if (ch->chnum == 0)
 			return 0;
 		data[0] = v2;
 		data[1] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 2)
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
 			goto err;
 		return 0;
                 
@@ -1675,13 +1720,13 @@
         case TREBLE_CONTROL:
 		data[0] = v1 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 1)
+                                    (ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
                         goto err;
 		if (ch->chnum == 0)
 			return 0;
 		data[0] = v2 >> 8;
 		if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
-				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 1)
+				    (ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
 			goto err;
 		return 0;
                
@@ -1839,7 +1884,7 @@
                         for (val = i = 0; i < ms->numch; i++)
 				if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
 					val |= 1 << ms->ch[i].osschannel;
-                        return put_user(0, (int *)arg);
+                        return put_user(val, (int *)arg);
                         
                 case SOUND_MIXER_CAPS:
                         return put_user(0, (int *)arg);
@@ -2778,26 +2823,26 @@
 	if ((state->termtype & 0xff00) == 0x0000 && !(state->mixchmask & SOUND_MASK_VOLUME))
 		return SOUND_MIXER_VOLUME;
 	if ((state->termtype & 0xff00) == 0x0100) {
-		if (!(state->mixchmask & SOUND_MASK_PCM))
+		if (state->mixchmask & SOUND_MASK_PCM)
 			return SOUND_MIXER_PCM;
-		if (!(state->mixchmask & SOUND_MASK_ALTPCM))
+		if (state->mixchmask & SOUND_MASK_ALTPCM)
 			return SOUND_MIXER_ALTPCM;
 	}
-	if ((state->termtype & 0xff00) == 0x0200 && !(state->mixchmask & SOUND_MASK_MIC))
+	if ((state->termtype & 0xff00) == 0x0200 && (state->mixchmask & SOUND_MASK_MIC))
 		return SOUND_MIXER_MIC;
-	if ((state->termtype & 0xff00) == 0x0300 && !(state->mixchmask & SOUND_MASK_SPEAKER))
+	if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
 		return SOUND_MIXER_SPEAKER;
-	if ((state->termtype & 0xff00) == 0x0300 && !(state->mixchmask & SOUND_MASK_SPEAKER))
+	if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
 		return SOUND_MIXER_SPEAKER;
 	if ((state->termtype & 0xff00) == 0x0500) {
-		if (!(state->mixchmask & SOUND_MASK_PHONEIN))
+		if (state->mixchmask & SOUND_MASK_PHONEIN)
 			return SOUND_MIXER_PHONEIN;
-		if (!(state->mixchmask & SOUND_MASK_PHONEOUT))
+		if (state->mixchmask & SOUND_MASK_PHONEOUT)
 			return SOUND_MIXER_PHONEOUT;
 	}
-	if (state->termtype >= 0x710 && state->termtype <= 0x711 && !(state->mixchmask & SOUND_MASK_RADIO))
+	if (state->termtype >= 0x710 && state->termtype <= 0x711 && (state->mixchmask & SOUND_MASK_RADIO))
 		return SOUND_MIXER_RADIO;
-	if (state->termtype >= 0x709 && state->termtype <= 0x70f && !(state->mixchmask & SOUND_MASK_VIDEO))
+	if (state->termtype >= 0x709 && state->termtype <= 0x70f && (state->mixchmask & SOUND_MASK_VIDEO))
 		return SOUND_MIXER_VIDEO;
 	u = ffs(state->mixchmask & (SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_LINE3 |
 				    SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | SOUND_MASK_DIGITAL3));
@@ -2818,18 +2863,18 @@
 	switch (ch->selector) {
 	case 0:  /* mixer unit request */
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		ch->minval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		ch->maxval = buf[0] | (buf[1] << 8);
 		v2 = ch->maxval - ch->minval;
 		if (!v2)
 			v2 = 1;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->chnum << 8) | 1, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		v1 = buf[0] | (buf[1] << 8);
 		v3 = v1 - ch->minval;
@@ -2840,7 +2885,7 @@
 		if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
 					    ((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
-					    state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+					    state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 			v1 = buf[0] | (buf[1] << 8);
 			v3 = v1 - ch->minval;
@@ -2854,15 +2899,15 @@
 		/* various feature unit controls */
 	case VOLUME_CONTROL:
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		ch->minval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		ch->maxval = buf[0] | (buf[1] << 8);
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 			goto err;
 		v1 = buf[0] | (buf[1] << 8);
 		v2 = ch->maxval - ch->minval;
@@ -2875,7 +2920,7 @@
 		ch->value = v3;
 		if (ch->chnum != 0) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 2)
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
 				goto err;
 			v1 = buf[0] | (buf[1] << 8);
 			v3 = v1 - ch->minval;
@@ -2890,15 +2935,15 @@
 	case MID_CONTROL:
 	case TREBLE_CONTROL:
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MIN, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
 			goto err;
 		ch->minval = buf[0] << 8;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_MAX, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
 			goto err;
 		ch->maxval = buf[0] << 8;
 		if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+				    (ch->selector << 8) | ch->chnum, state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
 			goto err;
 		v1 = buf[0] << 8;
 		v2 = ch->maxval - ch->minval;
@@ -2911,7 +2956,7 @@
 		ch->value = v3;
 		if (ch->chnum != 0) {
 			if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
-					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 1)
+					    (ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
 				goto err;
 			v1 = buf[0] << 8;
 			v3 = v1 - ch->minval;
@@ -2942,12 +2987,12 @@
 	unsigned int idx;
 
 	idx = inidx*numoch;
-	if (!(bmap[idx >> 3] & (1 << (idx & 7))))
+	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
 		return 0;
 	if (!(flg & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
 		return 1;
 	idx = (inidx+!!(flg & MIXFLG_STEREOIN))*numoch+!!(flg & MIXFLG_STEREOOUT);
-	if (!(bmap[idx >> 3] & (1 << (idx & 7))))
+	if (!(bmap[-(idx >> 3)] & (0x80 >> (idx & 7))))
 		return 0;
 	return 1;
 }
@@ -2958,6 +3003,8 @@
 	unsigned int chidx[SOUND_MIXER_NRDEVICES+1];
 	unsigned int termt[SOUND_MIXER_NRDEVICES];
 	unsigned char flg = (nroutch >= 2) ? MIXFLG_STEREOOUT : 0;
+	unsigned char *bmap = &mixer[9+mixer[4]];
+	unsigned int bmapsize;
 	struct mixerchannel *ch;
 	unsigned int i;
 
@@ -2977,7 +3024,9 @@
 	}
 	state->termtype = 0;
 	state->chconfig = mixer[6+mixer[4]] | (mixer[7+mixer[4]] << 8);
-	if (mixer[0] < 10+mixer[4]+((nroutch * chidx[mixer[4]] + 7) >> 3)) {
+	bmapsize = (nroutch * chidx[mixer[4]] + 7) >> 3;
+	bmap += bmapsize - 1;
+	if (mixer[0] < 10+mixer[4]+bmapsize) {
 		printk(KERN_ERR "usb_audio: unit %u invalid MIXER_UNIT descriptor (bitmap too small)\n", mixer[3]);
 		return;
 	}
@@ -2985,7 +3034,7 @@
 		state->termtype = termt[i];
 		if (chidx[i+1]-chidx[i] >= 2) {
 			flg |= MIXFLG_STEREOIN;
-			if (checkmixbmap(&mixer[9+mixer[4]], flg, chidx[i], nroutch)) {
+			if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
 				ch = getmixchannel(state, getvolchannel(state));
 				if (ch) {
 					ch->unitid = mixer[3];
@@ -2998,7 +3047,7 @@
 			}
 		}
 		flg &= ~MIXFLG_STEREOIN;
-		if (checkmixbmap(&mixer[9+mixer[4]], flg, chidx[i], nroutch)) {
+		if (checkmixbmap(bmap, flg, chidx[i], nroutch)) {
 			ch = getmixchannel(state, getvolchannel(state));
 			if (ch) {
 				ch->unitid = mixer[3];
@@ -3134,6 +3183,7 @@
 static void usb_audio_recurseunit(struct consmixstate *state, unsigned char unitid)
 {
 	unsigned char *p1;
+	unsigned int i, j;
 
 	if (test_and_set_bit(unitid, &state->unitbitmap)) {
 		printk(KERN_ERR "usb_audio: mixer path recursion detected, unit %d!\n", unitid);
@@ -3195,15 +3245,16 @@
 			printk(KERN_ERR "usb_audio: unit %u: invalid EXTENSION_UNIT descriptor\n", unitid);
 			return;
 		}
-		{
-			unsigned int i;
-			
-			for (i = 0; i < p1[6]; i++)
-				usb_audio_recurseunit(state, p1[7+i]);
+		for (j = i = 0; i < p1[6]; i++) {
+			usb_audio_recurseunit(state, p1[7+i]);
+			if (!i)
+				j = state->termtype;
+			else if (j != state->termtype)
+				j = 0;
 		}
 		state->nrchannels = p1[7+p1[6]];
 		state->chconfig = p1[8+p1[6]] | (p1[9+p1[6]] << 8);
-		state->termtype = 0;
+		state->termtype = j;
 		return;
 
 	default:
@@ -3378,6 +3429,10 @@
 	return -1;
 
  configfound:
+        if (usb_set_configuration(dev, config->bConfigurationValue) < 0) {
+		printk(KERN_ERR "usb_audio: set_configuration failed (ConfigValue 0x%x)\n", config->bConfigurationValue);
+		return -1;
+	}
 	ret = usb_get_descriptor(dev, USB_DT_CONFIG, i, buf, 8);
 	if (ret) {
 		printk(KERN_ERR "usb_audio: cannot get first 8 bytes of config descriptor %d of device %d\n", i, dev->devnum);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)