[linux-audio-dev] USB audio.c driver patch; complete n-channel/24 bit patch

Monty xiphmont at xiph.org
Fri Oct 25 07:18:01 UTC 2002


Apologies taking time to package this up.  The patches included are
tested against 2.4.19 or later. 

This patch fixes a few bugs and implements full n-channel support of
greater-than-stereo USB audio devices, such as the emagic emi 2|6.  I
also opted to make the minor extention to OSS to define 24 and 32 bit
AFMT modes, and the patch includes this.  It does not break any
existing OSS compatability, and unaware apps can continue to be
unaware.  The modified audio.c will build without the OSS extentions
to soundcard.h.

As suggested, I didn't bother with OSS mixer extentions.  The device I
care about most doesn't expose a per-channel mixer feature regardless.

Also, I was wrong: 2.5's audio.c is different, but the differences
appear to be for the sake of keeping up with other changes to USB
support.  I did not attempt to apply the included patch to 2.5's
audio.c, but I'd give it even odds with sufficient fuzz.

Monty
-------------- next part --------------
*** /home/xiphmont/src-linux-2.4-benh/include/linux/soundcard.h	Fri Oct  4 09:20:37 2002
--- /home/xiphmont/src-linux-2.4-monty/include/linux/soundcard.h	Fri Oct 25 06:39:14 2002
***************
*** 554,559 ****
--- 554,569 ----
  #	define AFMT_MPEG		0x00000200	/* MPEG (2) audio */
  #	define AFMT_AC3		0x00000400	/* Dolby Digital AC3 */
  
+ /* because they *do* exist and we want to use them --Monty */
+ #	define AFMT_S24_LE	        0x00000800	
+ #	define AFMT_S24_BE	        0x00001000	
+ #	define AFMT_U24_LE	        0x00002000	
+ #	define AFMT_U24_BE	        0x00004000	
+ #	define AFMT_S32_LE	        0x00008000	
+ #	define AFMT_S32_BE	        0x00010000	
+ #	define AFMT_U32_LE	        0x00020000	
+ #	define AFMT_U32_BE	        0x00040000	
+ 
  /*
   * Buffer status queries.
   */
-------------- next part --------------
*** /home/xiphmont/src-linux-2.4-benh/drivers/usb/audio.c	Fri Oct  4 09:20:13 2002
--- /home/xiphmont/src-linux-2.4-monty/drivers/usb/audio.c	Fri Oct 25 02:46:50 2002
***************
*** 99,104 ****
--- 99,110 ----
   *              for abs. Bug report by Andrew Morton <andrewm at uow.edu.au>
   * 2001-06-16:  Bryce Nesbitt <bryce at obviously.com>
   *              Fix SNDCTL_DSP_STEREO API violation
+  * 2002-10-16:  Monty <monty at xiph.org>
+  *              Expand device support from a maximum of 8/16bit,mono/stereo to 
+  *              8/16/24/32bit,N channels.  Add AFMT_?24_?? and AFMT_?32_?? to OSS
+  *              functionality. Tested and used in production with the emagic emi 2|6 
+  *              on PPC and Intel. Also fixed a few logic 'crash and burn' corner 
+  *              cases.
   */
  
  /*
***************
*** 230,235 ****
--- 236,246 ----
  #define DMABUFSHIFT       17  /* 128k worth of DMA buffer */
  #define NRSGBUF           (1U<<(DMABUFSHIFT-PAGE_SHIFT))
  
+ #define MAXCHANNELS       32
+ #define MAXWIDTH          4
+ #define MAXSAMPLEWIDTH    (MAXCHANNELS*MAXWIDTH)
+ #define TMPCOPYWIDTH      MAXSAMPLEWIDTH /* max (128,MAXSAMPLEWIDTH) */
+ 
  /*
   * This influences:
   * - Latency
***************
*** 387,399 ****
  	unsigned count;  /* usage counter; NOTE: the usb stack is also considered a user */
  };
  
  /* private audio format extensions */
! #define AFMT_STEREO        0x80000000
! #define AFMT_ISSTEREO(x)   ((x) & AFMT_STEREO)
! #define AFMT_IS16BIT(x)    ((x) & (AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE))
! #define AFMT_ISUNSIGNED(x) ((x) & (AFMT_U8|AFMT_U16_LE|AFMT_U16_BE))
! #define AFMT_BYTESSHIFT(x) ((AFMT_ISSTEREO(x) ? 1 : 0) + (AFMT_IS16BIT(x) ? 1 : 0))
! #define AFMT_BYTES(x)      (1<<AFMT_BYTESSHFIT(x))
  
  /* --------------------------------------------------------------------- */
  
--- 398,459 ----
  	unsigned count;  /* usage counter; NOTE: the usb stack is also considered a user */
  };
  
+ /* in the event we don't have the extended soundcard.h, we still need
+    to compile successfully.  Supply definitions */
+ 
+ #ifndef AFMT_S24_LE
+ #	define AFMT_S24_LE	        0x00000800	
+ #endif
+ #ifndef AFMT_S24_BE
+ #	define AFMT_S24_BE	        0x00001000	
+ #endif
+ #ifndef AFMT_U24_LE
+ #	define AFMT_U24_LE	        0x00002000	
+ #endif
+ #ifndef AFMT_U24_BE
+ #	define AFMT_U24_BE	        0x00004000	
+ #endif
+ #ifndef AFMT_S32_LE
+ #	define AFMT_S32_LE	        0x00008000	
+ #endif
+ #ifndef AFMT_S32_BE
+ #	define AFMT_S32_BE	        0x00010000	
+ #endif
+ #ifndef AFMT_U32_LE
+ #	define AFMT_U32_LE	        0x00020000	
+ #endif
+ #ifndef AFMT_U32_BE
+ #	define AFMT_U32_BE	        0x00040000	
+ #endif
+ 
  /* private audio format extensions */
! #define AFMT_STEREO         0x01000000
! #define AFMT_CHMASK         0xff000000
! #define AFMT_8MASK          (AFMT_U8 | AFMT_S8)
! #define AFMT_16MASK         (AFMT_U16_LE | AFMT_S16_LE | AFMT_U16_BE | AFMT_S16_BE)
! #define AFMT_24MASK         (AFMT_U24_LE | AFMT_S24_LE | AFMT_U24_BE | AFMT_S24_BE)
! #define AFMT_32MASK         (AFMT_U32_LE | AFMT_S32_LE | AFMT_U32_BE | AFMT_S32_BE)
! 
! #define AFMT_SIGNMASK       (AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE |\
!                                        AFMT_S24_LE | AFMT_S24_BE |\
!                                        AFMT_S32_LE | AFMT_S32_BE)
! 
! /* a little odd, but the code counts on byte formats being identified as 'big endian' */
! #define AFMT_ENDIANMASK     (AFMT_S8 | AFMT_U8 |\
! 			               AFMT_S16_BE | AFMT_U16_BE |\
!                                        AFMT_S24_BE | AFMT_U24_BE |\
!                                        AFMT_S32_BE | AFMT_U32_BE)
! 
! #define AFMT_ISSTEREO(x)    (((x) & 0xff000000) == AFMT_STEREO)
! #define AFMT_CHANNELS(x)    (((unsigned)(x) >> 24) + 1)
! #define AFMT_BYTES(x)       ( (((x)&AFMT_8MASK)!=0)+\
!                               (((x)&AFMT_16MASK)!=0)*2+\
!                               (((x)&AFMT_24MASK)!=0)*3+\
!                               (((x)&AFMT_32MASK)!=0)*4 )
! #define AFMT_SAMPLEBYTES(x) (AFMT_BYTES(x)*AFMT_CHANNELS(x))
! #define AFMT_SIGN(x)        ((x)&AFMT_SIGNMASK)
! #define AFMT_ENDIAN(x)      ((x)&AFMT_ENDIANMASK)
! 
  
  /* --------------------------------------------------------------------- */
  
***************
*** 468,474 ****
  	/* initialize some fields */
  	db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
  	/* calculate required buffer size */
! 	bytepersec = db->srate << AFMT_BYTESSHIFT(db->format);
  	bufs = 1U << DMABUFSHIFT;
  	if (db->ossfragshift) {
  		if ((1000 << db->ossfragshift) < bytepersec)
--- 528,534 ----
  	/* initialize some fields */
  	db->rdptr = db->wrptr = db->total_bytes = db->count = db->error = 0;
  	/* calculate required buffer size */
! 	bytepersec = db->srate * AFMT_SAMPLEBYTES(db->format);
  	bufs = 1U << DMABUFSHIFT;
  	if (db->ossfragshift) {
  		if ((1000 << db->ossfragshift) < bytepersec)
***************
*** 497,503 ****
  			db->sgbuf[nr] = p;
  			mem_map_reserve(virt_to_page(p));
  		}
! 		memset(db->sgbuf[nr], AFMT_ISUNSIGNED(db->format) ? 0x80 : 0, PAGE_SIZE);
  		if ((nr << PAGE_SHIFT) >= db->dmasize)
  			break;
  	}
--- 557,563 ----
  			db->sgbuf[nr] = p;
  			mem_map_reserve(virt_to_page(p));
  		}
! 		memset(db->sgbuf[nr], AFMT_SIGN(db->format) ? 0 : 0x80, PAGE_SIZE);
  		if ((nr << PAGE_SHIFT) >= db->dmasize)
  			break;
  	}
***************
*** 688,834 ****
  	usbin_stop(as);
  }
  
! static void conversion(const void *ibuf, unsigned int ifmt, void *obuf, unsigned int ofmt, void *tmp, unsigned int scnt)
  {
! 	unsigned int cnt, i;
! 	__s16 *sp, *sp2, s;
! 	unsigned char *bp;
! 
! 	cnt = scnt;
! 	if (AFMT_ISSTEREO(ifmt))
! 		cnt <<= 1;
! 	sp = ((__s16 *)tmp) + cnt;
! 	switch (ifmt & ~AFMT_STEREO) {
! 	case AFMT_U8:
! 		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
! 			bp--;
! 			sp--;
! 			*sp = (*bp ^ 0x80) << 8;
! 		}
! 		break;
  			
! 	case AFMT_S8:
! 		for (bp = ((unsigned char *)ibuf)+cnt, i = 0; i < cnt; i++) {
! 			bp--;
! 			sp--;
! 			*sp = *bp << 8;
! 		}
! 		break;
! 		
! 	case AFMT_U16_LE:
! 		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
! 			bp -= 2;
! 			sp--;
! 			*sp = (bp[0] | (bp[1] << 8)) ^ 0x8000;
! 		}
! 		break;
  
! 	case AFMT_U16_BE:
! 		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
! 			bp -= 2;
! 			sp--;
! 			*sp = (bp[1] | (bp[0] << 8)) ^ 0x8000;
! 		}
! 		break;
  
! 	case AFMT_S16_LE:
! 		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
! 			bp -= 2;
! 			sp--;
! 			*sp = bp[0] | (bp[1] << 8);
  		}
! 		break;
! 
! 	case AFMT_S16_BE:
! 		for (bp = ((unsigned char *)ibuf)+2*cnt, i = 0; i < cnt; i++) {
! 			bp -= 2;
! 			sp--;
! 			*sp = bp[1] | (bp[0] << 8);
  		}
! 		break;
  	}
! 	if (!AFMT_ISSTEREO(ifmt) && AFMT_ISSTEREO(ofmt)) {
! 		/* expand from mono to stereo */
! 		for (sp = ((__s16 *)tmp)+scnt, sp2 = ((__s16 *)tmp)+2*scnt, i = 0; i < scnt; i++) {
! 			sp--;
! 			sp2 -= 2;
! 			sp2[0] = sp2[1] = sp[0];
  		}
  	}
! 	if (AFMT_ISSTEREO(ifmt) && !AFMT_ISSTEREO(ofmt)) {
! 		/* contract from stereo to mono */
! 		for (sp = sp2 = ((__s16 *)tmp), i = 0; i < scnt; i++, sp++, sp2 += 2)
! 			sp[0] = (sp2[0] + sp2[1]) >> 1;
  	}
- 	cnt = scnt;
- 	if (AFMT_ISSTEREO(ofmt))
- 		cnt <<= 1;
- 	sp = ((__s16 *)tmp);
- 	bp = ((unsigned char *)obuf);
- 	switch (ofmt & ~AFMT_STEREO) {
- 	case AFMT_U8:
- 		for (i = 0; i < cnt; i++, sp++, bp++)
- 			*bp = (*sp >> 8) ^ 0x80;
- 		break;
- 
- 	case AFMT_S8:
- 		for (i = 0; i < cnt; i++, sp++, bp++)
- 			*bp = *sp >> 8;
- 		break;
- 
- 	case AFMT_U16_LE:
- 		for (i = 0; i < cnt; i++, sp++, bp += 2) {
- 			s = *sp;
- 			bp[0] = s;
- 			bp[1] = (s >> 8) ^ 0x80;
  		}
! 		break;
! 
! 	case AFMT_U16_BE:
! 		for (i = 0; i < cnt; i++, sp++, bp += 2) {
! 			s = *sp;
! 			bp[1] = s;
! 			bp[0] = (s >> 8) ^ 0x80;
  		}
! 		break;
  
- 	case AFMT_S16_LE:
- 		for (i = 0; i < cnt; i++, sp++, bp += 2) {
- 			s = *sp;
- 			bp[0] = s;
- 			bp[1] = s >> 8;
  		}
! 		break;
! 
! 	case AFMT_S16_BE:
! 		for (i = 0; i < cnt; i++, sp++, bp += 2) {
! 			s = *sp;
! 			bp[1] = s;
! 			bp[0] = s >> 8;
  		}
! 		break;
  	}
- 	
  }
  
  static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
  {
! 	union {
! 		__s16 s[64];
! 		unsigned char b[0];
! 	} tmp;
! 	unsigned int scnt, maxs, ufmtsh, dfmtsh;
! 
! 	ufmtsh = AFMT_BYTESSHIFT(u->format);
! 	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
! 	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
  	while (samples > 0) {
  		scnt = samples;
  		if (scnt > maxs)
  			scnt = maxs;
! 		conversion(buffer, u->format, tmp.b, u->dma.format, tmp.b, scnt);
! 		dmabuf_copyin(&u->dma, tmp.b, scnt << dfmtsh);
! 		buffer += scnt << ufmtsh;
  		samples -= scnt;
  	}
  }		
--- 748,915 ----
  	usbin_stop(as);
  }
  
! static inline int iconvert(unsigned char **xx,int jump)
  {
!   int value=0;
!   unsigned char *x=*xx;
    
!   /* conversion fall-through cascade compiles to a jump table */
!   switch(jump){
!   case 0:
!     /* 32 bit BE */
!     value  = x[3];
!   case 1:
!     /* 24 bit BE */
!     value |= x[2] << 8;
!   case 2:
!     /* 16 bit BE */
!     value |= x[1] << 16;
!   case 3:
!     /* 8 bit */
!     value |= x[0] << 24;
!     x+=(4-jump);
!     break;
! 
!   case 4:
!     /* 32 bit LE */
!     value  = *x++;
!   case 5:
!     /* 24 bit LE */
!     value |= *x++ << 8;
!   case 6:
!     /* 16 bit LE */
!     value |= *x++ << 16;
!     value |= *x++ << 24;
!     break;
!   }
!   *xx=x;
!   return(value);
! }
! 
! static inline void oconvert(unsigned char **yy,int jump,int value)
! {
!   unsigned char *y=*yy;
! 
!   /* conversion fall-through cascade compiles to a jump table */
!   switch(jump){
!   case 0:
!     /* 32 bit BE */
!     y[3] = value >> 24;
!   case 1:
!     /* 24 bit BE */
!     y[2] = value >> 16;
!   case 2:
!     /* 16 bit BE */
!     y[1] = value >> 8;
!   case 3:
!     /* 8 bit */
!     y[0] = value;
!     y+=(4-jump);
!     break;
! 
!   case 4:
!     /* 32 bit LE */
!     *y++ = value;
!   case 5:
!     /* 24 bit LE */
!     *y++ = value >> 8;
!   case 6:
!     /* 16 bit LE */
!     *y++ = value >> 16;
!     *y++ = value >> 24;
!     break;
!   }
!   *yy=y;
! }
! 
! /* capable of any-to-any conversion */
! static void conversion(const void *ibuf, unsigned int ifmt, 
! 		       void *obuf, unsigned int ofmt, unsigned int scnt)
! {
  
!   /* some conversion is indeed needed */
!   unsigned int i,j;
!   unsigned char *x=(unsigned char *)ibuf;
!   unsigned char *y=(unsigned char *)obuf;
    
!   int ichannels = AFMT_CHANNELS(ifmt);
!   int ochannels = AFMT_CHANNELS(ofmt);
!   int ibytes    = AFMT_BYTES(ifmt);
!   int obytes    = AFMT_BYTES(ofmt);
!   int iendian   = AFMT_ENDIAN(ifmt);
!   int oendian   = AFMT_ENDIAN(ofmt);
!   int isign     = AFMT_SIGN(ifmt)?0:0x80000000UL;
!   int osign     = AFMT_SIGN(ofmt)?0:0x80000000UL;
!   int sign      = (isign==osign?0:0x80000000UL);
!   
!   /* build the byte/endian jump table offsets */
!   int ijump = (iendian ? 4-ibytes : 8-ibytes);
!   int ojump = (oendian ? 4-obytes : 8-obytes);
!   
!   if(ichannels == 2 && ochannels == 1){
!     /* Stereo -> mono is a special case loop; we downmix */
!     for(i=0;i<scnt;i++){
!       int valueL = iconvert(&x,ijump) ^ isign; /* side effect; increments x */
!       int valueR = iconvert(&x,ijump) ^ isign; /* side effect; increments x */
!       int value  = (valueL>>1) + (valueR>>1);
!       oconvert(&y,ojump,value^osign);  /* side effect; increments y */
      }
!     return;
    }
!   if(ichannels == 1 && ochannels == 2){
!     /* mono->stereo is a special case loop; we replicate */
!     for(i=0;i<scnt;i++){
!       int value = iconvert(&x,ijump) ^ sign; /* side effect; increments x */
!       oconvert(&y,ojump,value);  /* side effect; increments y */
!       oconvert(&y,ojump,value);  /* side effect; increments y */
        }
!     return;
    }
+   if(ichannels<ochannels){
+     /* zero out extra output channels */
+     for(i=0;i<scnt;i++){
+       for(j=0;j<ichannels;j++){
+ 	int value = iconvert(&x,ijump) ^ sign; /* side effect; increments x */
+ 	oconvert(&y,ojump,value);  /* side effect; increments y */
+ 	
        }
!       for(;j<ochannels;j++){
! 	oconvert(&y,ojump,osign);  /* side effect; increments y */
        }
      }
!     return;
    }
!   if(ichannels>=ochannels){
!     /* discard extra input channels */
!     int xincrement=ibytes*(ichannels-ochannels);
!     for(i=0;i<scnt;i++){
!       for(j=0;j<ichannels;j++){
! 	int value = iconvert(&x,ijump) ^ sign; /* side effect; increments x */
! 	oconvert(&y,ojump,value);  /* side effect; increments y */
  	
        }
!       x+=xincrement;
      }
!     return;
    }
  }
  
  static void usbin_convert(struct usbin *u, unsigned char *buffer, unsigned int samples)
  {
!         unsigned int scnt;
! 	unsigned int ufmtb = AFMT_SAMPLEBYTES(u->format);
! 	unsigned int dfmtb = AFMT_SAMPLEBYTES(u->dma.format);
!         unsigned char tmp[TMPCOPYWIDTH];
! 	unsigned int maxs  = sizeof(tmp)/dfmtb;
! 
          while (samples > 0) {
                  scnt = samples;
                  if (scnt > maxs)
                          scnt = maxs;
! 
! 	        conversion(buffer, u->format, tmp, u->dma.format, scnt);
!                 dmabuf_copyin(&u->dma, tmp, scnt * dfmtb);
!                 buffer += scnt * ufmtb;
                  samples -= scnt;
          }
  }               
