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

📄 i810_audio.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to   the user's buffer.  it is filled by the dma machine and drained by this loop. */static ssize_t i810_read(struct file *file, char *buffer, size_t count, loff_t *ppos){	struct i810_state *state = (struct i810_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	ssize_t ret;	unsigned long flags;	unsigned swptr;	int cnt;#ifdef DEBUG	printk("i810_audio: i810_read called, count = %d\n", count);#endif	if (ppos != &file->f_pos)		return -ESPIPE;	if (dmabuf->mapped)		return -ENXIO;	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))		return ret;	if (!access_ok(VERIFY_WRITE, buffer, count))		return -EFAULT;	ret = 0;	while (count > 0) {		spin_lock_irqsave(&state->card->lock, flags);		if (dmabuf->count > (signed) dmabuf->dmasize) {			/* buffer overrun, we are recovering from sleep_on_timeout,			   resync hwptr and swptr, make process flush the buffer */			dmabuf->count = dmabuf->dmasize;			dmabuf->swptr = dmabuf->hwptr;		}		swptr = dmabuf->swptr;		cnt = dmabuf->dmasize - swptr;		if (dmabuf->count < cnt)			cnt = dmabuf->count;		spin_unlock_irqrestore(&state->card->lock, flags);		if (cnt > count)			cnt = count;		if (cnt <= 0) {			unsigned long tmo;			/* buffer is empty, start the dma machine and wait for data to be			   recorded */			start_adc(state);			if (file->f_flags & O_NONBLOCK) {				if (!ret) ret = -EAGAIN;				return ret;			}			/* This isnt strictly right for the 810  but it'll do */			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);			tmo >>= sample_shift[dmabuf->fmt];			/* There are two situations when sleep_on_timeout returns, one is when			   the interrupt is serviced correctly and the process is waked up by			   ISR ON TIME. Another is when timeout is expired, which means that			   either interrupt is NOT serviced correctly (pending interrupt) or it			   is TOO LATE for the process to be scheduled to run (scheduler latency)			   which results in a (potential) buffer overrun. And worse, there is			   NOTHING we can do to prevent it. */			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {#ifdef DEBUG				printk(KERN_ERR "i810_audio: recording schedule timeout, "				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,				       dmabuf->hwptr, dmabuf->swptr);#endif				/* a buffer overrun, we delay the recovery untill next time the				   while loop begin and we REALLY have space to record */			}			if (signal_pending(current)) {				ret = ret ? ret : -ERESTARTSYS;				return ret;			}			continue;		}		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {			if (!ret) ret = -EFAULT;			return ret;		}		swptr = (swptr + cnt) % dmabuf->dmasize;		spin_lock_irqsave(&state->card->lock, flags);		dmabuf->swptr = swptr;		dmabuf->count -= cnt;		spin_unlock_irqrestore(&state->card->lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;		start_adc(state);	}	return ret;}/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to   the soundcard.  it is drained by the dma machine and filled by this loop. */static ssize_t i810_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){	struct i810_state *state = (struct i810_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	ssize_t ret;	unsigned long flags;	unsigned swptr;	int cnt;#ifdef DEBUG	printk("i810_audio: i810_write called, count = %d\n", count);#endif	if (ppos != &file->f_pos)		return -ESPIPE;	if (dmabuf->mapped)		return -ENXIO;	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))		return ret;	if (!access_ok(VERIFY_READ, buffer, count))		return -EFAULT;	ret = 0;	while (count > 0) {		spin_lock_irqsave(&state->card->lock, flags);		if (dmabuf->count < 0) {			/* buffer underrun, we are recovering from sleep_on_timeout,			   resync hwptr and swptr */			dmabuf->count = 0;			dmabuf->swptr = dmabuf->hwptr;		}		swptr = dmabuf->swptr;		cnt = dmabuf->dmasize - swptr;		if (dmabuf->count + cnt > dmabuf->dmasize)			cnt = dmabuf->dmasize - dmabuf->count;		spin_unlock_irqrestore(&state->card->lock, flags);		if (cnt > count)			cnt = count;		if (cnt <= 0) {			unsigned long tmo;			/* buffer is full, start the dma machine and wait for data to be			   played */			start_dac(state);			if (file->f_flags & O_NONBLOCK) {				if (!ret) ret = -EAGAIN;				return ret;			}			/* Not strictly correct but works */			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);			tmo >>= sample_shift[dmabuf->fmt];			/* There are two situations when sleep_on_timeout returns, one is when			   the interrupt is serviced correctly and the process is waked up by			   ISR ON TIME. Another is when timeout is expired, which means that			   either interrupt is NOT serviced correctly (pending interrupt) or it			   is TOO LATE for the process to be scheduled to run (scheduler latency)			   which results in a (potential) buffer underrun. And worse, there is			   NOTHING we can do to prevent it. */			if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {#ifdef DEBUG				printk(KERN_ERR "i810_audio: playback schedule timeout, "				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",				       dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,				       dmabuf->hwptr, dmabuf->swptr);#endif				/* a buffer underrun, we delay the recovery untill next time the				   while loop begin and we REALLY have data to play */			}			if (signal_pending(current)) {				if (!ret) ret = -ERESTARTSYS;				return ret;			}			continue;		}		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {			if (!ret) ret = -EFAULT;			return ret;		}		swptr = (swptr + cnt) % dmabuf->dmasize;		spin_lock_irqsave(&state->card->lock, flags);		dmabuf->swptr = swptr;		dmabuf->count += cnt;		dmabuf->endcleared = 0;		spin_unlock_irqrestore(&state->card->lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;		start_dac(state);	}	return ret;}/* No kernel lock - we have our own spinlock */static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait){	struct i810_state *state = (struct i810_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	unsigned int mask = 0;	if (file->f_mode & FMODE_WRITE) {		if (!dmabuf->ready && prog_dmabuf(state, 0))			return 0;		poll_wait(file, &dmabuf->wait, wait);	}	if (file->f_mode & FMODE_READ) {		if (!dmabuf->ready && prog_dmabuf(state, 1))			return 0;		poll_wait(file, &dmabuf->wait, wait);	}	spin_lock_irqsave(&state->card->lock, flags);	i810_update_ptr(state);	if (file->f_mode & FMODE_READ) {		if (dmabuf->count >= (signed)dmabuf->fragsize)			mask |= POLLIN | POLLRDNORM;	}	if (file->f_mode & FMODE_WRITE) {		if (dmabuf->mapped) {			if (dmabuf->count >= (signed)dmabuf->fragsize)				mask |= POLLOUT | POLLWRNORM;		} else {			if ((signed)dmabuf->dmasize >= dmabuf->count + (signed)dmabuf->fragsize)				mask |= POLLOUT | POLLWRNORM;		}	}	spin_unlock_irqrestore(&state->card->lock, flags);	return mask;}static int i810_mmap(struct file *file, struct vm_area_struct *vma){	struct i810_state *state = (struct i810_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	int ret = -EINVAL;	unsigned long size;	lock_kernel();	if (vma->vm_flags & VM_WRITE) {		if ((ret = prog_dmabuf(state, 0)) != 0)			goto out;	} else if (vma->vm_flags & VM_READ) {		if ((ret = prog_dmabuf(state, 1)) != 0)			goto out;	} else 		goto out;	ret = -EINVAL;	if (vma->vm_pgoff != 0)		goto out;	size = vma->vm_end - vma->vm_start;	if (size > (PAGE_SIZE << dmabuf->buforder))		goto out;	ret = -EAGAIN;	if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf),			     size, vma->vm_page_prot))		goto out;	dmabuf->mapped = 1;	ret = 0;out:	unlock_kernel();	return ret;}static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	struct i810_state *state = (struct i810_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	audio_buf_info abinfo;	count_info cinfo;	int val, mapped, ret;	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||		((file->f_mode & FMODE_READ) && dmabuf->mapped);#ifdef DEBUG	printk("i810_audio: i810_ioctl, command = %2d, arg = 0x%08x\n",	       _IOC_NR(cmd), arg ? *(int *)arg : 0);#endif	switch (cmd) 	{	case OSS_GETVERSION:		return put_user(SOUND_VERSION, (int *)arg);	case SNDCTL_DSP_RESET:		/* FIXME: spin_lock ? */		if (file->f_mode & FMODE_WRITE) {			stop_dac(state);			synchronize_irq();			dmabuf->ready = 0;			resync_dma_ptrs(state);			dmabuf->swptr = dmabuf->hwptr = 0;			dmabuf->count = dmabuf->total_bytes = 0;		}		if (file->f_mode & FMODE_READ) {			stop_adc(state);			synchronize_irq();			resync_dma_ptrs(state);			dmabuf->ready = 0;			dmabuf->swptr = dmabuf->hwptr = 0;			dmabuf->count = dmabuf->total_bytes = 0;		}		return 0;	case SNDCTL_DSP_SYNC:		if (file->f_mode & FMODE_WRITE)			return drain_dac(state, file->f_flags & O_NONBLOCK);		return 0;	case SNDCTL_DSP_SPEED: /* set smaple rate */		if (get_user(val, (int *)arg))			return -EFAULT;		if (val >= 0) {			if (file->f_mode & FMODE_WRITE) {				stop_dac(state);				dmabuf->ready = 0;				spin_lock_irqsave(&state->card->lock, flags);				i810_set_dac_rate(state, val);				spin_unlock_irqrestore(&state->card->lock, flags);			}			if (file->f_mode & FMODE_READ) {				stop_adc(state);				dmabuf->ready = 0;				spin_lock_irqsave(&state->card->lock, flags);				i810_set_adc_rate(state, val);				spin_unlock_irqrestore(&state->card->lock, flags);			}		}		return put_user(dmabuf->rate, (int *)arg);	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */		if (get_user(val, (int *)arg))			return -EFAULT;		if(val==0)			return -EINVAL;		if (file->f_mode & FMODE_WRITE) {			stop_dac(state);			dmabuf->ready = 0;			dmabuf->fmt = I810_FMT_STEREO;		}		if (file->f_mode & FMODE_READ) {			stop_adc(state);			dmabuf->ready = 0;			dmabuf->fmt = I810_FMT_STEREO;		}		return 0;	case SNDCTL_DSP_GETBLKSIZE:		if (file->f_mode & FMODE_WRITE) {			if ((val = prog_dmabuf(state, 0)))				return val;			return put_user(dmabuf->fragsize, (int *)arg);		}		if (file->f_mode & FMODE_READ) {			if ((val = prog_dmabuf(state, 1)))				return val;			return put_user(dmabuf->fragsize, (int *)arg);		}	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/		return put_user(AFMT_S16_LE, (int *)arg);	case SNDCTL_DSP_SETFMT: /* Select sample format */		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != AFMT_QUERY) {			if (file->f_mode & FMODE_WRITE) {				stop_dac(state);				dmabuf->ready = 0;			}			if (file->f_mode & FMODE_READ) {				stop_adc(state);				dmabuf->ready = 0;			}		}		return put_user(AFMT_S16_LE, (int *)arg);	case SNDCTL_DSP_CHANNELS:		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != 0) {			if (file->f_mode & FMODE_WRITE) {				stop_dac(state);				dmabuf->ready = 0;			}			if (file->f_mode & FMODE_READ) {				stop_adc(state);				dmabuf->ready = 0;			}		}		return put_user(2, (int *)arg);	case SNDCTL_DSP_POST:		/* FIXME: the same as RESET ?? */		return 0;	case SNDCTL_DSP_SUBDIVIDE:		if (dmabuf->subdivision)			return -EINVAL;		if (get_user(val, (int *)arg))			return -EFAULT;		if (val != 1 && val != 2 && val != 4)			return -EINVAL;		dmabuf->subdivision = val;		return 0;	case SNDCTL_DSP_SETFRAGMENT:		if (get_user(val, (int *)arg))			return -EFAULT;		dmabuf->ossfragshift = val & 0xffff;		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;		if (dmabuf->ossfragshift < 4)			dmabuf->ossfragshift = 4;		if (dmabuf->ossfragshift > 15)			dmabuf->ossfragshift = 15;		if (dmabuf->ossmaxfrags < 4)			dmabuf->ossmaxfrags = 4;		return 0;	case SNDCTL_DSP_GETOSPACE:		if (!(file->f_mode & FMODE_WRITE))			return -EINVAL;		if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		i810_update_ptr(state);		abinfo.fragsize = dmabuf->fragsize;		abinfo.bytes = dmabuf->dmasize - dmabuf->count;		abinfo.fragstotal = dmabuf->numfrag;		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;		spin_unlock_irqrestore(&state->card->lock, flags);		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_GETISPACE:		if (!(file->f_mode & FMODE_READ))			return -EINVAL;		if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0)			return val;		spin_lock_irqsave(&state->card->lock, flags);		i810_update_ptr(state);		abinfo.fragsize = dmabuf->fragsize;		abinfo.bytes = dmabuf->count;		abinfo.fragstotal = dmabuf->numfrag;		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;		spin_unlock_irqrestore(&state->card->lock, flags);		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;	case SNDCTL_DSP_NONBLOCK:		file->f_flags |= O_NONBLOCK;		return 0;	case SNDCTL_DSP_GETCAPS:	    return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND,			    (int *)arg);	case SNDCTL_DSP_GETTRIGGER:		val = 0;		if (file->f_mode & FMODE_READ && dmabuf->enable)			val |= PCM_ENABLE_INPUT;		if (file->f_mode & FMODE_WRITE && dmabuf->enable)			val |= PCM_ENABLE_OUTPUT;		return put_user(val, (int *)arg);	case SNDCTL_DSP_SETTRIGGER:		if (get_user(val, (int *)arg))			return -EFAULT;		if (file->f_mode & FMODE_READ) {			if (val & PCM_ENABLE_INPUT) {				if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))					return ret;				start_adc(state);			} else				stop_adc(state);		}		if (file->f_mode & FMODE_WRITE) {			if (val & PCM_ENABLE_OUTPUT) {				if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))					return ret;				start_dac(state);			} else				stop_dac(state);		}		return 0;	case SNDCTL_DSP_GETIPTR:		if (!(file->f_mode & FMODE_READ))

⌨️ 快捷键说明

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