📄 audio.c
字号:
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); 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);}extern inline int prog_dmabuf_in(struct usb_audiodev *as){ usbin_stop(as); return dmabuf_init(&as->usbin.dma);}extern 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){ int minor = MINOR(inode->i_rdev); struct list_head *devs, *mdevs; struct usb_mixerdev *ms; struct usb_audio_state *s; down(&open_sem); for (devs = audiodevs.next; devs != &audiodevs; devs = devs->next) { s = list_entry(devs, struct usb_audio_state, audiodev); for (mdevs = s->mixerlist.next; mdevs != &s->mixerlist; mdevs = mdevs->next) { ms = list_entry(mdevs, struct usb_mixerdev, 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 0;}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; if (!ms->state->usbdev) return -ENODEV; if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "USB_AUDIO", sizeof(info.id)); strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); info.modify_counter = ms->modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; } if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; strncpy(info.id, "USB_AUDIO", sizeof(info.id)); strncpy(info.name, "USB Audio Class Driver", sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; } if (cmd == OSS_GETVERSION) return put_user(SOUND_VERSION, (int *)arg); if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) return -EINVAL; if (_IOC_DIR(cmd) == _IOC_READ) { switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ val = get_rec_src(ms); if (val < 0) return val; return put_user(val, (int *)arg); case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */ for (val = i = 0; i < ms->numch; i++) val |= 1 << ms->ch[i].osschannel; return put_user(val, (int *)arg); case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */ for (val = i = 0; i < ms->numch; i++) if (ms->ch[i].slctunitid) val |= 1 << ms->ch[i].osschannel; return put_user(val, (int *)arg); case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */ for (val = i = 0; i < ms->numch; i++) if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) val |= 1 << ms->ch[i].osschannel; return put_user(val, (int *)arg); case SOUND_MIXER_CAPS: return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); default: i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES) return -EINVAL; for (j = 0; j < ms->numch; j++) { if (ms->ch[j].osschannel == i) { return put_user(ms->ch[j].value, (int *)arg); } } return -EINVAL; } } if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) return -EINVAL; ms->modcnt++; switch (_IOC_NR(cmd)) { case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */ if (get_user(val, (int *)arg)) return -EFAULT; return set_rec_src(ms, val); default: i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES) return -EINVAL; for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++); if (j >= ms->numch) return -EINVAL; if (get_user(val, (int *)arg)) return -EFAULT; if (wrmixer(ms, j, val)) return -EIO; return put_user(ms->ch[j].value, (int *)arg); }}static /*const*/ struct file_operations usb_mixer_fops = { owner
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -