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

📄 audio.c

📁 Usb1.1驱动c语言源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 loff_t usb_audio_llseek(struct file *file, loff_t offset, int origin){	return -ESPIPE;}/* --------------------------------------------------------------------- */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++;	MOD_INC_USE_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 = ms->state;	down(&open_sem);	release(s);	MOD_DEC_USE_COUNT;	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 */			/* don't know how to handle this yet */			return put_user(0, (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 */			/* don't know how to handle this yet */			return put_user(0, (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(0, (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 */		get_user_ret(val, (int *)arg, -EFAULT);		/* set recording source: val */		return 0;	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;		get_user_ret(val, (int *)arg, -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 = {	llseek:		usb_audio_llseek,	ioctl:		usb_audio_ioctl_mixdev,	open:		usb_audio_open_mixdev,	release:	usb_audio_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_out(struct usb_audiodev *as, int nonblock){	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;	int count, tmo;		if (as->usbout.dma.mapped || !as->usbout.dma.ready)		return 0;	add_wait_queue(&as->usbout.dma.wait, &wait);	for (;;) {		__set_current_state(TASK_INTERRUPTIBLE);		spin_lock_irqsave(&as->lock, flags);		count = as->usbout.dma.count;		spin_unlock_irqrestore(&as->lock, flags);		if (count <= 0)			break;		if (signal_pending(current))			break;		if (nonblock) {			remove_wait_queue(&as->usbout.dma.wait, &wait);			set_current_state(TASK_RUNNING);			return -EBUSY;		}		tmo = 3 * HZ * count / as->usbout.dma.srate;		tmo >>= AFMT_BYTESSHIFT(as->usbout.dma.format);		if (!schedule_timeout(tmo + 1)) {			printk(KERN_DEBUG "usbaudio: dma timed out??\n");			break;		}	}	remove_wait_queue(&as->usbout.dma.wait, &wait);	set_current_state(TASK_RUNNING);	if (signal_pending(current))		return -ERESTARTSYS;	return 0;}/* --------------------------------------------------------------------- */static ssize_t usb_audio_read(struct file *file, char *buffer, size_t count, loff_t *ppos){	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;	DECLARE_WAITQUEUE(wait, current);	ssize_t ret = 0;	unsigned long flags;	unsigned int ptr;	int cnt, err;	if (ppos != &file->f_pos)		return -ESPIPE;	if (as->usbin.dma.mapped)		return -ENXIO;	if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))		return ret;	if (!access_ok(VERIFY_WRITE, buffer, count))		return -EFAULT;	add_wait_queue(&as->usbin.dma.wait, &wait);	while (count > 0) {		spin_lock_irqsave(&as->lock, flags);		ptr = as->usbin.dma.rdptr;		cnt = as->usbin.dma.count;		/* set task state early to avoid wakeup races */		if (cnt <= 0)			__set_current_state(TASK_INTERRUPTIBLE);		spin_unlock_irqrestore(&as->lock, flags);		if (cnt > count)			cnt = count;		if (cnt <= 0) {			if (usbin_start(as)) {				if (!ret)					ret = -ENODEV;				break;			}			if (file->f_flags & O_NONBLOCK) {				if (!ret)					ret = -EAGAIN;				break;			}			schedule();			if (signal_pending(current)) {				if (!ret)					ret = -ERESTARTSYS;				break;			}			continue;		}		if ((err = dmabuf_copyout_user(&as->usbin.dma, ptr, buffer, cnt))) {			if (!ret)				ret = err;			break;		}		ptr += cnt;		if (ptr >= as->usbin.dma.dmasize)			ptr -= as->usbin.dma.dmasize;		spin_lock_irqsave(&as->lock, flags);		as->usbin.dma.rdptr = ptr;		as->usbin.dma.count -= cnt;		spin_unlock_irqrestore(&as->lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;	}	__set_current_state(TASK_RUNNING);	remove_wait_queue(&as->usbin.dma.wait, &wait);	return ret;}static ssize_t usb_audio_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;	DECLARE_WAITQUEUE(wait, current);	ssize_t ret = 0;	unsigned long flags;	unsigned int ptr;	int cnt, err;	if (ppos != &file->f_pos)		return -ESPIPE;	if (as->usbout.dma.mapped)		return -ENXIO;	if (!as->usbout.dma.ready && (ret = prog_dmabuf_out(as)))		return ret;	if (!access_ok(VERIFY_READ, buffer, count))		return -EFAULT;	add_wait_queue(&as->usbout.dma.wait, &wait);	while (count > 0) {#if 0		printk(KERN_DEBUG "usb_audio_write: count %u dma: count %u rdptr %u wrptr %u dmasize %u fragsize %u flags 0x%02x taskst 0x%x\n",		       count, as->usbout.dma.count, as->usbout.dma.rdptr, as->usbout.dma.wrptr, as->usbout.dma.dmasize, as->usbout.dma.fragsize,		       as->usbout.flags, current->state);#endif		spin_lock_irqsave(&as->lock, flags);		if (as->usbout.dma.count < 0) {			as->usbout.dma.count = 0;			as->usbout.dma.rdptr = as->usbout.dma.wrptr;		}		ptr = as->usbout.dma.wrptr;		cnt = as->usbout.dma.dmasize - as->usbout.dma.count;		/* set task state early to avoid wakeup races */		if (cnt <= 0)			__set_current_state(TASK_INTERRUPTIBLE);		spin_unlock_irqrestore(&as->lock, flags);		if (cnt > count)			cnt = count;		if (cnt <= 0) {			if (usbout_start(as)) {				if (!ret)					ret = -ENODEV;				break;			}			if (file->f_flags & O_NONBLOCK) {				if (!ret)					ret = -EAGAIN;				break;			}			schedule();			if (signal_pending(current)) {				if (!ret)					ret = -ERESTARTSYS;				break;			}			continue;		}		if ((err = dmabuf_copyin_user(&as->usbout.dma, ptr, buffer, cnt))) {			if (!ret)				ret = err;			break;		}		ptr += cnt;		if (ptr >= as->usbout.dma.dmasize)			ptr -= as->usbout.dma.dmasize;		spin_lock_irqsave(&as->lock, flags);		as->usbout.dma.wrptr = ptr;		as->usbout.dma.count += cnt;		spin_unlock_irqrestore(&as->lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;		if (usbout_start(as)) {			if (!ret)				ret = -ENODEV;			break;		}	}	__set_current_state(TASK_RUNNING);	remove_wait_queue(&as->usbout.dma.wait, &wait);	return ret;}static unsigned int usb_audio_poll(struct file *file, struct poll_table_struct *wait){	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;	unsigned long flags;	unsigned int mask = 0;	if (file->f_mode & FMODE_WRITE) {		if (!as->usbout.dma.ready)			prog_dmabuf_out(as);		poll_wait(file, &as->usbout.dma.wait, wait);	}	if (file->f_mode & FMODE_READ) {		if (!as->usbin.dma.ready)			prog_dmabuf_in(as);		poll_wait(file, &as->usbin.dma.wait, wait);	}	spin_lock_irqsave(&as->lock, flags);	if (file->f_mode & FMODE_READ) {		if (as->usbin.dma.count >= (signed)as->usbin.dma.fragsize)			mask |= POLLIN | POLLRDNORM;	}	if (file->f_mode & FMODE_WRITE) {		if (as->usbout.dma.mapped) {			if (as->usbout.dma.count >= (signed)as->usbout.dma.fragsize) 				mask |= POLLOUT | POLLWRNORM;		} else {			if ((signed)as->usbout.dma.dmasize >= as->usbout.dma.count + (signed)as->usbout.dma.fragsize)				mask |= POLLOUT | POLLWRNORM;		}	}	spin_unlock_irqrestore(&as->lock, flags);	return mask;}static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma){	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;	struct dmabuf *db;	int ret;	if (vma->vm_flags & VM_WRITE) {		if ((ret = prog_dmabuf_out(as)) != 0)			return ret;		db = &as->usbout.dma;	} else if (vma->vm_flags & VM_READ) {		if ((ret = prog_dmabuf_in(as)) != 0)			return ret;		db = &as->usbin.dma;	} else		return -EINVAL;#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,22)	if (vma->vm_pgoff != 0)		return -EINVAL;#endif	return dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);}static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;	struct usb_audio_state *s = as->state;	uns

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -