*** /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 * 2001-06-16: Bryce Nesbitt * Fix SNDCTL_DSP_STEREO API violation + * 2002-10-16: Monty + * 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<> 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>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=ochannels){ ! /* discard extra input channels */ ! int xincrement=ibytes*(ichannels-ochannels); ! for(i=0;iformat); ! 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 => 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);