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

📄 trident.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
				if(!ret)					ret = -ENXIO;				goto out;			}			continue;		}		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {			if (!ret) ret = -EFAULT;			goto out;		}		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);	}out:	up(&state->sem);	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 trident_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){	struct trident_state *state = (struct trident_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	ssize_t ret;	unsigned long flags;	unsigned swptr;	int cnt;	unsigned int state_cnt;	unsigned int copy_count;#ifdef DEBUG	printk("trident: trident_write called, count = %d\n", count);#endif	VALIDATE_STATE(state);	if (ppos != &file->f_pos)		return -ESPIPE;		/*	 *	Guard against an mmap or ioctl while writing	 */		 	down(&state->sem);		if (dmabuf->mapped)	{		ret = -ENXIO;		goto out;	}	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))		goto out;	if (!access_ok(VERIFY_READ, buffer, count))	{		ret= -EFAULT;		goto out;	}		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;				goto out;			}			/* No matter how much data left in the buffer, we have to wait until			   CSO == ESO/2 or CSO == ESO when address engine interrupts */			lock_set_fmt(state);			tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);			tmo >>= sample_shift[dmabuf->fmt];			unlock_set_fmt(state);			up(&state->sem);						/* 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 "trident: 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 until next time the				   while loop begin and we REALLY have data to play */			}			if (signal_pending(current)) {				if (!ret) ret = -ERESTARTSYS;				goto out;			}			down(&state->sem);			if(dmabuf->mapped)			{				if(!ret)					ret = -ENXIO;				goto out;			}			continue;		}		lock_set_fmt(state);		if (state->chans_num == 6) {			copy_count = 0;			state_cnt = 0;			if (ali_write_5_1(state, buffer, cnt, &copy_count, &state_cnt) == -EFAULT) {				if (state_cnt){					swptr = (swptr + state_cnt) % dmabuf->dmasize;					spin_lock_irqsave(&state->card->lock, flags);					dmabuf->swptr = swptr;					dmabuf->count += state_cnt;					dmabuf->endcleared = 0;					spin_unlock_irqrestore(&state->card->lock, flags);				}				ret += copy_count;				if (!ret) ret = -EFAULT;				unlock_set_fmt(state);				goto out;			}		}		else {			if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {				if (!ret) ret = -EFAULT;				unlock_set_fmt(state);				goto out;			}			state_cnt = cnt;		}		unlock_set_fmt(state);				swptr = (swptr + state_cnt) % dmabuf->dmasize;						spin_lock_irqsave(&state->card->lock, flags);		dmabuf->swptr = swptr;		dmabuf->count += state_cnt;		dmabuf->endcleared = 0;		spin_unlock_irqrestore(&state->card->lock, flags);		count -= cnt;		buffer += cnt;			ret += cnt;		start_dac(state);	}out:	up(&state->sem);	return ret;}/* No kernel lock - we have our own spinlock */static unsigned int trident_poll(struct file *file, struct poll_table_struct *wait){	struct trident_state *state = (struct trident_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	unsigned int mask = 0;	VALIDATE_STATE(state);	/*	 *	Guard against a parallel poll and write causing multiple	 *	prog_dmabuf events	 */	 	down(&state->sem);	if (file->f_mode & FMODE_WRITE) {		if (!dmabuf->ready && prog_dmabuf(state, 0))		{			up(&state->sem);			return 0;		}		poll_wait(file, &dmabuf->wait, wait);	}	if (file->f_mode & FMODE_READ) {		if (!dmabuf->ready && prog_dmabuf(state, 1))		{			up(&state->sem);			return 0;		}		poll_wait(file, &dmabuf->wait, wait);	}	up(&state->sem);		spin_lock_irqsave(&state->card->lock, flags);	trident_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 trident_mmap(struct file *file, struct vm_area_struct *vma){	struct trident_state *state = (struct trident_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	int ret = -EINVAL;	unsigned long size;	VALIDATE_STATE(state);	lock_kernel();		/*	 *	Lock against poll read write or mmap creating buffers. Also lock	 *	a read or write against an mmap.	 */	 	down(&state->sem);		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:	up(&state->sem);	unlock_kernel();	return ret;}static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){	struct trident_state *state = (struct trident_state *)file->private_data;	struct dmabuf *dmabuf = &state->dmabuf;	unsigned long flags;	audio_buf_info abinfo;	count_info cinfo;	int val, mapped, ret = 0;	struct trident_card *card = state->card;	VALIDATE_STATE(state);	mapped = ((file->f_mode & FMODE_WRITE) && dmabuf->mapped) ||		((file->f_mode & FMODE_READ) && dmabuf->mapped);#ifdef DEBUG	printk("trident: trident_ioctl, command = %2d, arg = 0x%08x\n",	       _IOC_NR(cmd), arg ? *(int *)arg : 0);#endif	switch (cmd) 	{	case OSS_GETVERSION:		ret = put_user(SOUND_VERSION, (int *)arg);		break;			case SNDCTL_DSP_RESET:		/* FIXME: spin_lock ? */		if (file->f_mode & FMODE_WRITE) {			stop_dac(state);			synchronize_irq();			dmabuf->ready = 0;			dmabuf->swptr = dmabuf->hwptr = 0;			dmabuf->count = dmabuf->total_bytes = 0;		}		if (file->f_mode & FMODE_READ) {			stop_adc(state);			synchronize_irq();			dmabuf->ready = 0;			dmabuf->swptr = dmabuf->hwptr = 0;			dmabuf->count = dmabuf->total_bytes = 0;		}		break;	case SNDCTL_DSP_SYNC:		if (file->f_mode & FMODE_WRITE)			ret = drain_dac(state, file->f_flags & O_NONBLOCK);		break;	case SNDCTL_DSP_SPEED: /* set smaple rate */		if (get_user(val, (int *)arg))		{			ret = -EFAULT;			break;		}		if (val >= 0) {			if (file->f_mode & FMODE_WRITE) {				stop_dac(state);				dmabuf->ready = 0;				spin_lock_irqsave(&state->card->lock, flags);				trident_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);				trident_set_adc_rate(state, val);				spin_unlock_irqrestore(&state->card->lock, flags);			}		}		ret = put_user(dmabuf->rate, (int *)arg);		break;	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */		if (get_user(val, (int *)arg))		{			ret = -EFAULT;			break;		}		lock_set_fmt(state);		if (file->f_mode & FMODE_WRITE) {			stop_dac(state);			dmabuf->ready = 0;			if (val)				dmabuf->fmt |= TRIDENT_FMT_STEREO;			else				dmabuf->fmt &= ~TRIDENT_FMT_STEREO;		}		if (file->f_mode & FMODE_READ) {			stop_adc(state);			dmabuf->ready = 0;			if (val)				dmabuf->fmt |= TRIDENT_FMT_STEREO;			else				dmabuf->fmt &= ~TRIDENT_FMT_STEREO;		}		unlock_set_fmt(state);		break;	case SNDCTL_DSP_GETBLKSIZE:		if (file->f_mode & FMODE_WRITE) {			if ((val = prog_dmabuf(state, 0)))				ret = val;			else				ret = put_user(dmabuf->fragsize, (int *)arg);			break;		}		if (file->f_mode & FMODE_READ) {			if ((val = prog_dmabuf(state, 1)))				ret = val;			else				ret = put_user(dmabuf->fragsize, (int *)arg);			break;		}	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/		ret = put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);		break;	case SNDCTL_DSP_SETFMT: /* Select sample format */		if (get_user(val, (int *)arg))		{			ret = -EFAULT;			break;		}		lock_set_fmt(state);		if (val != AFMT_QUERY) {			if (file->f_mode & FMODE_WRITE) {				stop_dac(state);				dmabuf->ready = 0;				if (val == AFMT_S16_LE)					dmabuf->fmt |= TRIDENT_FMT_16BIT;				else					dmabuf->fmt &= ~TRIDENT_FMT_16BIT;			}			if (file->f_mode & FMODE_READ) {				stop_adc(state);				dmabuf->ready = 0;				if (val == AFMT_S16_LE)					dmabuf->fmt |= TRIDENT_FMT_16BIT;				else					dmabuf->fmt &= ~TRIDENT_FMT_16BIT;			}		}		unlock_set_fmt(state);		ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ?				AFMT_S16_LE : AFMT_U8, (int *)arg);		break;	case SNDCTL_DSP_CHANNELS:		if (get_user(val, (int *)arg))		{			ret = -EFAULT;			break;		}		if (val != 0) {			lock_set_fmt(state);			if (file->f_mode & FMODE_WRITE) {				stop_dac(state);				dmabuf->ready = 0;												//prevent from memory leak				if ((state->chans_num > 2) && (state->chans_num != val)) {					ali_free_other_states_resources(state);					state->chans_num =

⌨️ 快捷键说明

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