📄 audio.c
字号:
/* 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;
}
urb->interval = 1;
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, struct urb *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, struct pt_regs *regs)
{
struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
struct usbout *u = &as->usbout;
unsigned long flags;
unsigned int mask;
int suret = 0;
#if 0
printk(KERN_DEBUG "usbout_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 "usbout_completed: panic: unknown URB\n");
}
urb->dev = as->state->usbdev;
spin_lock_irqsave(&as->lock, flags);
if (!usbout_retire_desc(u, urb) &&
u->flags & FLG_RUNNING &&
!usbout_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 "usbout_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
}
spin_unlock_irqrestore(&as->lock, flags);
}
static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
{
unsigned int i, offs;
for (i = offs = 0; i < SYNCFRAMES; i++, offs += 3) {
urb->iso_frame_desc[i].length = 3;
urb->iso_frame_desc[i].offset = offs;
}
urb->interval = 1;
return 0;
}
/*
* return value: 0 if descriptor should be restarted, -1 otherwise
*/
static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
{
unsigned char *cp = urb->transfer_buffer;
unsigned int f, i;
for (i = 0; i < SYNCFRAMES; i++, cp += 3) {
if (urb->iso_frame_desc[i].status) {
dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u status %d\n", i, urb->iso_frame_desc[i].status));
continue;
}
if (urb->iso_frame_desc[i].actual_length < 3) {
dprintk((KERN_DEBUG "usbout_sync_retire_desc: frame %u length %d\n", i, urb->iso_frame_desc[i].actual_length));
continue;
}
f = cp[0] | (cp[1] << 8) | (cp[2] << 16);
if (abs(f - u->freqn) > (u->freqn >> 3) || f > u->freqmax) {
printk(KERN_WARNING "usbout_sync_retire_desc: requested frequency %u (nominal %u) out of range!\n", f, u->freqn);
continue;
}
u->freqm = f;
}
return 0;
}
static void usbout_sync_completed(struct urb *urb, struct pt_regs *regs)
{
struct usb_audiodev *as = (struct usb_audiodev *)urb->context;
struct usbout *u = &as->usbout;
unsigned long flags;
unsigned int mask;
int suret = 0;
#if 0
printk(KERN_DEBUG "usbout_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 "usbout_sync_completed: panic: unknown URB\n");
}
urb->dev = as->state->usbdev;
spin_lock_irqsave(&as->lock, flags);
if (!usbout_sync_retire_desc(u, urb) &&
u->flags & FLG_RUNNING &&
!usbout_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 "usbout_sync_completed: descriptor not restarted (usb_submit_urb: %d)\n", suret));
}
spin_unlock_irqrestore(&as->lock, flags);
}
static int usbout_start(struct usb_audiodev *as)
{
struct usb_device *dev = as->state->usbdev;
struct usbout *u = &as->usbout;
struct urb *urb;
unsigned long flags;
unsigned int maxsze, bufsz;
#if 0
printk(KERN_DEBUG "usbout_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->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);
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 <= 0 && !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 = usbout_completed;
if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
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 = usbout_completed;
if (!usbout_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
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 = usbout_sync_completed;
/* stride: u->syncinterval */
if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
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 = usbout_sync_completed;
/* stride: u->syncinterval */
if (!usbout_sync_prepare_desc(u, urb) && !usb_submit_urb(urb, GFP_ATOMIC))
u->flags |= FLG_SYNC1RUNNING;
else
u->flags &= ~FLG_RUNNING;
}
}
spin_unlock_irqrestore(&as->lock, flags);
return 0;
}
/* --------------------------------------------------------------------- */
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 */
/* 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;
}
return j;
}
static int set_format_in(struct usb_audiodev *as)
{
struct usb_device *dev = as->state->usbdev;
struct usb_host_interface *alts;
struct usb_interface *iface;
struct usbin *u = &as->usbin;
struct dmabuf *d = &u->dma;
struct audioformat *fmt;
unsigned int ep;
unsigned char data[3];
int fmtnr, ret;
iface = usb_ifnum_to_if(dev, u->interface);
if (!iface)
return 0;
fmtnr = find_format(as->fmtin, as->numfmtin, d->format, d->srate);
if (fmtnr < 0) {
printk(KERN_ERR "usbaudio: set_format_in(): failed to find desired format/speed combination.\n");
return -1;
}
fmt = as->fmtin + fmtnr;
alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
u->format = fmt->format;
u->datapipe = usb_rcvisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
u->syncpipe = u->syncinterval = 0;
if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x08) {
if (alts->desc.bNumEndpoints < 2 ||
alts->endpoint[1].desc.bmAttributes != 0x01 ||
alts->endpoint[1].desc.bSynchAddress != 0 ||
alts->endpoint[1].desc.bEndpointAddress != (alts->endpoint[0].desc.bSynchAddress & 0x7f)) {
printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims adaptive in "
"but has invalid synch pipe; treating as asynchronous in\n",
dev->devnum, u->interface, fmt->altsetting);
} else {
u->syncpipe = usb_sndisocpipe(dev, alts->endpoint[1].desc.bEndpointAddress & 0xf);
u->syncinterval = alts->endpoint[1].desc.bRefresh;
}
}
if (d->srate < fmt->sratelo)
d->srate = fmt->sratelo;
if (d->srate > fmt->sratehi)
d->srate = fmt->sratehi;
dprintk((KERN_DEBUG "usbaudio: set_format_in: usb_set_interface %u %u\n",
u->interface, fmt->altsetting));
if (usb_set_interface(dev, alts->desc.bInterfaceNumber, fmt->altsetting) < 0) {
printk(KERN_WARNING "usbaudio: usb_set_interface failed, device %d interface %d altsetting %d\n",
dev->devnum, u->interface, fmt->altsetting);
return -1;
}
if (fmt->sratelo == fmt->sratehi)
return 0;
ep = usb_pipeendpoint(u->datapipe) | (u->datapipe & USB_DIR_IN);
/* if endpoint has pitch control, enable it */
if (fmt->attributes & 0x02) {
data[0] = 1;
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
PITCH_CONTROL << 8, ep, data, 1, HZ)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to set output pitch control device %d interface %u endpoint 0x%x to %u\n",
ret, dev->devnum, u->interface, ep, d->srate);
return -1;
}
}
/* if endpoint has sampling rate control, set it */
if (fmt->attributes & 0x01) {
data[0] = d->srate;
data[1] = d->srate >> 8;
data[2] = d->srate >> 16;
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to set input sampling frequency device %d interface %u endpoint 0x%x to %u\n",
ret, dev->devnum, u->interface, ep, d->srate);
return -1;
}
if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
SAMPLING_FREQ_CONTROL << 8, ep, data, 3, HZ)) < 0) {
printk(KERN_ERR "usbaudio: failure (error %d) to get input sampling frequency device %d interface %u endpoint 0x%x\n",
ret, dev->devnum, u->interface, ep);
return -1;
}
dprintk((KERN_DEBUG "usbaudio: set_format_in: device %d interface %d altsetting %d srate req: %u real %u\n",
dev->devnum, u->interface, fmt->altsetting, d->srate, data[0] | (data[1] << 8) | (data[2] << 16)));
d->srate = data[0] | (data[1] << 8) | (data[2] << 16);
}
dprintk((KERN_DEBUG "usbaudio: set_format_in: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate));
return 0;
}
static int set_format_out(struct usb_audiodev *as)
{
struct usb_device *dev = as->state->usbdev;
struct usb_host_interface *alts;
struct usb_interface *iface;
struct usbout *u = &as->usbout;
struct dmabuf *d = &u->dma;
struct audioformat *fmt;
unsigned int ep;
unsigned char data[3];
int fmtnr, ret;
iface = usb_ifnum_to_if(dev, u->interface);
if (!iface)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -