⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audio.c

📁 USB Audio Class Driver
💻 C
📖 第 1 页 / 共 5 页
字号:
		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 + -