task.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,381 行 · 第 1/4 页

C
2,381
字号
			schedule();		set_current_state(current_state);		remove_wait_queue(&task->read_wait_q, &wait);		/* signal or 0-byte send from DSP */		if (ipblink_empty(&rcvdt->link))			goto up_out;	}	/* data protection while copying */	disable_irq(INT_D2A_MB1);	/* copy from delayed IPBUF */	if (sndtyp_pvt(task->ttyp)) {		/* private */		if (!ipblink_empty(&rcvdt->link)) {			struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r;			unsigned long dspadr = MKLONG(ipbp->ah, ipbp->al);			unsigned char *src;			size_t bkcnt;			if ((dspmem_access = is_dspword_internal_mem(dspadr)) != 0)				omap_dsp_enable_dspmem();			src = dspword_to_virt(dspadr) + rcvdt->rp;			bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;			if (bkcnt > count) {				if (copy_to_user_dsp(buf, src, count)) {					ret = -EFAULT;					goto copy_done_pvt;				}				ret = count;				rcvdt->rp += count;			} else {				if (copy_to_user_dsp(buf, src, bkcnt)) {					ret = -EFAULT;					goto copy_done_pvt;				}				ret = bkcnt;				ipblink_del_pvt(&rcvdt->link);				release_ipbuf_pvt(ipbp);				rcvdt->rp = 0;			}copy_done_pvt:			if (dspmem_access)				omap_dsp_disable_dspmem();		}	} else {		/* global */		if ((dspmem_access = is_ipbuf_internal_mem()) != 0)			omap_dsp_enable_dspmem();		while (!ipblink_empty(&rcvdt->link)) {			unsigned char *src;			size_t bkcnt;			unsigned short bid = rcvdt->link.top;			struct ipbuf *ipbp = ipbuf[bid];			src = ipbp->d + rcvdt->rp;			bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;			if (bkcnt > count) {				if (copy_to_user_dsp(buf, src, count)) {					ret = -EFAULT;					goto copy_done_gbl;				}				ret += count;				rcvdt->rp += count;				break;			} else {				if (copy_to_user_dsp(buf, src, bkcnt)) {					ret = -EFAULT;					goto copy_done_gbl;				}				ret += bkcnt;				buf += bkcnt;				count -= bkcnt;				ipblink_del_top(&rcvdt->link, ipbuf);				unuse_ipbuf(bid, MBSENDTYPE_NORMAL);				rcvdt->rp = 0;			}		}copy_done_gbl:		if (dspmem_access)			omap_dsp_disable_dspmem();	}	enable_irq(INT_D2A_MB1);up_out:#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	up(&task->read_sem);#endif	return ret;}static ssize_t omap_dsp_task_read_wd_psv(struct file *file, char *buf,					 size_t count, loff_t *ppos){	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);	struct dsptask *task = taskdev[minor]->task;	struct fifo_struct *fifo = &task->rcvdt.fifo;#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	int sem_st;#endif	int ret = 0;	if (count == 0) {		return 0;	} else if (count == 1) {		printk(KERN_ERR		       "omapdsp: count == 1 is illegal "		       "for omap_dsp_task_read().\n");		return -EINVAL;	} else {		/* force! */		count = 2;	}#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	if ((sem_st = down_tasksem_interruptible(task, &task->read_sem)) < 0)		return sem_st;#endif	omap_dsp_mbsend_and_wait(MBCMD(WDREQ), task->tid, 0,				 &task->read_wait_q);	if (fifo_empty(fifo))		goto up_out;	ret = copy_to_user_fm_fifo(buf, fifo, count);up_out:#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	up(&task->read_sem);#endif	return ret;}static ssize_t omap_dsp_task_read_bk_psv(struct file *file, char *buf,					 size_t count, loff_t *ppos){	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);	struct dsptask *task = taskdev[minor]->task;	struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk;	int dspmem_access;#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	int sem_st;#endif	int ret = 0;	if (count == 0) {		return 0;	} else if (count == 1) {		printk(KERN_ERR		       "omapdsp: count == 1 is illegal "		       "for omap_dsp_task_read().\n");		return -EINVAL;	} else if ((int)buf & 0x1) {		printk(KERN_ERR		       "omapdsp: buf should be word aligned "		       "for omap_dsp_task_read().\n");		return -EINVAL;	} else if (count & 0x1) {		/* force even value */		count--;	}#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	if ((sem_st = down_tasksem_interruptible(task, &task->read_sem)) < 0)		return sem_st;#endif	omap_dsp_mbsend_and_wait(MBCMD(BKREQ), task->tid, count/2,				 &task->read_wait_q);	/* signal or 0-byte send from DSP */	if (ipblink_empty(&rcvdt->link))		goto up_out;	/*	 * We will not receive more than requested count.	 */	if (sndtyp_pvt(task->ttyp)) {		/* private */		struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r;		size_t rcvcnt = ((unsigned long)ipbp->c) * 2;		unsigned long dspadr = MKLONG(ipbp->ah, ipbp->al);		void *src;		if (count > rcvcnt)			count = rcvcnt;		if ((dspmem_access = is_dspword_internal_mem(dspadr)) != 0)			omap_dsp_enable_dspmem();		src = dspword_to_virt(dspadr);		if (copy_to_user_dsp(buf, src, count)) {			ret = -EFAULT;			goto copy_done_pvt;		}		ipblink_del_pvt(&rcvdt->link);		release_ipbuf_pvt(ipbp);		ret = count;copy_done_pvt:		if (dspmem_access)			omap_dsp_disable_dspmem();	} else {		/* global */		unsigned short bid = rcvdt->link.top;		struct ipbuf *ipbp = ipbuf[bid];		size_t rcvcnt = ((unsigned long)ipbp->c) * 2;		if ((dspmem_access = is_ipbuf_internal_mem()) != 0)			omap_dsp_enable_dspmem();		if (count > rcvcnt)			count = rcvcnt;		if (copy_to_user_dsp(buf, ipbp->d, count)) {			ret = -EFAULT;			goto copy_done_gbl;		}		ipblink_del_top(&rcvdt->link, ipbuf);		unuse_ipbuf(bid, MBSENDTYPE_NORMAL);		ret = count;copy_done_gbl:		if (dspmem_access)			omap_dsp_disable_dspmem();	}up_out:#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	up(&task->read_sem);#endif	return count;}static ssize_t omap_dsp_task_write_wd(struct file *file, const char *buf,				      size_t count, loff_t *ppos){	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);	struct dsptask *task = taskdev[minor]->task;	unsigned short wd;#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	int sem_st;#endif	int ret = 0;	if (count == 0) {		return 0;	} else if (count & 0x1) {		printk(KERN_ERR		       "omapdsp: odd count is illegal "		       "for omap_dsp_task_write().\n");		return -EINVAL;	} else {		/* force! */		count = 2;	}#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	if ((sem_st = down_tasksem_interruptible(task, &task->write_sem)) < 0)		return sem_st;#endif	if (task->wsz == 0) {		long current_state;		DECLARE_WAITQUEUE(wait, current);		add_wait_queue(&task->write_wait_q, &wait);		current_state = current->state;		set_current_state(TASK_INTERRUPTIBLE);		if (task->wsz == 0)	/* last check */			schedule();		set_current_state(current_state);		remove_wait_queue(&task->write_wait_q, &wait);		/* signal or 0-byte send from DSP */		if (task->wsz == 0)			goto up_out;	}	if (copy_from_user(&wd, buf, count)) {		ret = -EFAULT;		goto up_out;	}	/* wsz protection */	disable_irq(INT_D2A_MB1);	if (omap_dsp_mbsend(MBCMD(WDSND), task->tid, wd) < 0)		goto enirq_up_out;	ret = count;	if (rcvtyp_acv(task->ttyp))		task->wsz = 0;enirq_up_out:	enable_irq(INT_D2A_MB1);up_out:#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	up(&task->write_sem);#endif	return ret;}static ssize_t omap_dsp_task_write_bk(struct file *file, const char *buf,				      size_t count, loff_t *ppos){	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);	struct dsptask *task = taskdev[minor]->task;	unsigned char tid = task->tid;	int dspmem_access;#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	int sem_st;#endif	int ret = 0;	if (count == 0) {		return 0;	} else if ((int)buf & 0x1) {		printk(KERN_ERR		       "omapdsp: buf should be word aligned "		       "for omap_dsp_task_write().\n");		return -EINVAL;	} else if (count & 0x1) {		printk(KERN_ERR		       "omapdsp: odd count is illegal "		       "for omap_dsp_task_write().\n");		return -EINVAL;	}#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	if ((sem_st = down_tasksem_interruptible(task, &task->write_sem)) < 0)		return sem_st;#endif	if (task->wsz == 0) {		long current_state;		DECLARE_WAITQUEUE(wait, current);		add_wait_queue(&task->write_wait_q, &wait);		current_state = current->state;		set_current_state(TASK_INTERRUPTIBLE);		if (task->wsz == 0)	/* last check */			schedule();		set_current_state(current_state);		remove_wait_queue(&task->write_wait_q, &wait);		/* interrupted by signal */		if (task->wsz == 0)			goto up_out;	}	/* wsz protection */	disable_irq(INT_D2A_MB1);	if (count > task->wsz)		count = task->wsz;	if (rcvtyp_pvt(task->ttyp)) {		/* private */		struct ipbuf_p *ipbp = task->ipbuf_pvt_w;		unsigned long dspadr = MKLONG(ipbp->ah, ipbp->al);		unsigned char *dst;		if (ipbp->s != OMAP_DSP_TID_FREE)			goto enirq_up_out;		if ((dspmem_access = is_dspword_internal_mem(dspadr)) != 0)			omap_dsp_enable_dspmem();		dst = dspword_to_virt(dspadr);		if (copy_from_user_dsp(dst, buf, count)) {			ret = -EFAULT;			if (dspmem_access)				omap_dsp_disable_dspmem();			goto enirq_up_out;		}		ipbp->c = count/2;		ipbp->s = tid;		if (dspmem_access)			omap_dsp_disable_dspmem();		if (omap_dsp_mbsend(MBCMD(BKSNDP), tid, 0) < 0)			goto enirq_up_out;	} else {		/* global */		unsigned short bid;		if ((dspmem_access = is_ipbuf_internal_mem()) != 0)			omap_dsp_enable_dspmem();		bid = get_free_ipbuf(tid);		if (bid == OMAP_DSP_BID_NULL)			goto enirq_up_out;		if (copy_from_user_dsp(ipbuf[bid]->d, buf, count)) {			release_ipbuf(bid);			ret = -EFAULT;			if (dspmem_access)				omap_dsp_disable_dspmem();			goto enirq_up_out;		}		ipbuf[bid]->c  = count/2;		ipbuf[bid]->sa = tid;		if (dspmem_access)			omap_dsp_disable_dspmem();		if (omap_dsp_mbsend(MBCMD(BKSND), tid, bid) < 0) {			release_ipbuf(bid);			goto enirq_up_out;		}		ipb_bsycnt_inc(&ipbcfg);	}	ret = count;	if (rcvtyp_acv(task->ttyp))		task->wsz = 0;enirq_up_out:	enable_irq(INT_D2A_MB1);up_out:#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	up(&task->write_sem);#endif	return ret;}static unsigned int omap_dsp_task_poll(struct file * file, poll_table * wait){	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);	struct dsptask *task = taskdev[minor]->task;	unsigned int mask = 0;	poll_wait(file, &task->read_wait_q, wait);	poll_wait(file, &task->write_wait_q, wait);	if (sndtyp_psv(task->ttyp) ||	    (sndtyp_wd(task->ttyp) && !fifo_empty(&task->rcvdt.fifo)) ||	    (sndtyp_bk(task->ttyp) && !ipblink_empty(&task->rcvdt.bk.link)))		mask |= POLLIN | POLLRDNORM;	if (task->wsz)		mask |= POLLOUT | POLLWRNORM;	return mask;}static int omap_dsp_task_ioctl(struct inode *inode, struct file *file,			       unsigned int cmd, unsigned long arg){	unsigned int minor = MINOR(inode->i_rdev);	struct taskdev *dev = taskdev[minor];	struct dsptask *task = dev->task;	unsigned char tid = task->tid;	unsigned short mbarg[1];	int argc, interactive;#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	int sem_st;#endif	int ret;	/* LOCK / UNLOCK operations */	switch (cmd) {	case OMAP_DSP_TASK_IOCTL_LOCK:		return omap_dsp_task_lock(task);	case OMAP_DSP_TASK_IOCTL_UNLOCK:		return omap_dsp_task_unlock(task);	}#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	/*	 * actually only interractive commands need to lock	 * the semaphore, but here all commands do it for simplicity.	 */	if ((sem_st = down_tasksem_interruptible(task, &task->ioctl_sem)) < 0)		return sem_st;#endif	if ((cmd >= 0x0080) && (cmd < 0x0100)) {		/*		 * 0x0080 - 0x00ff		 * reserved for backward compatibility		 * user-defined TCTL commands: no arg, non-interactive		 */		argc = 0;		interactive = 0;	} else if (cmd < 0x8000) {		/*		 * 0x0000 - 0x7fff (except 0x0080 - 0x00ff)		 * system reserved TCTL commands		 */		switch (cmd) {		case OMAP_DSP_MBCMD_TCTL_TEN:		case OMAP_DSP_MBCMD_TCTL_TDIS:			argc = 0;			interactive = 0;			break;		default:			ret = -ENOIOCTLCMD;			goto up_out;		}	}	/*	 * 0x8000 - 0xffff	 * user-defined TCTL commands	 */	else if (cmd < 0x8100) {		/* 0x8000-0x80ff: no arg, non-interactive */		argc = 0;		interactive = 0;	} else if (cmd < 0x8200) {		/* 0x8100-0x81ff: 1 arg, non-interactive */		argc = 1;		mbarg[0] = arg & 0xffff;		interactive = 0;	} else if (cmd < 0x9000) {		/* 0x8200-0x8fff: reserved */		ret = -ENOIOCTLCMD;		goto up_out;	} else if (cmd < 0x9100) {		/* 0x9000-0x90ff: no arg, interactive */		argc = 0;		interactive = 1;	} else if (cmd < 0x9200) {		/* 0x9100-0x91ff: 1 arg, interactive */		argc = 1;		mbarg[0] = arg & 0xffff;		interactive = 1;	} else if (cmd < 0x10000) {		/* 0x9200-0xffff: reserved */		ret =  -ENOIOCTLCMD;		goto up_out;	} else {		/*		 * 0x10000 -		 * non TCTL ioctls		 */		switch (cmd) {		case OMAP_DSP_TASK_IOCTL_BFLSH:			ret = omap_dsp_task_flush_buf(task);			break;		case OMAP_DSP_TASK_IOCTL_SETBSZ:			ret = omap_dsp_task_set_fifosz(task, arg);			break;		case OMAP_DSP_TASK_IOCTL_GETNAME:			ret = 0;			if (copy_to_user((void *)arg, dev->name,					 strlen(dev->name) + 1))				ret = -EFAULT;			break;		default:			ret = -ENOIOCTLCMD;		}		goto up_out;	}	/*	 * issue TCTL	 */	if (interactive) {		task->tctl_stat = -EBUSY;		omap_dsp_mbsend_and_wait_exarg(MBCMD(TCTL), tid, cmd,					       tid, argc, mbarg,					       &task->ioctl_wait_q);		ret = task->tctl_stat;		if (ret < 0) {			printk(KERN_ERR "omapdsp: TCTL not responding.\n");			goto up_out;		}	} else {		omap_dsp_mbsend_exarg(MBCMD(TCTL), tid, cmd, tid, argc, mbarg);		ret = 0;	}up_out:#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	up(&task->ioctl_sem);#endif	return ret;}static void omap_dsp_task_vma_open(struct vm_area_struct *vma){}static void omap_dsp_task_vma_close(struct vm_area_struct *vma){}/** * On demand page allocation is not allowed. The mapping area is defined by  * corresponding DSP tasks. */static struct page *omap_dsp_task_nopage_mmap(struct vm_area_struct *vma,					      unsigned long address, int *type){	return NOPAGE_SIGBUS;}static struct vm_operations_struct omap_dsp_task_vm_ops = {	.open   = omap_dsp_task_vma_open,	.close  = omap_dsp_task_vma_close,	.nopage = omap_dsp_task_nopage_mmap,};static int omap_dsp_task_mmap(struct file *filp, struct vm_area_struct *vma){	void *tmp_vadr;	unsigned long tmp_padr, tmp_vmadr, off;	size_t req_len, tmp_len;	unsigned int minor = MINOR(filp->f_dentry->d_inode->i_rdev);	struct dsptask *task = taskdev[minor]->task;	if (task->map_length == 0) {		printk(KERN_ERR		       "omapdsp: task %s doesn't have mmap buffer.\n",

⌨️ 快捷键说明

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