📄 audio.c
字号:
{ 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; 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, purb_t 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++; } } 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, purb_t 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, purb_t 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; purb_t 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) >> (14 - AFMT_BYTESSHIFT(u->format)); 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); if (u->durb[1].urb.transfer_buffer) kfree(u->durb[1].urb.transfer_buffer); if (u->surb[0].urb.transfer_buffer) kfree(u->surb[0].urb.transfer_buffer); if (u->surb[1].urb.transfer_buffer) kfree(u->surb[1].urb.transfer_buffer); u->durb[0].urb.transfer_buffer = u->durb[1].urb.transfer_buffer = u->surb[0].urb.transfer_buffer = u->surb[1].urb.transfer_buffer = NULL;}static inline void usbout_release(struct usb_audiodev *as){ usbout_stop(as);}static void usbout_disc(struct usb_audiodev *as){ struct usbout *u = &as->usbout; unsigned long flags; spin_lock_irqsave(&as->lock, flags); u->flags &= ~(FLG_RUNNING | FLG_CONNECTED); spin_unlock_irqrestore(&as->lock, flags); usbout_stop(as);}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, purb_t 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; scnt = u->phase >> 14; if (!scnt) { 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; } else u->dma.count += cnt; if (u->format == u->dma.format) { /* we do not need format conversion */ dmabuf_copyout(&u->dma, cp, cnt); } else { /* we need sampling format conversion */ usbout_convert(u, cp, scnt); } cnt = scnt << ufmtsh; urb->iso_frame_desc[i].length = cnt; offs += cnt; cp += cnt; } if (err) u->dma.error++; if (u->dma.mapped) { if (u->dma.count >= (signed)u->dma.fragsize) wake_up(&u->dma.wait); } else { if ((signed)u->dma.dmasize >= u->dma.count + (signed)u->dma.fragsize) wake_up(&u->dma.wait); } return err ? -1 : 0;}/* * return value: 0 if descriptor should be restarted, -1 otherwise */static int usbout_retire_desc(struct usbout *u, purb_t urb){ unsigned int i; for (i = 0; i < DESCFRAMES; i++) { if (urb->iso_frame_desc[i].status) { dprintk((KERN_DEBUG "usbout_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status)); continue; } } return 0;}static void usbout_completed(struct urb *urb)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -