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 + -
显示快捷键?