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

📄 esssolo1.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
		else if (l < 5)			l = 5;		r = (val >> 7) & 0x1fe;		if (r > 200)			r = 200;		else if (r < 5)			r = 5;		rl = (l - 5) / 13;		rr = (r - 5) / 13;		r = (rl * 13 + 5) / 2;		l = (rr * 13 + 5) / 2;		write_mixer(s, mixreg[vidx-1], (rl << 4) | rr);#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS                s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;#else                s->mix.vol[vidx-1] = val;#endif		return put_user(s->mix.vol[vidx-1], (int *)arg);	}}/* --------------------------------------------------------------------- */static int solo1_open_mixdev(struct inode *inode, struct file *file){	int minor = MINOR(inode->i_rdev);	struct solo1_state *s = NULL;	struct pci_dev *pci_dev;	pci_for_each_dev(pci_dev) {		struct pci_driver *drvr;		drvr = pci_dev_driver (pci_dev);		if (drvr != &solo1_driver)			continue;		s = (struct solo1_state*)pci_get_drvdata(pci_dev);		if (!s)			continue;		if (s->dev_mixer == minor)			break;	}	if (!s)		return -ENODEV;       	VALIDATE_STATE(s);	file->private_data = s;	return 0;}static int solo1_release_mixdev(struct inode *inode, struct file *file){	struct solo1_state *s = (struct solo1_state *)file->private_data;	VALIDATE_STATE(s);	return 0;}static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg);}static /*const*/ struct file_operations solo1_mixer_fops = {	owner:		THIS_MODULE,	llseek:		no_llseek,	ioctl:		solo1_ioctl_mixdev,	open:		solo1_open_mixdev,	release:	solo1_release_mixdev,};/* --------------------------------------------------------------------- */static int drain_dac(struct solo1_state *s, int nonblock){	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;	int count;	unsigned tmo;		if (s->dma_dac.mapped)		return 0;        add_wait_queue(&s->dma_dac.wait, &wait);        for (;;) {		set_current_state(TASK_INTERRUPTIBLE);                spin_lock_irqsave(&s->lock, flags);		count = s->dma_dac.count;                spin_unlock_irqrestore(&s->lock, flags);		if (count <= 0)			break;		if (signal_pending(current))                        break;                if (nonblock) {                        remove_wait_queue(&s->dma_dac.wait, &wait);                        set_current_state(TASK_RUNNING);                        return -EBUSY;                }		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;		if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))			tmo >>= 1;		if (s->channels > 1)			tmo >>= 1;                if (!schedule_timeout(tmo + 1))                        printk(KERN_DEBUG "solo1: dma timed out??\n");        }        remove_wait_queue(&s->dma_dac.wait, &wait);        set_current_state(TASK_RUNNING);        if (signal_pending(current))                return -ERESTARTSYS;        return 0;}/* --------------------------------------------------------------------- */static ssize_t solo1_read(struct file *file, char *buffer, size_t count, loff_t *ppos){	struct solo1_state *s = (struct solo1_state *)file->private_data;	DECLARE_WAITQUEUE(wait, current);	ssize_t ret;	unsigned long flags;	unsigned swptr;	int cnt;	VALIDATE_STATE(s);	if (ppos != &file->f_pos)		return -ESPIPE;	if (s->dma_adc.mapped)		return -ENXIO;	if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))		return ret;	if (!access_ok(VERIFY_WRITE, buffer, count))		return -EFAULT;	ret = 0;	add_wait_queue(&s->dma_adc.wait, &wait);	while (count > 0) {		spin_lock_irqsave(&s->lock, flags);		swptr = s->dma_adc.swptr;		cnt = s->dma_adc.dmasize-swptr;		if (s->dma_adc.count < cnt)			cnt = s->dma_adc.count;		if (cnt <= 0)			__set_current_state(TASK_INTERRUPTIBLE);		spin_unlock_irqrestore(&s->lock, flags);		if (cnt > count)			cnt = count;#ifdef DEBUGREC		printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  SBstat: 0x%02x  cnt: %u\n", 		       read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt);#endif		if (cnt <= 0) {			if (s->dma_adc.enabled)				start_adc(s);#ifdef DEBUGREC			printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"			       KERN_DEBUG "solo1_read: regs: B1: 0x%02x  B2: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n"			       KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"  			       KERN_DEBUG "solo1_read: SBstat: 0x%02x  cnt: %u\n",			       read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), 			       read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), 			       inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);#endif			if (inb(s->ddmabase+15) & 1)				printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");			if (file->f_flags & O_NONBLOCK) {				if (!ret)					ret = -EAGAIN;				break;			}			schedule();#ifdef DEBUGREC			printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"			       KERN_DEBUG "solo1_read: regs: B1: 0x%02x  B2: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n"			       KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"  			       KERN_DEBUG "solo1_read: SBstat: 0x%02x  cnt: %u\n",			       read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), 			       read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), 			       inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);#endif			if (signal_pending(current)) {				if (!ret)					ret = -ERESTARTSYS;				break;			}			continue;		}		if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {			if (!ret)				ret = -EFAULT;			break;		}		swptr = (swptr + cnt) % s->dma_adc.dmasize;		spin_lock_irqsave(&s->lock, flags);		s->dma_adc.swptr = swptr;		s->dma_adc.count -= cnt;		spin_unlock_irqrestore(&s->lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;		if (s->dma_adc.enabled)			start_adc(s);#ifdef DEBUGREC		printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  SBstat: 0x%02x\n", 		       read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));#endif	}	remove_wait_queue(&s->dma_adc.wait, &wait);	set_current_state(TASK_RUNNING);	return ret;}static ssize_t solo1_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){	struct solo1_state *s = (struct solo1_state *)file->private_data;	DECLARE_WAITQUEUE(wait, current);	ssize_t ret;	unsigned long flags;	unsigned swptr;	int cnt;	VALIDATE_STATE(s);	if (ppos != &file->f_pos)		return -ESPIPE;	if (s->dma_dac.mapped)		return -ENXIO;	if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))		return ret;	if (!access_ok(VERIFY_READ, buffer, count))		return -EFAULT;#if 0	printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x  71: 0x%02x  72: 0x%02x  74: 0x%02x  76: 0x%02x  78: 0x%02x  7A: 0x%02x\n"	       KERN_DEBUG "solo1_write: DMA: addr: 0x%08x  cnt: 0x%04x  stat: 0x%02x  SBstat: 0x%02x\n", 	       read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76),	       read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));	printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x  reg 7A: 0x%02x  DMAcnt: 0x%04x  DMAstat: 0x%02x  SBstat: 0x%02x\n", 	       read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));#endif	ret = 0;	add_wait_queue(&s->dma_dac.wait, &wait);		while (count > 0) {		spin_lock_irqsave(&s->lock, flags);		if (s->dma_dac.count < 0) {			s->dma_dac.count = 0;			s->dma_dac.swptr = s->dma_dac.hwptr;		}		swptr = s->dma_dac.swptr;		cnt = s->dma_dac.dmasize-swptr;		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)			cnt = s->dma_dac.dmasize - s->dma_dac.count;		if (cnt <= 0)			__set_current_state(TASK_INTERRUPTIBLE);		spin_unlock_irqrestore(&s->lock, flags);		if (cnt > count)			cnt = count;		if (cnt <= 0) {			if (s->dma_dac.enabled)				start_dac(s);			if (file->f_flags & O_NONBLOCK) {				if (!ret)					ret = -EAGAIN;				break;			}			schedule();			if (signal_pending(current)) {				if (!ret)					ret = -ERESTARTSYS;				break;			}			continue;		}		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {			if (!ret)				ret = -EFAULT;			break;		}		swptr = (swptr + cnt) % s->dma_dac.dmasize;		spin_lock_irqsave(&s->lock, flags);		s->dma_dac.swptr = swptr;		s->dma_dac.count += cnt;		s->dma_dac.endcleared = 0;		spin_unlock_irqrestore(&s->lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;		if (s->dma_dac.enabled)			start_dac(s);	}	remove_wait_queue(&s->dma_dac.wait, &wait);	set_current_state(TASK_RUNNING);	return ret;}/* No kernel lock - we have our own spinlock */static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait){	struct solo1_state *s = (struct solo1_state *)file->private_data;	unsigned long flags;	unsigned int mask = 0;	VALIDATE_STATE(s);	if (file->f_mode & FMODE_WRITE) {		if (!s->dma_dac.ready && prog_dmabuf_dac(s))			return 0;		poll_wait(file, &s->dma_dac.wait, wait);	}	if (file->f_mode & FMODE_READ) {		if (!s->dma_adc.ready && prog_dmabuf_adc(s))			return 0;		poll_wait(file, &s->dma_adc.wait, wait);	}	spin_lock_irqsave(&s->lock, flags);	solo1_update_ptr(s);	if (file->f_mode & FMODE_READ) {		if (s->dma_adc.mapped) {			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)				mask |= POLLIN | POLLRDNORM;		} else {			if (s->dma_adc.count > 0)				mask |= POLLIN | POLLRDNORM;		}	}	if (file->f_mode & FMODE_WRITE) {		if (s->dma_dac.mapped) {			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 				mask |= POLLOUT | POLLWRNORM;		} else {			if ((signed)s->dma_dac.dmasize > s->dma_dac.count)				mask |= POLLOUT | POLLWRNORM;		}	}	spin_unlock_irqrestore(&s->lock, flags);	return mask;}static int solo1_mmap(struct file *file, struct vm_area_struct *vma){	struct solo1_state *s = (struct solo1_state *)file->private_data;	struct dmabuf *db;	int ret = -EINVAL;	unsigned long size;	VALIDATE_STATE(s);	lock_kernel();	if (vma->vm_flags & VM_WRITE) {		if ((ret = prog_dmabuf_dac(s)) != 0)			goto out;		db = &s->dma_dac;	} else if (vma->vm_flags & VM_READ) {		if ((ret = prog_dmabuf_adc(s)) != 0)			goto out;		db = &s->dma_adc;	} else 		goto out;	ret = -EINVAL;	if (vma->vm_pgoff != 0)		goto out;	size = vma->vm_end - vma->vm_start;	if (size > (PAGE_SIZE << db->buforder))		goto out;	ret = -EAGAIN;	if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))		goto out;	db->mapped = 1;	ret = 0;out:	unlock_kernel();	return ret;}static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	struct solo1_state *s = (struct solo1_state *)file->private_data;	unsigned long flags;        audio_buf_info abinfo;        count_info cinfo;	int val, mapped, ret, count;        int div1, div2;        unsigned rate1, rate2;	VALIDATE_STATE(s);        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);	switch (cmd) {	case OSS_GETVERSION:		return put_user(SOUND_VERSION, (int *)arg);	case SNDCTL_DSP_SYNC:		if (file->f_mode & FMODE_WRITE)			return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);		return 0;			case SNDCTL_DSP_SETDUPLEX:		return 0;	case SNDCTL_DSP_GETCAPS:		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);		        case SNDCTL_DSP_RESET:		if (file->f_mode & FMODE_WRITE) {			stop_dac(s);			synchronize_irq();			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;		}		if (file->f_mode & FMODE_READ) {			stop_adc(s);			synchronize_irq();			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;		}		prog_codec(s);		return 0;        case SNDCTL_DSP_SPEED:                if (get_user(val, (int *)arg))			return -EFAULT;		if (val >= 0) {			stop_adc(s);			stop_dac(s);			s->dma_adc.ready = s->dma_dac.ready = 0;			/* program sampling rates */			if (val > 48000)				val = 48000;			if (val < 6300)				val = 6300;			div1 = (768000 + val / 2) / val;			rate1 = (768000 + div1 / 2) / div1;			div1 = -div1;			div2 = (793800 + val / 2) / val;			rate2 = (793800 + div2 / 2) / div2;			div2 = (-div2) & 0x7f;			if (abs(val - rate2) < abs(val - rate1)) {				rate1 = rate2;				div1 = div2;			}			s->rate = rate1;			s->clkdiv = div1;			prog_codec(s);		}		return put_user(s->rate, (int *)arg);		        case SNDCTL_DSP_STEREO:                if (get_user(val, (int *)arg))			return -EFAULT;		stop_adc(s);		stop_dac(s);		s->dma_adc.ready = s->dma_dac.ready = 0;		/* program channels */		s->channels = val ? 2 : 1;		prog_codec(s);

⌨️ 快捷键说明

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