***************
*** 837,843 ****
  {
  	unsigned int i, maxsize, offs;
  
! 	maxsize = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
  	//printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
  	for (i = offs = 0; i < DESCFRAMES; i++, offs += maxsize) {
  		urb->iso_frame_desc[i].length = maxsize;
--- 918,924 ----
  {
  	unsigned int i, maxsize, offs;
  
! 	maxsize = ((u->freqmax + 0x3fff) * AFMT_SAMPLEBYTES(u->format)) >> 14;
  	//printk(KERN_DEBUG "usbin_prepare_desc: maxsize %d freq 0x%x format 0x%x\n", maxsize, u->freqn, u->format);
  	for (i = offs = 0; i < DESCFRAMES; i++, offs += maxsize) {
  		urb->iso_frame_desc[i].length = maxsize;
***************
*** 852,877 ****
   */
  static int usbin_retire_desc(struct usbin *u, struct urb *urb)
  {
! 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
  	unsigned char *cp;
  
! 	ufmtsh = AFMT_BYTESSHIFT(u->format);
! 	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
  	for (i = 0; i < DESCFRAMES; i++) {
  		cp = ((unsigned char *)urb->transfer_buffer) + urb->iso_frame_desc[i].offset;
  		if (urb->iso_frame_desc[i].status) {
  			dprintk((KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
  			continue;
  		}
! 		scnt = urb->iso_frame_desc[i].actual_length >> ufmtsh;
  		if (!scnt)
  			continue;
! 		cnt = scnt << dfmtsh;
  		if (!u->dma.mapped) {
  			dmafree = u->dma.dmasize - u->dma.count;
  			if (cnt > dmafree) {
! 				scnt = dmafree >> dfmtsh;
! 				cnt = scnt << dfmtsh;
  				err++;
  			}
  		}
--- 933,958 ----
   */
  static int usbin_retire_desc(struct usbin *u, struct urb *urb)
  {
! 	unsigned int i, ufmtb, dfmtb, err = 0, cnt, scnt, dmafree;
  	unsigned char *cp;
  
! 	ufmtb = AFMT_SAMPLEBYTES(u->format);
! 	dfmtb = AFMT_SAMPLEBYTES(u->dma.format);
  	for (i = 0; i < DESCFRAMES; i++) {
  		cp = ((unsigned char *)urb->transfer_buffer) + urb->iso_frame_desc[i].offset;
  		if (urb->iso_frame_desc[i].status) {
  			dprintk((KERN_DEBUG "usbin_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
  			continue;
  		}
! 		scnt = urb->iso_frame_desc[i].actual_length / ufmtb;
  		if (!scnt)
  			continue;
! 		cnt = scnt * dfmtb;
  		if (!u->dma.mapped) {
  			dmafree = u->dma.dmasize - u->dma.count;
  			if (cnt > dmafree) {
! 				scnt = dmafree / dfmtb;
! 				cnt = scnt * dfmtb;
  				err++;
  			}
  		}
***************
*** 922,928 ****
  	} else {
  		u->flags &= ~(mask | FLG_RUNNING);
  		wake_up(&u->dma.wait);
! 		printk(KERN_DEBUG "usbin_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret);
  	}
  	spin_unlock_irqrestore(&as->lock, flags);
  }
--- 1003,1009 ----
  	} else {
  		u->flags &= ~(mask | FLG_RUNNING);
  		wake_up(&u->dma.wait);
! 		dprintk((KERN_DEBUG "usbin_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
  	}
  	spin_unlock_irqrestore(&as->lock, flags);
  }
***************
*** 1015,1021 ****
  		u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
  		u->freqmax = u->freqn + (u->freqn >> 2);
  		u->phase = 0;
! 		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
  		bufsz = DESCFRAMES * maxsze;
  		if (u->durb[0].urb.transfer_buffer)
  			kfree(u->durb[0].urb.transfer_buffer);
--- 1096,1102 ----
  		u->freqn = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
  		u->freqmax = u->freqn + (u->freqn >> 2);
  		u->phase = 0;
! 		maxsze = ((u->freqmax + 0x3fff) * AFMT_SAMPLEBYTES(u->format)) >> 14;
  		bufsz = DESCFRAMES * maxsze;
  		if (u->durb[0].urb.transfer_buffer)
  			kfree(u->durb[0].urb.transfer_buffer);
***************
*** 1166,1198 ****
  
  static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
  {
! 	union {
! 		__s16 s[64];
! 		unsigned char b[0];
! 	} tmp;
! 	unsigned int scnt, maxs, ufmtsh, dfmtsh;
! 
! 	ufmtsh = AFMT_BYTESSHIFT(u->format);
! 	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
! 	maxs = (AFMT_ISSTEREO(u->dma.format | u->format)) ? 32 : 64;
  	while (samples > 0) {
  		scnt = samples;
  		if (scnt > maxs)
  			scnt = maxs;
! 		dmabuf_copyout(&u->dma, tmp.b, scnt << dfmtsh);
! 		conversion(tmp.b, u->dma.format, buffer, u->format, tmp.b, scnt);
! 		buffer += scnt << ufmtsh;
  		samples -= scnt;
  	}
  }		
  
  static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
  {
! 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
  	unsigned char *cp = urb->transfer_buffer;
  
! 	ufmtsh = AFMT_BYTESSHIFT(u->format);
! 	dfmtsh = AFMT_BYTESSHIFT(u->dma.format);
  	for (i = offs = 0; i < DESCFRAMES; i++) {
  		urb->iso_frame_desc[i].offset = offs;
  		u->phase = (u->phase & 0x3fff) + u->freqm;
--- 1247,1277 ----
  
  static void usbout_convert(struct usbout *u, unsigned char *buffer, unsigned int samples)
  {
!         unsigned char tmp[TMPCOPYWIDTH];
!         unsigned int scnt;
! 	unsigned int ufmtb = AFMT_SAMPLEBYTES(u->format);
! 	unsigned int dfmtb = AFMT_SAMPLEBYTES(u->dma.format);
! 	unsigned int maxs  = sizeof(tmp)/dfmtb;
! 	
          while (samples > 0) {
                  scnt = samples;
                  if (scnt > maxs)
                          scnt = maxs;
! 
! 		dmabuf_copyout(&u->dma, tmp, scnt * dfmtb);
! 		conversion(tmp, u->dma.format, buffer, u->format, scnt);
!                 buffer += scnt * ufmtb;
                  samples -= scnt;
          }
  }		
  
  static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
  {
! 	unsigned int i, ufmtb, dfmtb, err = 0, cnt, scnt, offs;
  	unsigned char *cp = urb->transfer_buffer;
  
! 	ufmtb = AFMT_SAMPLEBYTES(u->format);
! 	dfmtb = AFMT_SAMPLEBYTES(u->dma.format);
  	for (i = offs = 0; i < DESCFRAMES; i++) {
  		urb->iso_frame_desc[i].offset = offs;
  		u->phase = (u->phase & 0x3fff) + u->freqm;
***************
*** 1201,1211 ****
  			urb->iso_frame_desc[i].length = 0;
  			continue;
  		}
! 		cnt = scnt << dfmtsh;
  		if (!u->dma.mapped) {
  			if (cnt > u->dma.count) {
! 				scnt = u->dma.count >> dfmtsh;
! 				cnt = scnt << dfmtsh;
  				err++;
  			}
  			u->dma.count -= cnt;
--- 1280,1290 ----
  			urb->iso_frame_desc[i].length = 0;
  			continue;
  		}
! 		cnt = scnt * dfmtb;
  		if (!u->dma.mapped) {
  			if (cnt > u->dma.count) {
! 				scnt = u->dma.count / dfmtb;
! 				cnt = scnt * dfmtb;
  				err++;
  			}
  			u->dma.count -= cnt;
***************
*** 1218,1224 ****
  			/* we need sampling format conversion */
  			usbout_convert(u, cp, scnt);
  		}
! 		cnt = scnt << ufmtsh;
  		urb->iso_frame_desc[i].length = cnt;
  		offs += cnt;
  		cp += cnt;
--- 1297,1303 ----
  			/* we need sampling format conversion */
  			usbout_convert(u, cp, scnt);
  		}
! 		cnt = scnt * ufmtb;
  		urb->iso_frame_desc[i].length = cnt;
  		offs += cnt;
  		cp += cnt;
***************
*** 1380,1386 ****
  		u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
  		u->freqmax = u->freqn + (u->freqn >> 2);
  		u->phase = 0;
! 		maxsze = (u->freqmax + 0x3fff) >> (14 - AFMT_BYTESSHIFT(u->format));
  		bufsz = DESCFRAMES * maxsze;
  		if (u->durb[0].urb.transfer_buffer)
  			kfree(u->durb[0].urb.transfer_buffer);
--- 1459,1466 ----
  		u->freqn = u->freqm = ((u->dma.srate << 11) + 62) / 125; /* this will overflow at approx 2MSPS */
  		u->freqmax = u->freqn + (u->freqn >> 2);
  		u->phase = 0;
! 		maxsze = ((u->freqmax + 0x3fff) * AFMT_SAMPLEBYTES(u->format)) >>14;
! 
  		bufsz = DESCFRAMES * maxsze;
  		if (u->durb[0].urb.transfer_buffer)
  			kfree(u->durb[0].urb.transfer_buffer);
***************
*** 1473,1499 ****
  }
  
  /* --------------------------------------------------------------------- */
  
! static unsigned int format_goodness(struct audioformat *afp, unsigned int fmt, unsigned int srate)
! {
  	unsigned int g = 0;
  
! 	if (srate < afp->sratelo)
! 		g += afp->sratelo - srate;
! 	if (srate > afp->sratehi)
! 		g += srate - afp->sratehi;
! 	if (AFMT_ISSTEREO(afp->format) && !AFMT_ISSTEREO(fmt))
! 		g += 0x100000;
! 	if (!AFMT_ISSTEREO(afp->format) && AFMT_ISSTEREO(fmt))
! 		g += 0x400000;
! 	if (AFMT_IS16BIT(afp->format) && !AFMT_IS16BIT(fmt))
! 		g += 0x100000;
! 	if (!AFMT_IS16BIT(afp->format) && AFMT_IS16BIT(fmt))
! 		g += 0x400000;
! 	return g;
  }
  
! static int find_format(struct audioformat *afp, unsigned int nr, unsigned int fmt, unsigned int srate)
  {
  	unsigned int i, g, gb = ~0;
  	int j = -1; /* default to failure */
--- 1553,1638 ----
  }
  
  /* --------------------------------------------------------------------- */
+ /* allowed conversions (sign, endian, width, channels), and relative
+    weighting penalties against fuzzy match selection.  For the
+    purposes of not confusing users, 'lossy' format translation is
+    disallowed, eg, don't allow a mono 8 bit device to successfully
+    open as 5.1, 24 bit... Never allow a mode that tries to deliver greater
+    than the hard capabilities of the device.
+ 
+    device --=> app
+ 
+    signed   => unsigned : 1
+    unsigned => signed   : 1
+ 
+    le       => be       : 1
+    be       => le       : 1
+ 
+    8        => 16       : not allowed
+    8        => 24       : not allowed
+    8        => 32       : not allowed
+    16       => 24       : not allowed
+    16       => 32       : not allowed
+    24       => 32       : not allowed
+ 
+    16       => 8        : 4
+    24       => 16       : 4
+    24       => 8        : 5
+    32       => 24       : 4
+    32       => 16       : 5
+    32       => 8        : 5
  
!    mono     => stereo   : not allowed
!    stereo   => mono     : 32 (downmix to L+R/2)
! 
!    N        => >N       : not allowed
!    N        => <N       : 32 */
! 
! static unsigned int format_goodness(struct audioformat *afp, unsigned int app,
! 				    unsigned int srate){
  	unsigned int g = 0;
+ 	unsigned int sratelo=afp->sratelo;
+ 	unsigned int sratehi=afp->sratehi;
+ 	unsigned int dev=afp->format;
+ 
+ 	if(AFMT_SIGN(dev) && !AFMT_SIGN(app))     g += 1;
+ 	if(!AFMT_SIGN(dev) && AFMT_SIGN(app))     g += 1;
+ 	if(AFMT_ENDIAN(dev) && !AFMT_ENDIAN(app)) g += 1;
+ 	if(!AFMT_ENDIAN(dev) && AFMT_ENDIAN(app)) g += 1;
+ 
+ 	switch(AFMT_BYTES(app)+AFMT_BYTES(dev)*10){
+ 	case 12: return ~0;
+ 	case 13: return ~0;
+ 	case 14: return ~0;
+ 	case 21: g += 4; break;
+ 	case 23: return ~0;
+ 	case 24: return ~0;
+ 	case 31: g += 5; break;
+ 	case 32: g += 4; break;
+ 	case 34: return ~0;
+ 	case 41: g += 6; break;
+ 	case 42: g += 5; break;
+ 	case 43: g += 4; break;
+ 	}
+ 
+ 	if(AFMT_CHANNELS(dev) > AFMT_CHANNELS(app)){
+ 	        g+=32;
+ 	}else if(AFMT_CHANNELS(dev) < AFMT_CHANNELS(app)){
+ 	        return ~0;
+ 	}
+ 	  
+ 	g<<=20;
+ 
+ 	if (srate < sratelo)
+ 	        g += sratelo - srate;
+         if (srate > sratehi)
+ 	        g += srate - sratehi;
  
! 	return(g);
  }
  
! static int find_format(struct audioformat *afp, unsigned int nr, 
! 			  unsigned int fmt, unsigned int srate)
  {
  	unsigned int i, g, gb = ~0;
  	int j = -1; /* default to failure */
***************
*** 1501,1508 ****
  	/* find "best" format (according to format_goodness) */
  	for (i = 0; i < nr; i++) {
  		g = format_goodness(&afp[i], fmt, srate);
! 		if (g >= gb) 
! 			continue;
  		j = i;
  		gb = g;
  	}
--- 1640,1646 ----
  	/* find "best" format (according to format_goodness) */
  	for (i = 0; i < nr; i++) {
  		g = format_goodness(&afp[i], fmt, srate);
! 		if (g >= gb) continue;
  		j = i;
  		gb = g;
  	}
***************
*** 2116,2123 ****
  			set_current_state(TASK_RUNNING);
  			return -EBUSY;
  		}
! 		tmo = 3 * HZ * count / as->usbout.dma.srate;
! 		tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);
  		if (!schedule_timeout(tmo + 1)) {
  			printk(KERN_DEBUG "usbaudio: dma timed out??\n");
  			break;
--- 2254,2261 ----
  			set_current_state(TASK_RUNNING);
  			return -EBUSY;
  		}
! 		tmo = 3 * HZ * count / (as->usbout.dma.srate * 
! 					AFMT_SAMPLEBYTES(as->usbout.dma.format));
  		if (!schedule_timeout(tmo + 1)) {
  			printk(KERN_DEBUG "usbaudio: dma timed out??\n");
  			break;
***************
*** 2218,2224 ****
  		return ret;
  	if (!access_ok(VERIFY_READ, buffer, count))
  		return -EFAULT;
! 	start_thr = (as->usbout.dma.srate << AFMT_BYTESSHIFT(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
  	add_wait_queue(&as->usbout.dma.wait, &wait);
  	while (count > 0) {
  #if 0
--- 2356,2362 ----
  		return ret;
  	if (!access_ok(VERIFY_READ, buffer, count))
  		return -EFAULT;
! 	start_thr = (as->usbout.dma.srate * AFMT_SAMPLEBYTES(as->usbout.dma.format)) / (1000 / (3 * DESCFRAMES));
  	add_wait_queue(&as->usbout.dma.wait, &wait);
  	while (count > 0) {
  #if 0
***************
*** 2410,2415 ****
--- 2548,2554 ----
  		if (get_user(val, (int *)arg))
  			return -EFAULT;
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
+ 		val2 &= 0x00ffffff;
  		if (val)
  			val2 |= AFMT_STEREO;
  		else
***************
*** 2423,2441 ****
  			return -EFAULT;
  		if (val != 0) {
  			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 			if (val == 1)
! 				val2 &= ~AFMT_STEREO;
! 			else
! 				val2 |= AFMT_STEREO;
  			if (set_format(as, file->f_mode, val2, 0))
  				return -EIO;
  		}
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
  
  	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
  		return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
! 				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, (int *)arg);
  
  	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
  		if (get_user(val, (int *)arg))
--- 2562,2583 ----
  			return -EFAULT;
  		if (val != 0) {
  			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 			
! 			val2 &= 0x00ffffff;
! 			val2 |= (val-1)<<24;
! 
  			if (set_format(as, file->f_mode, val2, 0))
  				return -EIO;
  		}
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 		return put_user(AFMT_CHANNELS(val2), (int *)arg);
  
  	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
  		return put_user(AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
! 				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE |
! 				AFMT_U24_LE | AFMT_U24_BE | AFMT_S24_LE | AFMT_S24_BE |
! 				AFMT_U32_LE | AFMT_U32_BE | AFMT_S32_LE | AFMT_S32_BE,
! 				(int *)arg);
  
  	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
  		if (get_user(val, (int *)arg))
***************
*** 2444,2458 ****
  			if (hweight32(val) != 1)
  				return -EINVAL;
  			if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
! 				     AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE)))
  				return -EINVAL;
  			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 			val |= val2 & AFMT_STEREO;
  			if (set_format(as, file->f_mode, val, 0))
  				return -EIO;
  		}
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 		return put_user(val2 & ~AFMT_STEREO, (int *)arg);
  
  	case SNDCTL_DSP_POST:
  		return 0;
--- 2586,2602 ----
  			if (hweight32(val) != 1)
  				return -EINVAL;
  			if (!(val & (AFMT_U8 | AFMT_U16_LE | AFMT_U16_BE |
! 				     AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE |
! 				     AFMT_U24_LE | AFMT_U24_BE | AFMT_S24_LE | AFMT_S24_BE |
! 				     AFMT_U32_LE | AFMT_U32_BE | AFMT_S32_LE | AFMT_S32_BE)))
  				return -EINVAL;
  			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 			val |= val2 & AFMT_CHMASK;
  			if (set_format(as, file->f_mode, val, 0))
  				return -EIO;
  		}
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 		return put_user(val2 & ~AFMT_CHMASK, (int *)arg);
  
  	case SNDCTL_DSP_POST:
  		return 0;
***************
*** 2491,2497 ****
  	case SNDCTL_DSP_GETOSPACE:
  		if (!(file->f_mode & FMODE_WRITE))
  			return -EINVAL;
! 		if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
  			return val;
  		spin_lock_irqsave(&as->lock, flags);
  		abinfo.fragsize = as->usbout.dma.fragsize;
--- 2635,2658 ----
  	case SNDCTL_DSP_GETOSPACE:
  		if (!(file->f_mode & FMODE_WRITE))
  			return -EINVAL;
! 
! 		/*if (!(as->usbout.flags & FLG_RUNNING) && (val = prog_dmabuf_out(as)) != 0)
! 
! 		The above is potentially disasterous; if the
! 		userspace app calls the GETOSPACE ioctl() before a
! 		data write on the device (as can happen in a
! 		sensible client that's tracking the write buffer
! 		low watermark), the kernel driver will never
! 		recover from momentary starvation (recall that
! 		FLG_RUNNING will be cleared by usbout_completed)
! 		because the ioctl will keep resetting the DMA
! 		buffer before each write, potentially never
! 		allowing us to fill the buffer back to the DMA
! 		restart threshhold.
! 
! 		Can you tell this was actually biting me? :-) */
! 
! 		if ((!as->usbout.dma.ready) && (val = prog_dmabuf_out(as)) != 0)
  			return val;
  		spin_lock_irqsave(&as->lock, flags);
  		abinfo.fragsize = as->usbout.dma.fragsize;
***************
*** 2504,2510 ****
  	case SNDCTL_DSP_GETISPACE:
  		if (!(file->f_mode & FMODE_READ))
  			return -EINVAL;
! 		if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)
  			return val;
  		spin_lock_irqsave(&as->lock, flags);
  		abinfo.fragsize = as->usbin.dma.fragsize;
--- 2665,2673 ----
  	case SNDCTL_DSP_GETISPACE:
  		if (!(file->f_mode & FMODE_READ))
  			return -EINVAL;
! 		
! 		/*if (!(as->usbin.flags & FLG_RUNNING) && (val = prog_dmabuf_in(as)) != 0)*/
! 		if ((!as->usbin.dma.ready) && (val = prog_dmabuf_in(as)) != 0)
  			return val;
  		spin_lock_irqsave(&as->lock, flags);
  		abinfo.fragsize = as->usbin.dma.fragsize;
***************
*** 2552,2562 ****
  
         case SNDCTL_DSP_GETBLKSIZE:
  		if (file->f_mode & FMODE_WRITE) {
! 			if ((val = prog_dmabuf_out(as)))
  				return val;
  			return put_user(as->usbout.dma.fragsize, (int *)arg);
  		}
! 		if ((val = prog_dmabuf_in(as)))
  			return val;
  		return put_user(as->usbin.dma.fragsize, (int *)arg);
  
--- 2715,2728 ----
  
         case SNDCTL_DSP_GETBLKSIZE:
  		if (file->f_mode & FMODE_WRITE) {
! 
! 		  /* do not clobber devices that are already running! */
! 		  if ((!as->usbout.dma.ready) && (val = prog_dmabuf_out(as)) != 0)
  		    return val;
  		  return put_user(as->usbout.dma.fragsize, (int *)arg);
  		}
! 		/* do not clobber devices that are already running! */
! 		if ((!as->usbin.dma.ready) && (val = prog_dmabuf_in(as)) != 0)
  		  return val;
  		return put_user(as->usbin.dma.fragsize, (int *)arg);
  
***************
*** 2604,2614 ****
  
  	case SOUND_PCM_READ_CHANNELS:
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 		return put_user(AFMT_ISSTEREO(val2) ? 2 : 1, (int *)arg);
  
  	case SOUND_PCM_READ_BITS:
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 		return put_user(AFMT_IS16BIT(val2) ? 16 : 8, (int *)arg);
  
  	case SOUND_PCM_WRITE_FILTER:
  	case SNDCTL_DSP_SETSYNCRO:
--- 2770,2780 ----
  
  	case SOUND_PCM_READ_CHANNELS:
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 		return put_user(AFMT_CHANNELS(val2), (int *)arg);
  
  	case SOUND_PCM_READ_BITS:
  		val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
! 		return put_user(AFMT_BYTES(val2) * 8, (int *)arg);
  
  	case SOUND_PCM_WRITE_FILTER:
  	case SNDCTL_DSP_SETSYNCRO:
***************
*** 2864,2870 ****
  				       dev->devnum, asifin, i);
  				continue;
  			}
! 			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
  			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
  			if (!fmt) {
  				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
--- 3030,3038 ----
  				       dev->devnum, asifin, i);
  				continue;
  			}
! 			format = (fmt[5] == 2) ? 
! 			  (AFMT_U32_LE | AFMT_U24_LE | AFMT_U16_LE | AFMT_U8) : 
! 			  (AFMT_S32_LE | AFMT_S24_LE | AFMT_S16_LE | AFMT_S8);
  			fmt = find_csinterface_descriptor(buffer, buflen, NULL, FORMAT_TYPE, asifin, i);
  			if (!fmt) {
  				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u FORMAT_TYPE descriptor not found\n", 
***************
*** 2876,2882 ****
  				       dev->devnum, asifin, i);
  				continue;
  			}
! 			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
  				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
  				       dev->devnum, asifin, i, fmt[4], fmt[5]);
  				continue;
--- 3044,3050 ----
  				       dev->devnum, asifin, i);
  				continue;
  			}
! 			if (fmt[4] < 1 || fmt[4] > MAXCHANNELS || fmt[5] < 1 || fmt[5] > 4) {
  				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
  				       dev->devnum, asifin, i, fmt[4], fmt[5]);
  				continue;
***************
*** 2889,2901 ****
  			}
  			if (as->numfmtin >= MAXFORMATS)
  				continue;
  			fp = &as->fmtin[as->numfmtin++];
! 			if (fmt[5] == 2)
! 				format &= (AFMT_U16_LE | AFMT_S16_LE);
! 			else
  				format &= (AFMT_U8 | AFMT_S8);
! 			if (fmt[4] == 2)
! 				format |= AFMT_STEREO;
  			fp->format = format;
  			fp->altsetting = i;
  			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
--- 3057,3082 ----
  			}
  			if (as->numfmtin >= MAXFORMATS)
  				continue;
+ 			printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u channels %u framesize %u configured\n", 
+ 				       dev->devnum, asifin, i, fmt[4], fmt[5]);
  			fp = &as->fmtin[as->numfmtin++];
! 			switch (fmt[5]) {
! 			case 1:
  			        format &= (AFMT_U8 | AFMT_S8);
! 				break;
! 			case 2:
! 				format &= (AFMT_U16_LE | AFMT_S16_LE);
! 				break;
! 			case 3:
! 				format &= (AFMT_U24_LE | AFMT_S24_LE);
! 				break;
! 			case 4:
! 				format &= (AFMT_U32_LE | AFMT_S32_LE);
! 				break;
! 			}
! 			
! 			format |= (fmt[4]-1) << 24;
! 
  			fp->format = format;
  			fp->altsetting = i;
  			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
***************
*** 2944,2950 ****
  				       dev->devnum, asifout, i);
  				continue;
  			}
! 			format = (fmt[5] == 2) ? (AFMT_U16_LE | AFMT_U8) : (AFMT_S16_LE | AFMT_S8);
  			/* Dallas DS4201 workaround */
  			if (dev->descriptor.idVendor == 0x04fa && dev->descriptor.idProduct == 0x4201)
  				format = (AFMT_S16_LE | AFMT_S8);
--- 3125,3134 ----
  				       dev->devnum, asifout, i);
  				continue;
  			}
! 			format = (fmt[5] == 2) ? 
! 			  (AFMT_U32_LE | AFMT_U24_LE | AFMT_U16_LE | AFMT_U8) : 
! 			  (AFMT_S32_LE | AFMT_S24_LE | AFMT_S16_LE | AFMT_S8);
! 
  			/* Dallas DS4201 workaround */
  			if (dev->descriptor.idVendor == 0x04fa && dev->descriptor.idProduct == 0x4201)
  				format = (AFMT_S16_LE | AFMT_S8);
***************
*** 2959,2965 ****
  				       dev->devnum, asifout, i);
  				continue;
  			}
! 			if (fmt[4] < 1 || fmt[4] > 2 || fmt[5] < 1 || fmt[5] > 2) {
  				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
  				       dev->devnum, asifout, i, fmt[4], fmt[5]);
  				continue;
--- 3143,3149 ----
  				       dev->devnum, asifout, i);
  				continue;
  			}
! 			if (fmt[4] < 1 || fmt[4] > MAXCHANNELS || fmt[5] < 1 || fmt[5] > 4) {
  				printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u unsupported channels %u framesize %u\n", 
  				       dev->devnum, asifout, i, fmt[4], fmt[5]);
  				continue;
***************
*** 2972,2984 ****
  			}
  			if (as->numfmtout >= MAXFORMATS)
  				continue;
  			fp = &as->fmtout[as->numfmtout++];
! 			if (fmt[5] == 2)
! 				format &= (AFMT_U16_LE | AFMT_S16_LE);
! 			else
  				format &= (AFMT_U8 | AFMT_S8);
! 			if (fmt[4] == 2)
! 				format |= AFMT_STEREO;
  			fp->format = format;
  			fp->altsetting = i;
  			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);
--- 3156,3182 ----
  			}
  			if (as->numfmtout >= MAXFORMATS)
  				continue;
+ 			printk(KERN_ERR "usbaudio: device %u interface %u altsetting %u channels %u framesize %u configured\n", 
+ 			       dev->devnum, asifout, i, fmt[4], fmt[5]);
  			fp = &as->fmtout[as->numfmtout++];
! 
! 			switch (fmt[5]) {
! 			case 1:
  			        format &= (AFMT_U8 | AFMT_S8);
! 				break;
! 			case 2:
! 				format &= (AFMT_U16_LE | AFMT_S16_LE);
! 				break;
! 			case 3:
! 				format &= (AFMT_U24_LE | AFMT_S24_LE);
! 				break;
! 			case 4:
! 				format &= (AFMT_U32_LE | AFMT_S32_LE);
! 				break;
! 			}
! 
! 			format |= (fmt[4]-1) << 24;
! 
  			fp->format = format;
  			fp->altsetting = i;
  			fp->sratelo = fp->sratehi = fmt[8] | (fmt[9] << 8) | (fmt[10] << 16);


More information about the Linux-audio-dev mailing list