📄 audio.c
字号:
return 0;
fmtnr = find_format(as->fmtout, as->numfmtout, d->format, d->srate);
if (fmtnr < 0) {
printk(KERN_ERR "usbaudio: set_format_out(): failed to find desired format/speed combination.\n");
return -1;
}
fmt = as->fmtout + fmtnr;
u->format = fmt->format;
alts = usb_altnum_to_altsetting(iface, fmt->altsetting);
u->datapipe = usb_sndisocpipe(dev, alts->endpoint[0].desc.bEndpointAddress & 0xf);
u->syncpipe = u->syncinterval = 0;
if ((alts->endpoint[0].desc.bmAttributes & 0x0c) == 0x04) {
#if 0
printk(KERN_DEBUG "bNumEndpoints 0x%02x endpoint[1].bmAttributes 0x%02x\n"
KERN_DEBUG "endpoint[1].bSynchAddress 0x%02x endpoint[1].bEndpointAddress 0x%02x\n"
KERN_DEBUG "endpoint[0].bSynchAddress 0x%02x\n", alts->bNumEndpoints,
alts->endpoint[1].bmAttributes, alts->endpoint[1].bSynchAddress,
alts->endpoint[1].bEndpointAddress, alts->endpoint[0].bSynchAddress);
#endif
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 | 0x80)) {
printk(KERN_WARNING "usbaudio: device %d interface %d altsetting %d claims asynch out "
"but has invalid synch pipe; treating as adaptive out\n",
dev->devnum, u->interface, fmt->altsetting);
} else {
u->syncpipe = usb_rcvisocpipe(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_out: usb_set_interface %u %u\n",
u->interface, fmt->altsetting));
if (usb_set_interface(dev, u->interface, 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 output 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 output sampling frequency device %d interface %u endpoint 0x%x\n",
ret, dev->devnum, u->interface, ep);
return -1;
}
dprintk((KERN_DEBUG "usbaudio: set_format_out: 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_out: USB format 0x%x, DMA format 0x%x srate %u\n", u->format, d->format, d->srate));
return 0;
}
static int set_format(struct usb_audiodev *s, unsigned int fmode, unsigned int fmt, unsigned int srate)
{
int ret1 = 0, ret2 = 0;
if (!(fmode & (FMODE_READ|FMODE_WRITE)))
return -EINVAL;
if (fmode & FMODE_READ) {
usbin_stop(s);
s->usbin.dma.ready = 0;
if (fmt == AFMT_QUERY)
fmt = s->usbin.dma.format;
else
s->usbin.dma.format = fmt;
if (!srate)
srate = s->usbin.dma.srate;
else
s->usbin.dma.srate = srate;
}
if (fmode & FMODE_WRITE) {
usbout_stop(s);
s->usbout.dma.ready = 0;
if (fmt == AFMT_QUERY)
fmt = s->usbout.dma.format;
else
s->usbout.dma.format = fmt;
if (!srate)
srate = s->usbout.dma.srate;
else
s->usbout.dma.srate = srate;
}
if (fmode & FMODE_READ)
ret1 = set_format_in(s);
if (fmode & FMODE_WRITE)
ret2 = set_format_out(s);
return ret1 ? ret1 : ret2;
}
/* --------------------------------------------------------------------- */
static int wrmixer(struct usb_mixerdev *ms, unsigned mixch, unsigned value)
{
struct usb_device *dev = ms->state->usbdev;
unsigned char data[2];
struct mixerchannel *ch;
int v1, v2, v3;
if (mixch >= ms->numch)
return -1;
ch = &ms->ch[mixch];
v3 = ch->maxval - ch->minval;
v1 = value & 0xff;
v2 = (value >> 8) & 0xff;
if (v1 > 100)
v1 = 100;
if (v2 > 100)
v2 = 100;
if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
v2 = v1;
ch->value = v1 | (v2 << 8);
v1 = (v1 * v3) / 100 + ch->minval;
v2 = (v2 * v3) / 100 + ch->minval;
switch (ch->selector) {
case 0: /* mixer unit request */
data[0] = v1;
data[1] = v1 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->chnum << 8) | 1, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
goto err;
if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2;
data[1] = v2 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
((ch->chnum + !!(ch->flags & MIXFLG_STEREOIN)) << 8) | (1 + !!(ch->flags & MIXFLG_STEREOOUT)),
ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
goto err;
return 0;
/* various feature unit controls */
case VOLUME_CONTROL:
data[0] = v1;
data[1] = v1 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
goto err;
if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2;
data[1] = v2 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
goto err;
return 0;
case BASS_CONTROL:
case MID_CONTROL:
case TREBLE_CONTROL:
data[0] = v1 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
goto err;
if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->selector << 8) | (ch->chnum + 1), ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
goto err;
return 0;
default:
return -1;
}
return 0;
err:
printk(KERN_ERR "usbaudio: mixer request device %u if %u unit %u ch %u selector %u failed\n",
dev->devnum, ms->iface, ch->unitid, ch->chnum, ch->selector);
return -1;
}
static int get_rec_src(struct usb_mixerdev *ms)
{
struct usb_device *dev = ms->state->usbdev;
unsigned int mask = 0, retmask = 0;
unsigned int i, j;
unsigned char buf;
int err = 0;
for (i = 0; i < ms->numch; i++) {
if (!ms->ch[i].slctunitid || (mask & (1 << i)))
continue;
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
err = -EIO;
printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n",
dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
continue;
}
for (j = i; j < ms->numch; j++) {
if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
continue;
mask |= 1 << j;
if (buf == (ms->ch[j].slctunitid >> 8))
retmask |= 1 << ms->ch[j].osschannel;
}
}
if (err)
return -EIO;
return retmask;
}
static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
{
struct usb_device *dev = ms->state->usbdev;
unsigned int mask = 0, smask, bmask;
unsigned int i, j;
unsigned char buf;
int err = 0;
for (i = 0; i < ms->numch; i++) {
if (!ms->ch[i].slctunitid || (mask & (1 << i)))
continue;
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
err = -EIO;
printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n",
dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
continue;
}
/* first generate smask */
smask = bmask = 0;
for (j = i; j < ms->numch; j++) {
if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
continue;
smask |= 1 << ms->ch[j].osschannel;
if (buf == (ms->ch[j].slctunitid >> 8))
bmask |= 1 << ms->ch[j].osschannel;
mask |= 1 << j;
}
/* check for multiple set sources */
j = hweight32(srcmask & smask);
if (j == 0)
continue;
if (j > 1)
srcmask &= ~bmask;
for (j = i; j < ms->numch; j++) {
if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
continue;
if (!(srcmask & (1 << ms->ch[j].osschannel)))
continue;
buf = ms->ch[j].slctunitid >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, HZ) < 0) {
err = -EIO;
printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n",
dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
continue;
}
}
}
return err ? -EIO : 0;
}
/* --------------------------------------------------------------------- */
/*
* should be called with open_sem hold, so that no new processes
* look at the audio device to be destroyed
*/
static void release(struct usb_audio_state *s)
{
struct usb_audiodev *as;
struct usb_mixerdev *ms;
s->count--;
if (s->count) {
up(&open_sem);
return;
}
up(&open_sem);
wake_up(&open_wait);
while (!list_empty(&s->audiolist)) {
as = list_entry(s->audiolist.next, struct usb_audiodev, list);
list_del(&as->list);
usbin_release(as);
usbout_release(as);
dmabuf_release(&as->usbin.dma);
dmabuf_release(&as->usbout.dma);
usb_free_urb(as->usbin.durb[0].urb);
usb_free_urb(as->usbin.durb[1].urb);
usb_free_urb(as->usbin.surb[0].urb);
usb_free_urb(as->usbin.surb[1].urb);
usb_free_urb(as->usbout.durb[0].urb);
usb_free_urb(as->usbout.durb[1].urb);
usb_free_urb(as->usbout.surb[0].urb);
usb_free_urb(as->usbout.surb[1].urb);
kfree(as);
}
while (!list_empty(&s->mixerlist)) {
ms = list_entry(s->mixerlist.next, struct usb_mixerdev, list);
list_del(&ms->list);
kfree(ms);
}
kfree(s);
}
static inline int prog_dmabuf_in(struct usb_audiodev *as)
{
usbin_stop(as);
return dmabuf_init(&as->usbin.dma);
}
static inline int prog_dmabuf_out(struct usb_audiodev *as)
{
usbout_stop(as);
return dmabuf_init(&as->usbout.dma);
}
/* --------------------------------------------------------------------- */
static int usb_audio_open_mixdev(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct usb_mixerdev *ms;
struct usb_audio_state *s;
down(&open_sem);
list_for_each_entry(s, &audiodevs, audiodev) {
list_for_each_entry(ms, &s->mixerlist, list) {
if (ms->dev_mixer == minor)
goto mixer_found;
}
}
up(&open_sem);
return -ENODEV;
mixer_found:
if (!s->usbdev) {
up(&open_sem);
return -EIO;
}
file->private_data = ms;
s->count++;
up(&open_sem);
return nonseekable_open(inode, file);
}
static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
{
struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
struct usb_audio_state *s;
lock_kernel();
s = ms->state;
down(&open_sem);
release(s);
unlock_kernel();
return 0;
}
static int usb_audio_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
int i, j, val;
int __user *user_arg = (int __user *)arg;
if (!ms->state->usbdev)
return -ENODEV;
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
memset(&info, 0, sizeof(info));
strncpy(info.id, "USB_AUDIO", sizeof(info.id));
strncpy(info.name, "USB Audio Class Driver", sizeof(info.name));
info.modify_counter = ms->modcnt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -