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