📄 audio.c
字号:
*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; }} static int usbin_prepare_desc(struct usbin *u, struct urb *urb){ 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; urb->iso_frame_desc[i].offset = offs; } return 0;}/* * return value: 0 if descriptor should be restarted, -1 otherwise * convert sample format on the fly if necessary */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++; } } u->dma.count += cnt; if (u->format == u->dma.format) { /* we do not need format conversion */ dprintk((KERN_DEBUG "usbaudio: no sample format conversion\n")); dmabuf_copyin(&u->dma, cp, cnt); } else { /* we need sampling format conversion */ dprintk((KERN_DEBUG "usbaudio: sample format conversion %x != %x\n", u->format, u->dma.format)); usbin_convert(u, cp, scnt); } } if (err) u->dma.error++; if (u->dma.count >= (signed)u->dma.fragsize) wake_up(&u->dma.wait); return err ? -1 : 0;}static void usbin_completed(struct urb *urb){ struct usb_audiodev *as = (struct usb_audiodev *)urb->context; struct usbin *u = &as->usbin; unsigned long flags; unsigned int mask; int suret = USB_ST_NOERROR;#if 0 printk(KERN_DEBUG "usbin_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);#endif if (urb == &u->durb[0].urb) mask = FLG_URB0RUNNING; else if (urb == &u->durb[1].urb) mask = FLG_URB1RUNNING; else { mask = 0; printk(KERN_ERR "usbin_completed: panic: unknown URB\n"); } urb->dev = as->state->usbdev; spin_lock_irqsave(&as->lock, flags); if (!usbin_retire_desc(u, urb) && u->flags & FLG_RUNNING && !usbin_prepare_desc(u, urb) && (suret = usb_submit_urb(urb)) == USB_ST_NOERROR) { u->flags |= mask; } 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);}/* * we output sync data */static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb){ unsigned char *cp = urb->transfer_buffer; unsigned int i, offs; for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3, cp += 3) { urb->iso_frame_desc[i].length = 3; urb->iso_frame_desc[i].offset = offs; cp[0] = u->freqn; cp[1] = u->freqn >> 8; cp[2] = u->freqn >> 16; } return 0;}/* * return value: 0 if descriptor should be restarted, -1 otherwise */static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb){ unsigned int i; for (i = 0; i < SYNCFRAMES; i++) if (urb->iso_frame_desc[0].status) dprintk((KERN_DEBUG "usbin_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status)); return 0;}static void usbin_sync_completed(struct urb *urb){ struct usb_audiodev *as = (struct usb_audiodev *)urb->context; struct usbin *u = &as->usbin; unsigned long flags; unsigned int mask; int suret = USB_ST_NOERROR;#if 0 printk(KERN_DEBUG "usbin_sync_completed: status %d errcnt %d flags 0x%x\n", urb->status, urb->error_count, u->flags);#endif if (urb == &u->surb[0].urb) mask = FLG_SYNC0RUNNING; else if (urb == &u->surb[1].urb) mask = FLG_SYNC1RUNNING; else { mask = 0; printk(KERN_ERR "usbin_sync_completed: panic: unknown URB\n"); } urb->dev = as->state->usbdev; spin_lock_irqsave(&as->lock, flags); if (!usbin_sync_retire_desc(u, urb) && u->flags & FLG_RUNNING && !usbin_sync_prepare_desc(u, urb) && (suret = usb_submit_urb(urb)) == USB_ST_NOERROR) { u->flags |= mask; } else { u->flags &= ~(mask | FLG_RUNNING); wake_up(&u->dma.wait); dprintk((KERN_DEBUG "usbin_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret)); } spin_unlock_irqrestore(&as->lock, flags);}static int usbin_start(struct usb_audiodev *as){ struct usb_device *dev = as->state->usbdev; struct usbin *u = &as->usbin; struct urb *urb; unsigned long flags; unsigned int maxsze, bufsz;#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 */ spin_lock_irqsave(&as->lock, flags); if (!(u->flags & FLG_CONNECTED)) { spin_unlock_irqrestore(&as->lock, flags); return -EIO; } if (!(u->flags & FLG_RUNNING)) { spin_unlock_irqrestore(&as->lock, flags); 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); u->durb[0].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL); u->durb[0].urb.transfer_buffer_length = bufsz; if (u->durb[1].urb.transfer_buffer) kfree(u->durb[1].urb.transfer_buffer); u->durb[1].urb.transfer_buffer = kmalloc(bufsz, GFP_KERNEL); u->durb[1].urb.transfer_buffer_length = bufsz; if (u->syncpipe) { if (u->surb[0].urb.transfer_buffer) kfree(u->surb[0].urb.transfer_buffer); u->surb[0].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL); u->surb[0].urb.transfer_buffer_length = 3*SYNCFRAMES; if (u->surb[1].urb.transfer_buffer) kfree(u->surb[1].urb.transfer_buffer); u->surb[1].urb.transfer_buffer = kmalloc(3*SYNCFRAMES, GFP_KERNEL); u->surb[1].urb.transfer_buffer_length = 3*SYNCFRAMES; } if (!u->durb[0].urb.transfer_buffer || !u->durb[1].urb.transfer_buffer || (u->syncpipe && (!u->surb[0].urb.transfer_buffer || !u->surb[1].urb.transfer_buffer))) { printk(KERN_ERR "usbaudio: cannot start playback device %d\n", dev->devnum); return 0; } spin_lock_irqsave(&as->lock, flags); } if (u->dma.count >= u->dma.dmasize && !u->dma.mapped) { spin_unlock_irqrestore(&as->lock, flags); return 0; } u->flags |= FLG_RUNNING; if (!(u->flags & FLG_URB0RUNNING)) { urb = &u->durb[0].urb; urb->dev = dev; urb->pipe = u->datapipe; urb->transfer_flags = USB_ISO_ASAP; urb->number_of_packets = DESCFRAMES; urb->context = as; urb->complete = usbin_completed; if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb)) u->flags |= FLG_URB0RUNNING; else u->flags &= ~FLG_RUNNING; } if (u->flags & FLG_RUNNING && !(u->flags & FLG_URB1RUNNING)) { urb = &u->durb[1].urb; urb->dev = dev; urb->pipe = u->datapipe; urb->transfer_flags = USB_ISO_ASAP; urb->number_of_packets = DESCFRAMES; urb->context = as; urb->complete = usbin_completed; if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb)) u->flags |= FLG_URB1RUNNING; else u->flags &= ~FLG_RUNNING; } if (u->syncpipe) { if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC0RUNNING)) { urb = &u->surb[0].urb; urb->dev = dev; urb->pipe = u->syncpipe; urb->transfer_flags = USB_ISO_ASAP; urb->number_of_packets = SYNCFRAMES; urb->context = as; urb->complete = usbin_sync_completed; /* stride: u->syncinterval */ if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb)) u->flags |= FLG_SYNC0RUNNING; else u->flags &= ~FLG_RUNNING; } if (u->flags & FLG_RUNNING && !(u->flags & FLG_SYNC1RUNNING)) { urb = &u->surb[1].urb; urb->dev = dev; urb->pipe = u->syncpipe; urb->transfer_flags = USB_ISO_ASAP; urb->number_of_packets = SYNCFRAMES; urb->context = as; urb->complete = usbin_sync_completed; /* stride: u->syncinterval */ if (!usbin_sync_prepare_desc(u, urb) && !usb_submit_urb(urb)) u->flags |= FLG_SYNC1RUNNING; else u->flags &= ~FLG_RUNNING; } } spin_unlock_irqrestore(&as->lock, flags); return 0;}static void usbout_stop(struct usb_audiodev *as){ struct usbout *u = &as->usbout; unsigned long flags; unsigned int i, notkilled = 1; spin_lock_irqsave(&as->lock, flags); u->flags &= ~FLG_RUNNING; i = u->flags; spin_unlock_irqrestore(&as->lock, flags); while (i & (FLG_URB0RUNNING|FLG_URB1RUNNING|FLG_SYNC0RUNNING|FLG_SYNC1RUNNING)) { set_current_state(notkilled ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); schedule_timeout(1); spin_lock_irqsave(&as->lock, flags); i = u->flags; spin_unlock_irqrestore(&as->lock, flags); if (notkilled && signal_pending(current)) { if (i & FLG_URB0RUNNING) usb_unlink_urb(&u->durb[0].urb); if (i & FLG_URB1RUNNING) usb_unlink_urb(&u->durb[1].urb); if (i & FLG_SYNC0RUNNING) usb_unlink_urb(&u->surb[0].urb); if (i & FLG_SYNC1RUNNING) usb_unlink_urb(&u->surb[1].urb); notkilled = 0; } } set_current_state(TASK_RUNNING); if (u->durb[0].urb.transfer_buffer) kfree(u->durb[0].urb.transfer_buffer);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -