📄 audio.c
字号:
{
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;
}
}
static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
{
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;
}
urb->interval = 1;
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, 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 pt_regs *regs)
{
struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
struct usbin *u = &as->usbin;
unsigned long flags;
unsigned int mask;
int suret = 0;
#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, GFP_ATOMIC)) == 0) {
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;
}
urb->interval = 1;
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 pt_regs *regs)
{
struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
struct usbin *u = &as->usbin;
unsigned long flags;
unsigned int mask;
int suret = 0;
#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, GFP_ATOMIC)) == 0) {
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) >> (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 = URB_ISO_ASAP;
urb->number_of_packets = DESCFRAMES;
urb->context = as;
urb->complete = usbin_completed;
if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
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 = URB_ISO_ASAP;
urb->number_of_packets = DESCFRAMES;
urb->context = as;
urb->complete = usbin_completed;
if (!usbin_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_KERNEL))
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 = URB_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, GFP_KERNEL))
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 = URB_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, GFP_KERNEL))
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_kill_urb(u->durb[0].urb);
if (i & FLG_URB1RUNNING)
usb_kill_urb(u->durb[1].urb);
if (i & FLG_SYNC0RUNNING)
usb_kill_urb(u->surb[0].urb);
if (i & FLG_SYNC1RUNNING)
usb_kill_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, 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;
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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -