task.c

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

C
2,381
字号
		       task->name);		return -EINVAL;	}	if (is_dsp_internal_mem(task->map_base)) {		printk(KERN_ERR		       "omapdsp: task %s: map_base = %p\n"		       "    DARAM/SARAM can't be used as mmap buffer.\n",		       task->name, task->map_base);		return -EINVAL;	}	/*	 * Don't swap this area out	 * Don't dump this area to a core file	 */	vma->vm_flags |= VM_RESERVED | VM_IO;	/* Do not cache this area */	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);	req_len = vma->vm_end - vma->vm_start;	off = vma->vm_pgoff << PAGE_SHIFT;	tmp_vmadr = vma->vm_start;	tmp_vadr = task->map_base + off;	do {		tmp_padr = omap_dsp_virt_to_phys(tmp_vadr, &tmp_len);		if (tmp_padr == 0) {			printk(KERN_ERR			       "omapdsp: task %s: illegal address "			       "for mmap: %p", task->name, tmp_vadr);			/* partial mapping will be cleared in upper layer */			return -EINVAL;		}		if (tmp_len > req_len)			tmp_len = req_len;		printk(KERN_DEBUG		       "omapdsp: mmap info: "		       "vmadr = %08lx, padr = %08lx, len = %x\n",		       tmp_vmadr, tmp_padr, tmp_len);		if (remap_page_range(vma, tmp_vmadr, tmp_padr, tmp_len,				     vma->vm_page_prot) != 0) {			printk(KERN_ERR			       "omapdsp: task %s: remap_page_range() failed.\n",			       task->name);			/* partial mapping will be cleared in upper layer */			return -EAGAIN;		}		req_len   -= tmp_len;		tmp_vmadr += tmp_len;		tmp_vadr  += tmp_len;	} while (req_len);	vma->vm_ops = &omap_dsp_task_vm_ops;	omap_dsp_task_vma_open(vma);	return 0;}static int omap_dsp_task_open(struct inode *inode, struct file *file){	unsigned int minor = MINOR(inode->i_rdev);	struct taskdev *dev = taskdev[minor];	int sem_st;	if (minor >= n_task) {		/* dynamic task */		if ((sem_st = down_interruptible(&dev->dld_sem)) < 0)			return sem_st;#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN		if (dev->usecount > 0) {			up(&dev->dld_sem);			return -EBUSY;		}#endif		if (dev->task == NULL) {			/*			 * ask for daemon to load the dsptask.			 */			long current_state;			DECLARE_WAITQUEUE(wait, current);			add_wait_queue(&dev->open_wait_q, &wait);			current_state = current->state;			set_current_state(TASK_INTERRUPTIBLE);			dev->openstat = OMAP_DSP_OPENSTAT_REQ;			/* wake up twch daemon for tadd */			omap_dsp_twch_touch();			if (dev->task == NULL)	/* last check */				schedule();			set_current_state(current_state);			remove_wait_queue(&dev->open_wait_q, &wait);			if (dev->task == NULL) {				/*				 * FIXME: error handling should be in				 * more safe way (lock control, etc)				 */				printk(KERN_ERR				       "omapdsp: task attach failed for %s!\n",				       dev->name);				dev->openstat = OMAP_DSP_OPENSTAT_CLOSE;				/* wake up twch daemon */				omap_dsp_twch_touch();				up(&dev->dld_sem);				return -EBUSY;			}		}	} else {		/* static task */		preempt_disable();#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN		if (dev->usecount > 0)			return -EBUSY;#endif	}	/*	 * disable preemption while handling dev struct members	 */	dev->openstat = OMAP_DSP_OPENSTAT_OPEN;	dev->usecount++;	proc_list_add(&dev->task->proc_list, current);	if (minor >= n_task)	/* dynamic task */		up(&dev->dld_sem);	else			/* static task */		preempt_enable();	file->f_op = &dev->fops;	omap_dsp_map_update(current);	omap_dsp_cur_users_add(current);	return 0;}static int omap_dsp_task_release(struct inode *inode, struct file *file){	unsigned int minor = MINOR(inode->i_rdev);	struct taskdev *dev = taskdev[minor];	struct dsptask *task = dev->task;#ifdef CONFIG_OMAP_DSP_TASK_MULTIOPEN	if (task->lock_pid == current->pid)		omap_dsp_task_unlock(task);#endif	omap_dsp_cur_users_del(current);	if (minor >= n_task)	/* dynamic task */		down(&dev->dld_sem);	else			/* static task */		preempt_disable();	/*	 * disable preemption while handling dev struct members	 */	proc_list_del(&dev->task->proc_list, current);	if (--dev->usecount == 0) {		dev->openstat = OMAP_DSP_OPENSTAT_CLOSE;		omap_dsp_task_flush_buf(task);		if (minor >= n_task) {	/* dynamic task */			/* wake up twch daemon for tdel */			omap_dsp_twch_touch();			/* do not release dld_sem */			return 0;		}	}	if (minor >= n_task)	/* dynamic task */		up(&dev->dld_sem);	else			/* static task */		preempt_enable();	return 0;}/* * mkdev / rmdev */int omap_dsp_mkdev(char *name){	struct taskdev *dev;	int status;	unsigned char minor;	if (taskmod_cfgstat != CFGSTAT_DONE) {		printk(KERN_ERR "omapdsp: dsp has not been configured.\n");		return -EINVAL;	}	for (minor = n_task; minor < TASKDEV_MAX; minor++) {		if (taskdev[minor] == NULL)			goto do_make;	}	printk(KERN_ERR "omapdsp: Too many task devices.\n");	return -EBUSY;do_make:	if ((dev = kmalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL)		return -ENOMEM;	memset(dev, 0, sizeof(struct taskdev));	if ((status = omap_dsp_taskdev_init(dev, name, minor)) < 0) {		kfree(dev);		return status;	}	taskdev[minor] = dev;	return minor;}int omap_dsp_rmdev(char *name){	unsigned char minor;	int ret;	if (taskmod_cfgstat != CFGSTAT_DONE) {		printk(KERN_ERR "omapdsp: dsp has not been configured.\n");		return -EINVAL;	}	for (minor = n_task; minor < TASKDEV_MAX; minor++) {		if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {			if ((ret = omap_dsp_rmdev_minor(minor)) < 0)				return ret;			return minor;		}	}	return -EINVAL;}static int omap_dsp_rmdev_minor(unsigned char minor){	struct taskdev *dev = taskdev[minor];	struct dsptask *task = dev->task;	if ((dev->usecount > 0) || waitqueue_active(&dev->open_wait_q))		return -EBUSY;	if (task) {		/* FIXME: tdel? */		omap_dsp_taskdev_detach_task(dev);		omap_dsp_task_unconfig(task);		kfree(task);	}	omap_dsp_taskdev_delete(minor);	kfree(dev);	return 0;}struct file_operations omap_dsp_task_fops = {	.owner   = THIS_MODULE,	.poll    = omap_dsp_task_poll,	.ioctl   = omap_dsp_task_ioctl,	.open    = omap_dsp_task_open,	.release = omap_dsp_task_release,	.mmap    = omap_dsp_task_mmap,};static int omap_dsp_taskdev_init(struct taskdev *dev, char *name,				 unsigned char minor){	taskdev[minor] = dev;	strncpy(dev->name, name, OMAP_DSP_TNM_LEN);	dev->enable = 1;	dev->name[OMAP_DSP_TNM_LEN-1] = '\0';	dev->openstat = OMAP_DSP_OPENSTAT_CLOSE;	dev->usecount = 0;	memcpy(&dev->fops, &omap_dsp_task_fops, sizeof(struct file_operations));	devfs_mk_cdev(MKDEV(OMAP_DSP_TASK_MAJOR, minor),		      S_IFCHR | S_IRUGO | S_IWUGO, "dsptask/%s", dev->name);#ifdef CONFIG_PROC_FS	omap_dsp_taskdev_create_proc(dev);#endif	init_waitqueue_head(&dev->open_wait_q);	init_MUTEX(&dev->dld_sem);	return 0;}static void omap_dsp_taskdev_delete(unsigned char minor){	struct taskdev *dev = taskdev[minor];	if (!dev->enable)		return;#ifdef CONFIG_PROC_FS	omap_dsp_taskdev_remove_proc(dev);#endif	devfs_remove("dsptask/%s", dev->name);	taskdev[minor] = NULL;}static void omap_dsp_taskdev_attach_task(struct taskdev *dev,					struct dsptask *task){	unsigned short ttyp = task->ttyp;	dev->task = task;	dev->fops.read =		sndtyp_acv(ttyp) ?			sndtyp_wd(ttyp) ? omap_dsp_task_read_wd_acv:			/* sndtyp_bk */   omap_dsp_task_read_bk_acv:		/* sndtyp_psv */			sndtyp_wd(ttyp) ? omap_dsp_task_read_wd_psv:			/* sndtyp_bk */   omap_dsp_task_read_bk_psv;	dev->fops.write =		rcvtyp_wd(ttyp) ? omap_dsp_task_write_wd:		/* rcvbyp_bk */	  omap_dsp_task_write_bk;	printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);}static void omap_dsp_taskdev_detach_task(struct taskdev *dev){	if (dev->task) {		dev->task = NULL;		dev->fops.read = NULL;		dev->fops.write = NULL;		printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name);	}}/* * tadd / tdel */int omap_dsp_tadd(unsigned char minor, unsigned long adr){	struct taskdev *dev;	struct dsptask *task;	unsigned short argv[2];	int ret = minor;	if (minor >= TASKDEV_MAX) {		printk(KERN_ERR		       "omapdsp: illegal minor number (%d) for tadd\n", minor);		return -EINVAL;	}	dev = taskdev[minor];	if (!dev) {		printk(KERN_ERR		       "omapdsp: no task device with minor %d\n", minor);		return -EINVAL;	}	if (dev->task) {		printk(KERN_ERR		       "omapdsp: task has already been attached "		       "for taskdev %s\n", dev->name);		return -EINVAL;	}	if (adr == OMAP_DSP_TADD_ABORTADR) {		ret = 0;	/* FIXME: Is it ok? */		goto done;	}	if (adr >= DSPSPACE_SIZE) {		printk(KERN_ERR		       "omapdsp: illegal address 0x%08lx for tadd\n", adr);		ret = -EINVAL;		goto done;	}	adr >>= 1;	/* word address */	argv[0] = adr >> 16;		/* addrh */	argv[1] = adr & 0xffff;	/* addrl */	tadd_tid = OMAP_DSP_TID_ANON;	tcfg_wait_cmd = MBCMD(TADD);	omap_dsp_mbsend_and_wait_exarg(MBCMD(TADD), 0, 0,				      OMAP_DSP_TID_ANON, 2, argv, &tcfg_wait_q);	if (tadd_tid == OMAP_DSP_TID_ANON) {		printk(KERN_ERR "omapdsp: tadd failed!\n");		ret = -EINVAL;		goto done;	}	if ((tadd_tid < n_task) || dsptask[tadd_tid]) {		printk(KERN_ERR "omapdsp: illegal tid (%d)!\n", tadd_tid);		ret = -EINVAL;		goto done;	}	if ((task = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL)		return -ENOMEM;	memset(task, 0, sizeof(struct dsptask));	if ((ret = omap_dsp_task_config(task, tadd_tid)) < 0)		goto done;	if (strcmp(dev->name, task->name)) {		printk(KERN_ERR		       "omapdsp: task name (%s) doesn't match with "		       "device name (%s).\n", task->name, dev->name);		ret = -EINVAL;		goto done;	}	omap_dsp_taskdev_attach_task(dev, task);done:	wake_up_interruptible(&dev->open_wait_q);	return ret;}int omap_dsp_tdel(unsigned int minor){	struct taskdev *dev;	struct dsptask *task;	unsigned char tid;	if (minor >= TASKDEV_MAX) {		printk(KERN_ERR		       "omapdsp: illegal minor number (%d) for tdel\n", minor);		return -EINVAL;	}	dev = taskdev[minor];	if (!dev) {		printk(KERN_ERR		       "omapdsp: no task device with minor %d\n", minor);		return -EINVAL;	}	task = dev->task;	if (!task) {		printk(KERN_ERR		       "omapdsp: task has not been attached "		       "for taskdev %s\n", dev->name);		return -EINVAL;	}	if (dev->usecount > 0) {		printk(KERN_ERR "omapdsp: taskdev %s is busy.\n", dev->name);		return -EBUSY;	}	tid = task->tid;	tdel_tid = OMAP_DSP_TID_ANON;	tcfg_wait_cmd = MBCMD(TDEL);	omap_dsp_mbsend_and_wait(MBCMD(TDEL), tid, 0, &tcfg_wait_q);	omap_dsp_taskdev_detach_task(dev);	omap_dsp_task_unconfig(task);	kfree(task);	up(&dev->dld_sem);	if (tdel_tid != tid) {		printk(KERN_ERR "omapdsp: tdel failed!\n");		return -EINVAL;	}	return minor;}/* * openstat inquiry */int omap_dsp_taskdev_openstat(unsigned char minor){	return taskdev[minor] ? taskdev[minor]->openstat :				OMAP_DSP_OPENSTAT_CLOSE;}/* * functions called from mailbox1 interrupt routine */void mailbox1_wdsnd(unsigned char tid, unsigned short data){	struct dsptask *task = dsptask[tid];	if ((tid >= TASKDEV_MAX) || (task == NULL)) {		printk(KERN_ERR "mailbox: WDSND with illegal tid! %d\n", tid);		return;	}	if (sndtyp_bk(task->ttyp)) {		printk(KERN_ERR		       "mailbox: WDSND from block sending task! "		       "(task%d)\n", tid);		return;	}	if (sndtyp_psv(task->ttyp) && !waitqueue_active(&task->read_wait_q)) {		printk(KERN_WARNING		       "mailbox: WDSND from passive sending task "		       "(task%d) without request!\n", tid);		return;	}	write_word_to_fifo(&task->rcvdt.fifo, data);	wake_up_interruptible(&task->read_wait_q);}void mailbox1_wdreq(unsigned char tid){	struct dsptask *task = dsptask[tid];	if ((tid >= TASKDEV_MAX) || (task == NULL)) {		printk(KERN_ERR "mailbox: WDREQ with illegal tid! %d\n", tid);		return;	}	if (rcvtyp_psv(task->ttyp)) {		printk(KERN_ERR		       "mailbox: WDREQ from passive receiving task! "		       "(task%d)\n", tid);		return;	}	task->wsz = 2;	wake_up_interruptible(&task->write_wait_q);}void mailbox1_bksnd(unsigned char tid, unsigned short bid){	struct dsptask *task = dsptask[tid];	unsigned short cnt;	if (bid >= ipbcfg.ln) {		printk(KERN_ERR "mailbox: BKSND with illegal bid! %d\n", bid);		return;	}	ipb_bsycnt_dec(&ipbcfg);	if ((tid >= TASKDEV_MAX) || (task == NULL)) {		printk(KERN_ERR "mailbox: BKSND with illegal tid! %d\n", tid);		unuse_ipbuf(bid, MBSENDTYPE_NOWAIT);		return;	}	if (sndtyp_wd(task->ttyp)) {		printk(KERN_ERR		       "mailbox: BKSND from word sending task! "		       "(task%d)\n", tid);		unuse_ipbuf(bid, MBSENDTYPE_NOWAIT);		return;	}	if (sndtyp_pvt(task->ttyp)) {		printk(KERN_ERR		       "mailbox: BKSND from private sending task! "		       "(task%d)\n", tid);		unuse_ipbuf(bid, MBSENDTYPE_NOWAIT);		return;	}	if (sync_with_dsp(&ipbuf[bid]->sd, tid, 10) < 0) {		printk(KERN_ERR "mailbox: BKSND - IPBUF sync failed!\n");		return;	}	/* should be done in DSP, but just in case. */	ipbuf[bid]->next = OMAP_DSP_BID_NULL;	cnt = ipbuf[bid]->c;	if (cnt > ipbcfg.lsz) {		printk(KERN_ERR		       "mailbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",		       cnt, ipbcfg.lsz);		unuse_ipbuf(bid, MBSENDTYPE_NOWAIT);		return;	}	if (cnt == 0) {		/* 0-byte send from DSP */		unuse_ipbuf(bid, MBSENDTYPE_NOWAIT);		goto done;	}	ipblink_add_tail(&task->rcvdt.bk.link, bid, ipbuf);	/* we keep coming bid and return alternative line to DSP. */	balance_ipbuf(MBSENDTYPE_NOWAIT);done:	wake_up_interruptible(&task->read_wait_q);}void mailbox1_bkreq(unsigned char tid, unsigned short cnt){	struct dsptask *task = dsptask[tid];	if ((tid >= TASKDEV_MAX) || (task == NULL)) {		printk(KERN_ERR "mailbox: BKREQ with illegal tid! %d\n", tid);		return;	}	if (rcvtyp_wd(task->ttyp)) {		printk(KERN_ERR		       "mailbox: BKREQ from word receiving task! "		       "(task%d)\n", tid);		return;	}	if (rcvtyp_pvt(task->ttyp)) {		printk(KERN_ERR		       "mailbox: BKREQ from private receiving task! "		       "(task%d)\n", tid);		return;	}	if (rcvtyp_psv(task->ttyp)) {		printk(KERN_ERR		       "mailbox: BKREQ from passive receiving task! "		       "(task%d)\n", tid);		return;	}	task->wsz = cnt*2;	wake_up_interruptible(&task->write_wait_q);}void mailbox1_bkyld(unsigned short bid){

⌨️ 快捷键说明

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