swarm_cs4297a.c

来自「linux 内核源代码」· C语言 代码 · 共 1,971 行 · 第 1/5 页

C
1,971
字号
//   Mixer file operations struct.// ******************************************************************************************static /*const */ struct file_operations cs4297a_mixer_fops = {	.owner		= THIS_MODULE,	.llseek		= no_llseek,	.ioctl		= cs4297a_ioctl_mixdev,	.open		= cs4297a_open_mixdev,	.release	= cs4297a_release_mixdev,};// --------------------------------------------------------------------- static int drain_adc(struct cs4297a_state *s, int nonblock){        /* This routine serves no purpose currently - any samples           sitting in the receive queue will just be processed by the           background consumer.  This would be different if DMA           actually stopped when there were no clients. */	return 0;}static int drain_dac(struct cs4297a_state *s, int nonblock){	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;        unsigned hwptr;	unsigned tmo;	int count;	if (s->dma_dac.mapped)		return 0;        if (nonblock)                return -EBUSY;	add_wait_queue(&s->dma_dac.wait, &wait);        while ((count = __raw_readq(SS_CSR(R_SER_DMA_DSCR_COUNT_TX))) ||               (s->dma_dac.count > 0)) {                if (!signal_pending(current)) {                        set_current_state(TASK_INTERRUPTIBLE);                        /* XXXKW is this calculation working? */                        tmo = ((count * FRAME_TX_US) * HZ) / 1000000;                        schedule_timeout(tmo + 1);                } else {                        /* XXXKW do I care if there is a signal pending? */                }        }        spin_lock_irqsave(&s->lock, flags);        /* Reset the bookkeeping */        hwptr = (int)(((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) -                       s->dma_dac.descrtab_phys) / sizeof(serdma_descr_t));        s->dma_dac.hwptr = s->dma_dac.swptr = hwptr;        spin_unlock_irqrestore(&s->lock, flags);	remove_wait_queue(&s->dma_dac.wait, &wait);	current->state = TASK_RUNNING;	return 0;}// --------------------------------------------------------------------- static ssize_t cs4297a_read(struct file *file, char *buffer, size_t count,			   loff_t * ppos){	struct cs4297a_state *s =	    (struct cs4297a_state *) file->private_data;	ssize_t ret;	unsigned long flags;	int cnt, count_fr, cnt_by;	unsigned copied = 0;	CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,		  printk(KERN_INFO "cs4297a: cs4297a_read()+ %d \n", count));	VALIDATE_STATE(s);	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;//// "count" is the amount of bytes to read (from app), is decremented each loop//      by the amount of bytes that have been returned to the user buffer.// "cnt" is the running total of each read from the buffer (changes each loop)// "buffer" points to the app's buffer// "ret" keeps a running total of the amount of bytes that have been copied//      to the user buffer.// "copied" is the total bytes copied into the user buffer for each loop.//	while (count > 0) {		CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO			"_read() count>0 count=%d .count=%d .swptr=%d .hwptr=%d \n",				count, s->dma_adc.count,				s->dma_adc.swptr, s->dma_adc.hwptr));		spin_lock_irqsave(&s->lock, flags);                /* cnt will be the number of available samples (16-bit                   stereo); it starts out as the maxmimum consequetive                   samples */		cnt = (s->dma_adc.sb_end - s->dma_adc.sb_swptr) / 2;                count_fr = s->dma_adc.count / FRAME_SAMPLE_BYTES;		// dma_adc.count is the current total bytes that have not been read.		// if the amount of unread bytes from the current sw pointer to the		// end of the buffer is greater than the current total bytes that		// have not been read, then set the "cnt" (unread bytes) to the		// amount of unread bytes.  		if (count_fr < cnt)			cnt = count_fr;                cnt_by = cnt * FRAME_SAMPLE_BYTES;		spin_unlock_irqrestore(&s->lock, flags);		//		// if we are converting from 8/16 then we need to copy		// twice the number of 16 bit bytes then 8 bit bytes.		// 		if (s->conversion) {			if (cnt_by > (count * 2)) {				cnt = (count * 2) / FRAME_SAMPLE_BYTES;                                cnt_by = count * 2;                        }		} else {			if (cnt_by > count) {				cnt = count / FRAME_SAMPLE_BYTES;                                cnt_by = count;                        }		}		//		// "cnt" NOW is the smaller of the amount that will be read,		// and the amount that is requested in this read (or partial).		// if there are no bytes in the buffer to read, then start the		// ADC and wait for the interrupt handler to wake us up.		//		if (cnt <= 0) {			// start up the dma engine and then continue back to the top of			// the loop when wake up occurs.			start_adc(s);			if (file->f_flags & O_NONBLOCK)				return ret ? ret : -EAGAIN;			interruptible_sleep_on(&s->dma_adc.wait);			if (signal_pending(current))				return ret ? ret : -ERESTARTSYS;			continue;		}		// there are bytes in the buffer to read.		// copy from the hw buffer over to the user buffer.		// user buffer is designated by "buffer"		// virtual address to copy from is dma_buf+swptr		// the "cnt" is the number of bytes to read.		CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO			"_read() copy_to cnt=%d count=%d ", cnt_by, count));		CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO			 " .sbufsz=%d .count=%d buffer=0x%.8x ret=%d\n",				 s->dma_adc.sbufsz, s->dma_adc.count,				 (unsigned) buffer, ret));		if (copy_to_user (buffer, ((void *)s->dma_adc.sb_swptr), cnt_by))			return ret ? ret : -EFAULT;                copied = cnt_by;                /* Return the descriptors */		spin_lock_irqsave(&s->lock, flags);                CS_DBGOUT(CS_FUNCTION, 2,                           printk(KERN_INFO "cs4297a: upd_rcv sw->hw %x/%x\n", s->dma_adc.swptr, s->dma_adc.hwptr));		s->dma_adc.count -= cnt_by;                s->dma_adc.sb_swptr += cnt * 2;                if (s->dma_adc.sb_swptr == s->dma_adc.sb_end)                        s->dma_adc.sb_swptr = s->dma_adc.sample_buf;		spin_unlock_irqrestore(&s->lock, flags);		count -= copied;		buffer += copied;		ret += copied;		start_adc(s);	}	CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,		  printk(KERN_INFO "cs4297a: cs4297a_read()- %d\n", ret));	return ret;}static ssize_t cs4297a_write(struct file *file, const char *buffer,			    size_t count, loff_t * ppos){	struct cs4297a_state *s =	    (struct cs4297a_state *) file->private_data;	ssize_t ret;	unsigned long flags;	unsigned swptr, hwptr;	int cnt;	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,		  printk(KERN_INFO "cs4297a: cs4297a_write()+ count=%d\n",			 count));	VALIDATE_STATE(s);	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;	ret = 0;	while (count > 0) {                serdma_t *d = &s->dma_dac;                int copy_cnt;                u32 *s_tmpl;                u32 *t_tmpl;                u32 left, right;                int swap = (s->prop_dac.fmt == AFMT_S16_LE) || (s->prop_dac.fmt == AFMT_U16_LE);                                /* XXXXXX this is broken for BLOAT_FACTOR */		spin_lock_irqsave(&s->lock, flags);		if (d->count < 0) {			d->count = 0;			d->swptr = d->hwptr;		}		if (d->underrun) {			d->underrun = 0;                        hwptr = (unsigned) (((__raw_readq(SS_CSR(R_SER_DMA_CUR_DSCR_ADDR_TX)) & M_DMA_CURDSCR_ADDR) -                                             d->descrtab_phys) / sizeof(serdma_descr_t));			d->swptr = d->hwptr = hwptr;		}		swptr = d->swptr;		cnt = d->sbufsz - (swptr * FRAME_SAMPLE_BYTES);                /* Will this write fill up the buffer? */		if (d->count + cnt > d->sbufsz)			cnt = d->sbufsz - d->count;		spin_unlock_irqrestore(&s->lock, flags);		if (cnt > count)			cnt = count;		if (cnt <= 0) {			start_dac(s);			if (file->f_flags & O_NONBLOCK)				return ret ? ret : -EAGAIN;			interruptible_sleep_on(&d->wait);			if (signal_pending(current))				return ret ? ret : -ERESTARTSYS;			continue;		}		if (copy_from_user(d->sample_buf, buffer, cnt))			return ret ? ret : -EFAULT;                copy_cnt = cnt;                s_tmpl = (u32 *)d->sample_buf;                t_tmpl = (u32 *)(d->dma_buf + (swptr * 4));                /* XXXKW assuming 16-bit stereo! */                do {			u32 tmp;			t_tmpl[0] = cpu_to_be32(0x98000000);			tmp = be32_to_cpu(s_tmpl[0]);			left = tmp & 0xffff;			right = tmp >> 16;			if (swap) {				left = swab16(left);				right = swab16(right);			}			t_tmpl[1] = cpu_to_be32(left >> 8);			t_tmpl[2] = cpu_to_be32(((left & 0xff) << 24) |						(right << 4));                        s_tmpl++;                        t_tmpl += 8;                        copy_cnt -= 4;                } while (copy_cnt);                /* Mux in any pending read/write accesses */                if (s->reg_request) {			*(u64 *)(d->dma_buf + (swptr * 4)) |=				cpu_to_be64(s->reg_request);                        s->reg_request = 0;                        wake_up(&s->dma_dac.reg_wait);                }                CS_DBGOUT(CS_WAVE_WRITE, 4,                          printk(KERN_INFO                                 "cs4297a: copy in %d to swptr %x\n", cnt, swptr));		swptr = (swptr + (cnt/FRAME_SAMPLE_BYTES)) % d->ringsz;                __raw_writeq(cnt/FRAME_SAMPLE_BYTES, SS_CSR(R_SER_DMA_DSCR_COUNT_TX));		spin_lock_irqsave(&s->lock, flags);		d->swptr = swptr;		d->count += cnt;		d->endcleared = 0;		spin_unlock_irqrestore(&s->lock, flags);		count -= cnt;		buffer += cnt;		ret += cnt;		start_dac(s);	}	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,		  printk(KERN_INFO "cs4297a: cs4297a_write()- %d\n", ret));	return ret;}static unsigned int cs4297a_poll(struct file *file,				struct poll_table_struct *wait){	struct cs4297a_state *s =	    (struct cs4297a_state *) file->private_data;	unsigned long flags;	unsigned int mask = 0;	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,		  printk(KERN_INFO "cs4297a: cs4297a_poll()+\n"));	VALIDATE_STATE(s);	if (file->f_mode & FMODE_WRITE) {		CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,			  printk(KERN_INFO				 "cs4297a: cs4297a_poll() wait on FMODE_WRITE\n"));		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) {		CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,			  printk(KERN_INFO				 "cs4297a: cs4297a_poll() wait on FMODE_READ\n"));		if(!s->dma_dac.ready && prog_dmabuf_adc(s))			return 0;		poll_wait(file, &s->dma_adc.wait, wait);	}	spin_lock_irqsave(&s->lock, flags);	cs4297a_update_ptr(s,CS_FALSE);	if (file->f_mode & FMODE_WRITE) {		if (s->dma_dac.mapped) {			if (s->dma_dac.count >=			    (signed) s->dma_dac.fragsize) {				if (s->dma_dac.wakeup)					mask |= POLLOUT | POLLWRNORM;				else					mask = 0;				s->dma_dac.wakeup = 0;			}		} else {			if ((signed) (s->dma_dac.sbufsz/2) >= s->dma_dac.count)				mask |= POLLOUT | POLLWRNORM;		}	} else 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;		}	}	spin_unlock_irqrestore(&s->lock, flags);	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,		  printk(KERN_INFO "cs4297a: cs4297a_poll()- 0x%.8x\n",			 mask));	return mask;}static int cs4297a_mmap(struct file *file, struct vm_area_struct *vma){        /* XXXKW currently no mmap support */        return -EINVAL;	return 0;}static int cs4297a_ioctl(struct inode *inode, struct file *file,			unsigned int cmd, unsigned long arg){	struct cs4297a_state *s =	    (struct cs4297a_state *) file->private_data;	unsigned long flags;	audio_buf_info abinfo;	count_info cinfo;	int val, mapped, ret;	CS_DBGOUT(CS_FUNCTION|CS_IOCTL, 4, printk(KERN_INFO		 "cs4297a: cs4297a_ioctl(): file=0x%.8x cmd=0x%.8x\n",			 (unsigned) file, cmd));#if CSDEBUG	cs_printioctl(cmd);#endif	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:		CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(

⌨️ 快捷键说明

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