]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/plat-omap/dsp/task.c
ARM: OMAP: DSPGW: rename mbx -> mbox
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / dsp / task.c
index 9a9595d9d01e0d4ff8be8f99c70abeed7cc08466..118f7a52e55022e7a0d262de04c1afb264e9a79b 100644 (file)
@@ -1,28 +1,24 @@
 /*
- * linux/arch/arm/mach-omap/dsp/task.c
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
  *
- * OMAP DSP task device driver
+ * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
  *
- * Copyright (C) 2002-2005 Nokia Corporation
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
  *
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
- * mmap function by Hiroo Ishikawa <ext-hiroo.ishikawa@nokia.com>
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
  *
- * 2005/07/26:  DSP Gateway version 3.3
  */
 
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
-#include <asm/signal.h>
-#include <asm/irq.h>
-#include <asm/ioctls.h>
-#include <asm/arch/dsp.h>
+#include <asm/arch/mailbox.h>
 #include "uaccess_dsp.h"
+#include "dsp_mbcmd.h"
 #include "dsp.h"
 #include "ipbuf.h"
 #include "fifo.h"
 #include "proclist.h"
+#include "ioctl.h"
 
 #define is_aligned(adr,align)  (!((adr)&((align)-1)))
 
 /*
- * taskdev.state: device state machine
+ * devstate: task device state machine
  * NOTASK:     task is not attached.
  * ATTACHED:   task is attached.
  * GARBAGE:    task is detached. waiting for all processes to close this device.
  * ADDREQ:     requesting for tadd
  * DELREQ:     requesting for tdel. no process is opening this device.
+ * FREEZED:    task is attached, but reserved to be killed.
  * ADDFAIL:    tadd failed.
  * ADDING:     tadd in process.
  * DELING:     tdel in process.
  * KILLING:    tkill in process.
  */
-#define devstate_name(stat) (\
-       ((stat) & OMAP_DSP_DEVSTATE_NOTASK)   ? "NOTASK" :\
-       ((stat) & OMAP_DSP_DEVSTATE_ATTACHED) ? "ATTACHED" :\
-       ((stat) & OMAP_DSP_DEVSTATE_GARBAGE)  ? "GARBAGE" :\
-       ((stat) & OMAP_DSP_DEVSTATE_INVALID)  ? "INVALID" :\
-       ((stat) & OMAP_DSP_DEVSTATE_ADDREQ)   ? "ADDREQ" :\
-       ((stat) & OMAP_DSP_DEVSTATE_DELREQ)   ? "DELREQ" :\
-       ((stat) & OMAP_DSP_DEVSTATE_ADDFAIL)  ? "ADDFAIL" :\
-       ((stat) & OMAP_DSP_DEVSTATE_ADDING)   ? "ADDING" :\
-       ((stat) & OMAP_DSP_DEVSTATE_DELING)   ? "DELING" :\
-       ((stat) & OMAP_DSP_DEVSTATE_KILLING)  ? "KILLING" :\
-                                               "unknown")
+#define TASKDEV_ST_NOTASK      0x00000001
+#define TASKDEV_ST_ATTACHED    0x00000002
+#define TASKDEV_ST_GARBAGE     0x00000004
+#define TASKDEV_ST_INVALID     0x00000008
+#define TASKDEV_ST_ADDREQ      0x00000100
+#define TASKDEV_ST_DELREQ      0x00000200
+#define TASKDEV_ST_FREEZED     0x00000400
+#define TASKDEV_ST_ADDFAIL     0x00001000
+#define TASKDEV_ST_ADDING      0x00010000
+#define TASKDEV_ST_DELING      0x00020000
+#define TASKDEV_ST_KILLING     0x00040000
+#define TASKDEV_ST_STATE_MASK  0x7fffffff
+#define TASKDEV_ST_STALE       0x80000000
+
+struct {
+       long state;
+       char *name;
+} devstate_desc[] = {
+       { TASKDEV_ST_NOTASK,   "notask" },
+       { TASKDEV_ST_ATTACHED, "attached" },
+       { TASKDEV_ST_GARBAGE,  "garbage" },
+       { TASKDEV_ST_INVALID,  "invalid" },
+       { TASKDEV_ST_ADDREQ,   "addreq" },
+       { TASKDEV_ST_DELREQ,   "delreq" },
+       { TASKDEV_ST_FREEZED,  "freezed" },
+       { TASKDEV_ST_ADDFAIL,  "addfail" },
+       { TASKDEV_ST_ADDING,   "adding" },
+       { TASKDEV_ST_DELING,   "deling" },
+       { TASKDEV_ST_KILLING,  "killing" },
+};
+
+static char *devstate_name(long state) {
+       int i;
+       int max = ARRAY_SIZE(devstate_desc);
+
+       for (i = 0; i < max; i++) {
+               if (state & devstate_desc[i].state)
+                       return devstate_desc[i].name;
+       }
+       return "unknown";
+}
+
+struct rcvdt_bk_struct {
+       struct ipblink link;
+       unsigned int rp;
+};
 
 struct taskdev {
        struct bus_type *bus;
@@ -83,25 +112,35 @@ struct taskdev {
        struct device dev;      /* Generic device interface */
 
        long state;
-       spinlock_t state_lock;
+       struct rw_semaphore state_sem;
        wait_queue_head_t state_wait_q;
+       struct mutex usecount_lock;
        unsigned int usecount;
-       char name[OMAP_DSP_TNM_LEN];
+       char name[TNM_LEN];
        struct file_operations fops;
+       spinlock_t proc_list_lock;
        struct list_head proc_list;
        struct dsptask *task;
 
        /* read stuff */
        wait_queue_head_t read_wait_q;
        struct mutex read_mutex;
+       union {
+               struct fifo_struct fifo;        /* for active word */
+               struct rcvdt_bk_struct bk;
+       } rcvdt;
 
        /* write stuff */
        wait_queue_head_t write_wait_q;
        struct mutex write_mutex;
+       spinlock_t wsz_lock;
+       size_t wsz;
 
-       /* ioctl stuff */
-       wait_queue_head_t ioctl_wait_q;
-       struct mutex ioctl_mutex;
+       /* tctl stuff */
+       wait_queue_head_t tctl_wait_q;
+       struct mutex tctl_mutex;
+       int tctl_stat;
+       int tctl_ret;   /* return value for tctl_show() */
 
        /* device lock */
        struct mutex lock;
@@ -110,61 +149,71 @@ struct taskdev {
 
 #define to_taskdev(n) container_of(n, struct taskdev, dev)
 
-struct rcvdt_bk_struct {
-       struct ipblink link;
-       unsigned int rp;
-       struct ipbuf_p *ipbuf_pvt_r;
-};
-
 struct dsptask {
        enum {
-               TASK_STATE_ERR = 0,
-               TASK_STATE_READY,
-               TASK_STATE_CFGREQ
+               TASK_ST_ERR = 0,
+               TASK_ST_READY,
+               TASK_ST_CFGREQ
        } state;
-       unsigned char tid;
-       char name[OMAP_DSP_TNM_LEN];
-       unsigned short ttyp;
+       u8 tid;
+       char name[TNM_LEN];
+       u16 ttyp;
        struct taskdev *dev;
 
        /* read stuff */
-       union {
-               struct fifo_struct fifo;        /* for active word */
-               struct rcvdt_bk_struct bk;
-       } rcvdt;
+       struct ipbuf_p *ipbuf_pvt_r;
 
        /* write stuff */
-       size_t wsz;
-       spinlock_t wsz_lock;
-       struct ipbuf_p *ipbuf_pvt_w;    /* for private block */
-
-       /* tctl stuff */
-       int tctl_stat;
+       struct ipbuf_p *ipbuf_pvt_w;
 
        /* mmap stuff */
        void *map_base;
        size_t map_length;
 };
 
-#define sndtyp_acv(ttyp)       ((ttyp) & OMAP_DSP_TTYP_ASND)
-#define sndtyp_psv(ttyp)       (!((ttyp) & OMAP_DSP_TTYP_ASND))
-#define sndtyp_bk(ttyp)                ((ttyp) & OMAP_DSP_TTYP_BKDM)
-#define sndtyp_wd(ttyp)                (!((ttyp) & OMAP_DSP_TTYP_BKDM))
-#define sndtyp_pvt(ttyp)       ((ttyp) & OMAP_DSP_TTYP_PVDM)
-#define sndtyp_gbl(ttyp)       (!((ttyp) & OMAP_DSP_TTYP_PVDM))
-#define rcvtyp_acv(ttyp)       ((ttyp) & OMAP_DSP_TTYP_ARCV)
-#define rcvtyp_psv(ttyp)       (!((ttyp) & OMAP_DSP_TTYP_ARCV))
-#define rcvtyp_bk(ttyp)                ((ttyp) & OMAP_DSP_TTYP_BKMD)
-#define rcvtyp_wd(ttyp)                (!((ttyp) & OMAP_DSP_TTYP_BKMD))
-#define rcvtyp_pvt(ttyp)       ((ttyp) & OMAP_DSP_TTYP_PVMD)
-#define rcvtyp_gbl(ttyp)       (!((ttyp) & OMAP_DSP_TTYP_PVMD))
-
+#define sndtyp_acv(ttyp)       ((ttyp) & TTYP_ASND)
+#define sndtyp_psv(ttyp)       (!((ttyp) & TTYP_ASND))
+#define sndtyp_bk(ttyp)                ((ttyp) & TTYP_BKDM)
+#define sndtyp_wd(ttyp)                (!((ttyp) & TTYP_BKDM))
+#define sndtyp_pvt(ttyp)       ((ttyp) & TTYP_PVDM)
+#define sndtyp_gbl(ttyp)       (!((ttyp) & TTYP_PVDM))
+#define rcvtyp_acv(ttyp)       ((ttyp) & TTYP_ARCV)
+#define rcvtyp_psv(ttyp)       (!((ttyp) & TTYP_ARCV))
+#define rcvtyp_bk(ttyp)                ((ttyp) & TTYP_BKMD)
+#define rcvtyp_wd(ttyp)                (!((ttyp) & TTYP_BKMD))
+#define rcvtyp_pvt(ttyp)       ((ttyp) & TTYP_PVMD)
+#define rcvtyp_gbl(ttyp)       (!((ttyp) & TTYP_PVMD))
+
+static __inline__ int has_taskdev_lock(struct taskdev *dev);
 static int dsp_rmdev_minor(unsigned char minor);
 static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor);
 static void taskdev_delete(unsigned char minor);
-static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
-static void taskdev_detach_task(struct taskdev *dev);
-static int dsp_tdel_bh(unsigned char minor, unsigned short type);
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task);
+static int dsp_tdel_bh(struct taskdev *dev, u16 type);
+
+static struct bus_type dsptask_bus = {
+       .name = "dsptask",
+};
+
+static struct class *dsp_task_class;
+static DEFINE_MUTEX(devmgr_lock);
+static struct taskdev *taskdev[TASKDEV_MAX];
+static struct dsptask *dsptask[TASKDEV_MAX];
+static DEFINE_MUTEX(cfg_lock);
+static u16 cfg_cmd;
+static u8 cfg_tid;
+static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
+static u8 n_task;      /* static task count */
+static void *heap;
+
+#define is_dynamic_task(tid)   ((tid) >= n_task)
+
+#define devstate_read_lock(dev, devstate) \
+               devstate_read_lock_timeout(dev, devstate, 0)
+#define devstate_read_unlock(dev)      up_read(&(dev)->state_sem)
+#define devstate_write_lock(dev, devstate) \
+               devstate_write_lock_timeout(dev, devstate, 0)
+#define devstate_write_unlock(dev)     up_write(&(dev)->state_sem)
 
 static ssize_t devname_show(struct device *d, struct device_attribute *attr,
                            char *buf);
@@ -189,147 +238,189 @@ static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
 static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
                         char *buf);
 
-static struct device_attribute dev_attr_devname = __ATTR_RO(devname);
-static struct device_attribute dev_attr_devstate = __ATTR_RO(devstate);
-static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
-static struct device_attribute dev_attr_fifosz = 
-       __ATTR(fifosz, S_IWUGO | S_IRUGO, fifosz_show, fifosz_store);
-static struct device_attribute dev_attr_fifocnt = __ATTR_RO(fifocnt);
-static struct device_attribute dev_attr_taskname = __ATTR_RO(taskname);
-static struct device_attribute dev_attr_ttyp = __ATTR_RO(ttyp);
-static struct device_attribute dev_attr_ipblink = __ATTR_RO(ipblink);
-static struct device_attribute dev_attr_wsz = __ATTR_RO(wsz);
-static struct device_attribute dev_attr_mmap = __ATTR_RO(mmap);
-
-static struct bus_type dsptask_bus = {
-       .name = "dsptask",
-};
-
-static struct class *dsp_task_class;
-static struct taskdev *taskdev[TASKDEV_MAX];
-static struct dsptask *dsptask[TASKDEV_MAX];
-static DEFINE_MUTEX(cfg_lock);
-static unsigned short cfg_cmd;
-static unsigned char cfg_tid;
-static DECLARE_WAIT_QUEUE_HEAD(cfg_wait_q);
-static unsigned char n_task;
-static void *heap;
+#define __ATTR_RW(_name,_mode) { \
+       .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE },     \
+       .show   = _name##_show,                                 \
+       .store  = _name##_store,                                        \
+}
 
-#define devstate_lock(dev, devstate)   devstate_lock_timeout(dev, devstate, 0)
+static struct device_attribute dev_attr_devname   = __ATTR_RO(devname);
+static struct device_attribute dev_attr_devstate  = __ATTR_RO(devstate);
+static struct device_attribute dev_attr_proc_list = __ATTR_RO(proc_list);
+static struct device_attribute dev_attr_taskname  = __ATTR_RO(taskname);
+static struct device_attribute dev_attr_ttyp      = __ATTR_RO(ttyp);
+static struct device_attribute dev_attr_fifosz    = __ATTR_RW(fifosz, 0666);
+static struct device_attribute dev_attr_fifocnt   = __ATTR_RO(fifocnt);
+static struct device_attribute dev_attr_ipblink   = __ATTR_RO(ipblink);
+static struct device_attribute dev_attr_wsz       = __ATTR_RO(wsz);
+static struct device_attribute dev_attr_mmap      = __ATTR_RO(mmap);
 
 /*
- * devstate_lock_timeout():
- * when called with timeout > 0, dev->state can be diffeent from what you want.
+ * devstate_read_lock_timeout()
+ * devstate_write_lock_timeout():
+ * timeout != 0: dev->state can be diffeent from what you want.
+ * timeout == 0: no timeout
  */
-static int devstate_lock_timeout(struct taskdev *dev, long devstate,
-                                int timeout)
+static int devstate_read_lock_timeout(struct taskdev *dev, long devstate,
+                                     int timeout)
 {
        DECLARE_WAITQUEUE(wait, current);
        long current_state = current->state;
        int ret = 0;
 
-       spin_lock(&dev->state_lock);
+       down_read(&dev->state_sem);
+       if (dev->state & devstate)
+               return 0;
+
        add_wait_queue(&dev->state_wait_q, &wait);
-       while (!(dev->state & devstate)) {
+       do {
                set_current_state(TASK_INTERRUPTIBLE);
-               spin_unlock(&dev->state_lock);
+               up_read(&dev->state_sem);
                if (timeout) {
                        if ((timeout = schedule_timeout(timeout)) == 0) {
                                /* timeout */
-                               spin_lock(&dev->state_lock);
+                               down_read(&dev->state_sem);
                                break;
                        }
+               } else
+                       schedule();
+               if (signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
                }
-               else
+               down_read(&dev->state_sem);
+       } while (!(dev->state & devstate));
+       remove_wait_queue(&dev->state_wait_q, &wait);
+       set_current_state(current_state);
+       return ret;
+}
+
+static int devstate_read_lock_and_test(struct taskdev *dev, long devstate)
+{
+       down_read(&dev->state_sem);
+       if (dev->state & devstate)
+               return 1;       /* success */
+       /* failure */
+       up_read(&dev->state_sem);
+       return 0;
+}
+
+static int devstate_write_lock_timeout(struct taskdev *dev, long devstate,
+                                      int timeout)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       long current_state = current->state;
+       int ret = 0;
+
+       down_write(&dev->state_sem);
+       if (dev->state & devstate)
+               return 0;
+
+       add_wait_queue(&dev->state_wait_q, &wait);
+       do {
+               set_current_state(TASK_INTERRUPTIBLE);
+               up_write(&dev->state_sem);
+               if (timeout) {
+                       if ((timeout = schedule_timeout(timeout)) == 0) {
+                               /* timeout */
+                               down_write(&dev->state_sem);
+                               break;
+                       }
+               } else
                        schedule();
                if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
+                       ret = -EINTR;
                        break;
                }
-               spin_lock(&dev->state_lock);
-       }
+               down_write(&dev->state_sem);
+       } while (!(dev->state & devstate));
        remove_wait_queue(&dev->state_wait_q, &wait);
        set_current_state(current_state);
        return ret;
 }
 
-static __inline__ void devstate_unlock(struct taskdev *dev)
+static int devstate_write_lock_and_test(struct taskdev *dev, long devstate)
 {
-       spin_unlock(&dev->state_lock);
+       down_write(&dev->state_sem);
+       if (dev->state & devstate)      /* success */
+               return 1;
+
+       /* failure */
+       up_write(&dev->state_sem);
+       return -1;
 }
 
-static inline int taskdev_lock_interruptible(struct taskdev *dev,
-                                            struct mutex *lock)
+static int taskdev_lock_interruptible(struct taskdev *dev,
+                                     struct mutex *lock)
 {
        int ret;
 
-       if (dev->lock_pid == current->pid) {
-               /* this process has lock */
+       if (has_taskdev_lock(dev))
                ret = mutex_lock_interruptible(lock);
-       else {
+       else {
                if ((ret = mutex_lock_interruptible(&dev->lock)) != 0)
                        return ret;
                ret = mutex_lock_interruptible(lock);
                mutex_unlock(&dev->lock);
        }
+
        return ret;
 }
 
-static void proclist_send_sigbus(struct list_head *list)
+static int taskdev_lock_and_statelock_attached(struct taskdev *dev,
+                                              struct mutex *lock)
 {
-       siginfo_t info;
-       struct proc_list *pl;
-       struct task_struct *tsk;
+       int ret;
 
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = SI_KERNEL;
-       info._sifields._sigfault._addr = NULL;
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
 
-       /* need to lock tasklist_lock before calling find_task_by_pid_type. */
-       read_lock(&tasklist_lock);
-       list_for_each_entry(pl, list, list_head) {
-               if ((tsk = find_task_by_pid_type(PIDTYPE_PID, pl->pid)) != NULL)
-                       send_sig_info(SIGBUS, &info, tsk);
-       }
-       read_unlock(&tasklist_lock);
+       if ((ret = taskdev_lock_interruptible(dev, lock)) != 0)
+               devstate_read_unlock(dev);
+
+       return ret;
+}
+
+static __inline__ void taskdev_unlock_and_stateunlock(struct taskdev *dev,
+                                                     struct mutex *lock)
+{
+       mutex_unlock(lock);
+       devstate_read_unlock(dev);
 }
 
-static int dsp_task_flush_buf(struct dsptask *task)
+/*
+ * taskdev_flush_buf()
+ * must be called under state_lock(ATTACHED) and dev->read_mutex.
+ */
+static int taskdev_flush_buf(struct taskdev *dev)
 {
-       unsigned short ttyp = task->ttyp;
+       u16 ttyp = dev->task->ttyp;
 
        if (sndtyp_wd(ttyp)) {
                /* word receiving */
-               flush_fifo(&task->rcvdt.fifo);
+               flush_fifo(&dev->rcvdt.fifo);
        } else {
                /* block receiving */
-               struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk;
-
-               spin_lock(&rcvdt->link.lock);
-               if (sndtyp_gbl(ttyp)) {
-                       /* global IPBUF */
-                       while (!ipblink_empty(&rcvdt->link)) {
-                               unsigned short bid = rcvdt->link.top;
-                               ipblink_del_top(&rcvdt->link, ipbuf);
-                               unuse_ipbuf(bid);
-                       }
-               } else {
-                       /* private IPBUF */
-                       if (!ipblink_empty(&rcvdt->link)) {
-                               ipblink_del_pvt(&rcvdt->link);
-                               release_ipbuf_pvt(rcvdt->ipbuf_pvt_r);
-                       }
+               struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
+
+               if (sndtyp_gbl(ttyp))
+                       ipblink_flush(&rcvdt->link);
+               else {
+                       ipblink_flush_pvt(&rcvdt->link);
+                       release_ipbuf_pvt(dev->task->ipbuf_pvt_r);
                }
-               spin_unlock(&rcvdt->link.lock);
        }
 
        return 0;
 }
 
-static int dsp_task_set_fifosz(struct dsptask *task, unsigned long sz)
+/*
+ * taskdev_set_fifosz()
+ * must be called under dev->read_mutex.
+ */
+static int taskdev_set_fifosz(struct taskdev *dev, unsigned long sz)
 {
-       unsigned short ttyp = task->ttyp;
+       u16 ttyp = dev->task->ttyp;
        int stat;
 
        if (!(sndtyp_wd(ttyp) && sndtyp_acv(ttyp))) {
@@ -340,35 +431,40 @@ static int dsp_task_set_fifosz(struct dsptask *task, unsigned long sz)
        }
        if ((sz == 0) || (sz & 1)) {
                printk(KERN_ERR "omapdsp: illegal buffer size! (%ld)\n"
-                               "it must be even and non-zero value.\n", sz);
+                               "it must be even and non-zero value.\n", sz);
                return -EINVAL;
        }
 
-       stat = realloc_fifo(&task->rcvdt.fifo, sz);
+       stat = realloc_fifo(&dev->rcvdt.fifo, sz);
        if (stat == -EBUSY) {
                printk(KERN_ERR "omapdsp: buffer is not empty!\n");
                return stat;
        } else if (stat < 0) {
                printk(KERN_ERR
                       "omapdsp: unable to change receive buffer size. "
-                      "(%ld bytes for %s)\n", sz, task->name);
+                      "(%ld bytes for %s)\n", sz, dev->name);
                return stat;
        }
 
        return 0;
 }
 
+static __inline__ int has_taskdev_lock(struct taskdev *dev)
+{
+       return (dev->lock_pid == current->pid);
+}
+
 static int taskdev_lock(struct taskdev *dev)
 {
        if (mutex_lock_interruptible(&dev->lock))
-               return -ERESTARTSYS;
+               return -EINTR;
        dev->lock_pid = current->pid;
        return 0;
 }
 
 static int taskdev_unlock(struct taskdev *dev)
 {
-       if (dev->lock_pid != current->pid) {
+       if (!has_taskdev_lock(dev)) {
                printk(KERN_ERR
                       "omapdsp: an illegal process attempted to "
                       "unlock the dsptask lock!\n");
@@ -379,28 +475,26 @@ static int taskdev_unlock(struct taskdev *dev)
        return 0;
 }
 
-static int dsp_task_config(struct dsptask *task, unsigned char tid)
+static int dsp_task_config(struct dsptask *task, u8 tid)
 {
-       unsigned short ttyp;
-       struct mbcmd mb;
+       u16 ttyp;
        int ret;
 
        task->tid = tid;
        dsptask[tid] = task;
 
        /* TCFG request */
-       task->state = TASK_STATE_CFGREQ;
+       task->state = TASK_ST_CFGREQ;
        if (mutex_lock_interruptible(&cfg_lock)) {
-               ret = -ERESTARTSYS;
+               ret = -EINTR;
                goto fail_out;
        }
-       cfg_cmd = MBCMD(TCFG);
-       mbcmd_set(mb, MBCMD(TCFG), tid, 0);
-       dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
+       cfg_cmd = MBOX_CMD_DSP_TCFG;
+       mbcompose_send_and_wait(TCFG, tid, 0, &cfg_wait_q);
        cfg_cmd = 0;
        mutex_unlock(&cfg_lock);
 
-       if (task->state != TASK_STATE_READY) {
+       if (task->state != TASK_ST_READY) {
                printk(KERN_ERR "omapdsp: task %d configuration error!\n", tid);
                ret = -EINVAL;
                goto fail_out;
@@ -426,7 +520,7 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid)
 
        /* private buffer address check */
        if (sndtyp_pvt(ttyp) &&
-           (ipbuf_p_validate(task->rcvdt.bk.ipbuf_pvt_r, DIR_D2A) < 0)) {
+           (ipbuf_p_validate(task->ipbuf_pvt_r, DIR_D2A) < 0)) {
                ret = -EINVAL;
                goto fail_out;
        }
@@ -435,7 +529,7 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid)
                ret = -EINVAL;
                goto fail_out;
        }
-       
+
        /* mmap buffer configuration check */
        if ((task->map_length > 0) &&
            ((!is_aligned((unsigned long)task->map_base, PAGE_SIZE)) ||
@@ -451,36 +545,6 @@ static int dsp_task_config(struct dsptask *task, unsigned char tid)
                goto fail_out;
        }
 
-       /*
-        * initialization
-        */
-
-       /* read initialization */
-       if (sndtyp_wd(ttyp)) {
-               /* word */
-               size_t fifosz;
-
-               fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */
-                                           32; /* active */
-               if (init_fifo(&task->rcvdt.fifo, fifosz) < 0) {
-                       printk(KERN_ERR
-                              "omapdsp: unable to allocate receive buffer. "
-                              "(%d bytes for %s)\n", fifosz, task->name);
-                       ret = -ENOMEM;
-                       goto fail_out;
-               }
-       } else {
-               /* block */
-               INIT_IPBLINK(&task->rcvdt.bk.link);
-               task->rcvdt.bk.rp = 0;
-       }
-
-       /* write initialization */
-       spin_lock_init(&task->wsz_lock);
-       task->wsz = rcvtyp_acv(ttyp) ? 0 :              /* active */
-                   rcvtyp_wd(ttyp)  ? 2 :              /* passive word */
-                                      ipbcfg.lsz*2;    /* passive block */
-
        return 0;
 
 fail_out:
@@ -490,10 +554,10 @@ fail_out:
 
 static void dsp_task_init(struct dsptask *task)
 {
-       dsp_mbsend(MBCMD(TCTL), task->tid, OMAP_DSP_MBCMD_TCTL_TINIT);
+       mbcompose_send(TCTL, task->tid, TCTL_TINIT);
 }
 
-int dsp_task_config_all(unsigned char n)
+int dsp_task_config_all(u8 n)
 {
        int i, ret;
        struct taskdev *devheap;
@@ -503,26 +567,23 @@ int dsp_task_config_all(unsigned char n)
        memset(taskdev, 0, sizeof(void *) * TASKDEV_MAX);
        memset(dsptask, 0, sizeof(void *) * TASKDEV_MAX);
 
-       n_task = n;
-       printk(KERN_INFO "omapdsp: found %d task(s)\n", n_task);
-       if (n_task == 0)
+       printk(KERN_INFO "omapdsp: found %d task(s)\n", n);
+       if (n == 0)
                return 0;
 
        /*
         * reducing kmalloc!
         */
-       devheapsz  = sizeof(struct taskdev) * n_task;
-       taskheapsz = sizeof(struct dsptask) * n_task;
-       heap = kmalloc(devheapsz + taskheapsz, GFP_KERNEL);
-       if (heap == NULL) {
-               n_task = 0;
+       devheapsz  = sizeof(struct taskdev) * n;
+       taskheapsz = sizeof(struct dsptask) * n;
+       heap = kzalloc(devheapsz + taskheapsz, GFP_KERNEL);
+       if (heap == NULL)
                return -ENOMEM;
-       }
-       memset(heap, 0, devheapsz + taskheapsz);
        devheap  = heap;
        taskheap = heap + devheapsz;
 
-       for (i = 0; i < n_task; i++) {
+       n_task = n;
+       for (i = 0; i < n; i++) {
                struct taskdev *dev  = &devheap[i];
                struct dsptask *task = &taskheap[i];
 
@@ -530,7 +591,8 @@ int dsp_task_config_all(unsigned char n)
                        return ret;
                if ((ret = taskdev_init(dev, task->name, i)) < 0)
                        return ret;
-               taskdev_attach_task(dev, task);
+               if ((ret = taskdev_attach_task(dev, task)) < 0)
+                       return ret;
                dsp_task_init(task);
                printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);
        }
@@ -540,20 +602,13 @@ int dsp_task_config_all(unsigned char n)
 
 static void dsp_task_unconfig(struct dsptask *task)
 {
-       unsigned char tid = task->tid;
-
-       preempt_disable();
-       dsp_task_flush_buf(task);
-       if (sndtyp_wd(task->ttyp) && (task->state == TASK_STATE_READY))
-               free_fifo(&task->rcvdt.fifo);
-       dsptask[tid] = NULL;
-       preempt_enable();
+       dsptask[task->tid] = NULL;
 }
 
 void dsp_task_unconfig_all(void)
 {
        unsigned char minor;
-       unsigned char tid;
+       u8 tid;
        struct dsptask *task;
 
        for (minor = 0; minor < n_task; minor++) {
@@ -603,7 +658,7 @@ static struct device_driver dsptask_driver = {
        .bus    = &dsptask_bus,
 };
 
-unsigned char dsp_task_count(void)
+u8 dsp_task_count(void)
 {
        return n_task;
 }
@@ -612,21 +667,22 @@ int dsp_taskmod_busy(void)
 {
        struct taskdev *dev;
        unsigned char minor;
+       unsigned int usecount;
 
        for (minor = 0; minor < TASKDEV_MAX; minor++) {
                dev = taskdev[minor];
                if (dev == NULL)
                        continue;
-               if (dev->usecount > 0) {
+               if ((usecount = dev->usecount) > 0) {
                        printk("dsp_taskmod_busy(): %s: usecount=%d\n",
-                              dev->name, dev->usecount);
+                              dev->name, usecount);
                        return 1;
                }
 /*
-               if ((dev->state & (OMAP_DSP_DEVSTATE_ADDREQ |
-                                  OMAP_DSP_DEVSTATE_DELREQ)) {
+               if ((dev->state & (TASKDEV_ST_ADDREQ |
+                                  TASKDEV_ST_DELREQ)) {
 */
-               if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ) {
+               if (dev->state & TASKDEV_ST_ADDREQ) {
                        printk("dsp_taskmod_busy(): %s is in %s\n",
                               dev->name, devstate_name(dev->state));
                        return 1;
@@ -638,12 +694,11 @@ int dsp_taskmod_busy(void)
 /*
  * DSP task device file operations
  */
-static ssize_t dsp_task_read_wd_acv(struct file *file, char *buf, size_t count,
-                                   loff_t *ppos)
+static ssize_t dsp_task_read_wd_acv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
 {
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        struct taskdev *dev = taskdev[minor];
-       int have_devstate_lock = 0;
        int ret = 0;
 
        if (count == 0) {
@@ -654,58 +709,40 @@ static ssize_t dsp_task_read_wd_acv(struct file *file, char *buf, size_t count,
                return -EINVAL;
        }
 
-       if (taskdev_lock_interruptible(dev, &dev->read_mutex))
-               return -ERESTARTSYS;
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
-       have_devstate_lock = 1;
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
 
-       if (fifo_empty(&dev->task->rcvdt.fifo)) {
+       if (fifo_empty(&dev->rcvdt.fifo)) {
                long current_state = current->state;
                DECLARE_WAITQUEUE(wait, current);
 
                set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&dev->read_wait_q, &wait);
-               if (fifo_empty(&dev->task->rcvdt.fifo)) {       /* last check */
-                       devstate_unlock(dev);
-                       have_devstate_lock = 0;
+               if (fifo_empty(&dev->rcvdt.fifo))       /* last check */
                        schedule();
-               }
                set_current_state(current_state);
                remove_wait_queue(&dev->read_wait_q, &wait);
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
+               if (fifo_empty(&dev->rcvdt.fifo)) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
                        goto up_out;
                }
-               if (!have_devstate_lock) {
-                       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-                               ret = -ERESTARTSYS;
-                               goto up_out;
-                       }
-                       have_devstate_lock = 1;
-               }
-               if (fifo_empty(&dev->task->rcvdt.fifo)) /* should not occur */
-                       goto up_out;
        }
 
-       ret = copy_to_user_fm_fifo(buf, &dev->task->rcvdt.fifo, count);
+       ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count);
 
 up_out:
-       if (have_devstate_lock)
-               devstate_unlock(dev);
-       mutex_unlock(&dev->read_mutex);
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
        return ret;
 }
 
-static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count,
-                                   loff_t *ppos)
+static ssize_t dsp_task_read_bk_acv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
 {
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        struct taskdev *dev = taskdev[minor];
-       struct rcvdt_bk_struct *rcvdt;
-       int have_devstate_lock = 0;
+       struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
        ssize_t ret = 0;
 
        if (count == 0) {
@@ -721,55 +758,38 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count,
                return -EINVAL;
        }
 
-       if (taskdev_lock_interruptible(dev, &dev->read_mutex))
-               return -ERESTARTSYS;
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
-       have_devstate_lock = 1;
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
 
-       if (ipblink_empty(&dev->task->rcvdt.bk.link)) {
+       if (ipblink_empty(&rcvdt->link)) {
                long current_state;
                DECLARE_WAITQUEUE(wait, current);
 
                add_wait_queue(&dev->read_wait_q, &wait);
                current_state = current->state;
                set_current_state(TASK_INTERRUPTIBLE);
-               if (ipblink_empty(&dev->task->rcvdt.bk.link)) { /* last check */
-                       devstate_unlock(dev);
-                       have_devstate_lock = 0;
+               if (ipblink_empty(&rcvdt->link))        /* last check */
                        schedule();
-               }
                set_current_state(current_state);
                remove_wait_queue(&dev->read_wait_q, &wait);
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
+               if (ipblink_empty(&rcvdt->link)) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
                        goto up_out;
                }
-               if (!have_devstate_lock) {
-                       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-                               ret = -ERESTARTSYS;
-                               goto up_out;
-                       }
-                       have_devstate_lock = 1;
-               }
-               /* signal or 0-byte send from DSP */
-               if (ipblink_empty(&dev->task->rcvdt.bk.link))
-                       goto up_out;
        }
 
-       rcvdt = &dev->task->rcvdt.bk;
        /* copy from delayed IPBUF */
        if (sndtyp_pvt(dev->task->ttyp)) {
                /* private */
                if (!ipblink_empty(&rcvdt->link)) {
-                       struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r;
+                       struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
                        unsigned char *base, *src;
                        size_t bkcnt;
 
                        if (dsp_mem_enable(ipbp) < 0) {
-                               ret = -ERESTARTSYS;
+                               ret = -EBUSY;
                                goto up_out;
                        }
                        base = MKVIRT(ipbp->ah, ipbp->al);
@@ -777,11 +797,11 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count,
                        if (dsp_address_validate(base, bkcnt,
                                                 "task %s read buffer",
                                                 dev->task->name) < 0) {
-                               ret = -ERESTARTSYS;
+                               ret = -EINVAL;
                                goto pv_out1;
                        }
                        if (dsp_mem_enable(base) < 0) {
-                               ret = -ERESTARTSYS;
+                               ret = -EBUSY;
                                goto pv_out1;
                        }
                        src = base + rcvdt->rp;
@@ -798,9 +818,7 @@ static ssize_t dsp_task_read_bk_acv(struct file *file, char *buf, size_t count,
                                        goto pv_out2;
                                }
                                ret = bkcnt;
-                               spin_lock(&rcvdt->link.lock);
                                ipblink_del_pvt(&rcvdt->link);
-                               spin_unlock(&rcvdt->link.lock);
                                release_ipbuf_pvt(ipbp);
                                rcvdt->rp = 0;
                        }
@@ -812,17 +830,16 @@ pv_out1:
        } else {
                /* global */
                if (dsp_mem_enable_ipbuf() < 0) {
-                       ret = -ERESTARTSYS;
+                       ret = -EBUSY;
                        goto up_out;
                }
                while (!ipblink_empty(&rcvdt->link)) {
                        unsigned char *src;
                        size_t bkcnt;
-                       unsigned short bid = rcvdt->link.top;
-                       struct ipbuf *ipbp = ipbuf[bid];
+                       struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
 
-                       src = ipbp->d + rcvdt->rp;
-                       bkcnt = ((unsigned long)ipbp->c) * 2 - rcvdt->rp;
+                       src = ipb_h->p->d + rcvdt->rp;
+                       bkcnt = ((unsigned long)ipb_h->p->c) * 2 - rcvdt->rp;
                        if (bkcnt > count) {
                                if (copy_to_user_dsp(buf, src, count)) {
                                        ret = -EFAULT;
@@ -839,10 +856,8 @@ pv_out1:
                                ret += bkcnt;
                                buf += bkcnt;
                                count -= bkcnt;
-                               spin_lock(&rcvdt->link.lock);
-                               ipblink_del_top(&rcvdt->link, ipbuf);
-                               spin_unlock(&rcvdt->link.lock);
-                               unuse_ipbuf(bid);
+                               ipblink_del_top(&rcvdt->link);
+                               unuse_ipbuf(ipb_h);
                                rcvdt->rp = 0;
                        }
                }
@@ -851,19 +866,15 @@ gb_out:
        }
 
 up_out:
-       if (have_devstate_lock)
-               devstate_unlock(dev);
-       mutex_unlock(&dev->read_mutex);
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
        return ret;
 }
 
-static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count,
-                                   loff_t *ppos)
+static ssize_t dsp_task_read_wd_psv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
 {
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        struct taskdev *dev = taskdev[minor];
-       struct mbcmd mb;
-       unsigned char tid;
        int ret = 0;
 
        if (count == 0) {
@@ -877,46 +888,31 @@ static ssize_t dsp_task_read_wd_psv(struct file *file, char *buf, size_t count,
                count = 2;
        }
 
-       if (taskdev_lock_interruptible(dev, &dev->read_mutex))
-               return -ERESTARTSYS;
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
-       tid = dev->task->tid;
-       devstate_unlock(dev);
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
 
-       mbcmd_set(mb, MBCMD(WDREQ), tid, 0);
-       dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q);
+       mbcompose_send_and_wait(WDREQ, dev->task->tid, 0, &dev->read_wait_q);
 
-       if (signal_pending(current)) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
+       if (fifo_empty(&dev->rcvdt.fifo)) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
                goto up_out;
        }
-       if (fifo_empty(&dev->task->rcvdt.fifo)) /* should not occur */
-               goto unlock_out;
 
-       ret = copy_to_user_fm_fifo(buf, &dev->task->rcvdt.fifo, count);
+       ret = copy_to_user_fm_fifo(buf, &dev->rcvdt.fifo, count);
 
-unlock_out:
-       devstate_unlock(dev);
 up_out:
-       mutex_unlock(&dev->read_mutex);
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
        return ret;
 }
 
-static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count,
-                                   loff_t *ppos)
+static ssize_t dsp_task_read_bk_psv(struct file *file, char __user *buf,
+                                   size_t count, loff_t *ppos)
 {
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        struct taskdev *dev = taskdev[minor];
-       struct rcvdt_bk_struct *rcvdt;
-       struct mbcmd mb;
-       unsigned char tid;
+       struct rcvdt_bk_struct *rcvdt = &dev->rcvdt.bk;
        int ret = 0;
 
        if (count == 0) {
@@ -932,53 +928,41 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count,
                return -EINVAL;
        }
 
-       if (taskdev_lock_interruptible(dev, &dev->read_mutex))
-               return -ERESTARTSYS;
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
-       tid = dev->task->tid;
-       devstate_unlock(dev);
+       if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+               return -ENODEV;
 
-       mbcmd_set(mb, MBCMD(BKREQ), tid, count/2);
-       dsp_mbcmd_send_and_wait(&mb, &dev->read_wait_q);
+       mbcompose_send_and_wait(BKREQ, dev->task->tid, count/2,
+                               &dev->read_wait_q);
 
-       if (signal_pending(current)) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
+       if (ipblink_empty(&rcvdt->link)) {
+               /* failure */
+               if (signal_pending(current))
+                       ret = -EINTR;
                goto up_out;
        }
-       rcvdt = &dev->task->rcvdt.bk;
-       /* signal or 0-byte send from DSP */
-       if (ipblink_empty(&rcvdt->link))
-               goto unlock_out;
 
        /*
         * We will not receive more than requested count.
         */
        if (sndtyp_pvt(dev->task->ttyp)) {
                /* private */
-               struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r;
+               struct ipbuf_p *ipbp = dev->task->ipbuf_pvt_r;
                size_t rcvcnt;
                void *src;
 
                if (dsp_mem_enable(ipbp) < 0) {
-                       ret = -ERESTARTSYS;
-                       goto unlock_out;
+                       ret = -EBUSY;
+                       goto up_out;
                }
                src = MKVIRT(ipbp->ah, ipbp->al);
                rcvcnt = ((unsigned long)ipbp->c) * 2;
                if (dsp_address_validate(src, rcvcnt, "task %s read buffer",
                                         dev->task->name) < 0) {
-                       ret = -ERESTARTSYS;
+                       ret = -EINVAL;
                        goto pv_out1;
                }
                if (dsp_mem_enable(src) < 0) {
-                       ret = -ERESTARTSYS;
+                       ret = -EBUSY;
                        goto pv_out1;
                }
                if (count > rcvcnt)
@@ -987,9 +971,7 @@ static ssize_t dsp_task_read_bk_psv(struct file *file, char *buf, size_t count,
                        ret = -EFAULT;
                        goto pv_out2;
                }
-               spin_lock(&rcvdt->link.lock);
                ipblink_del_pvt(&rcvdt->link);
-               spin_unlock(&rcvdt->link.lock);
                release_ipbuf_pvt(ipbp);
                ret = count;
 pv_out2:
@@ -998,44 +980,38 @@ pv_out1:
                dsp_mem_disable(ipbp);
        } else {
                /* global */
-               unsigned short bid = rcvdt->link.top;
-               struct ipbuf *ipbp = ipbuf[bid];
+               struct ipbuf_head *ipb_h = bid_to_ipbuf(rcvdt->link.top);
                size_t rcvcnt;
 
                if (dsp_mem_enable_ipbuf() < 0) {
-                       ret = -ERESTARTSYS;
-                       goto unlock_out;
+                       ret = -EBUSY;
+                       goto up_out;
                }
-               rcvcnt = ((unsigned long)ipbp->c) * 2;
+               rcvcnt = ((unsigned long)ipb_h->p->c) * 2;
                if (count > rcvcnt)
                        count = rcvcnt;
-               if (copy_to_user_dsp(buf, ipbp->d, count)) {
+               if (copy_to_user_dsp(buf, ipb_h->p->d, count)) {
                        ret = -EFAULT;
                        goto gb_out;
                }
-               spin_lock(&rcvdt->link.lock);
-               ipblink_del_top(&rcvdt->link, ipbuf);
-               spin_unlock(&rcvdt->link.lock);
-               unuse_ipbuf(bid);
+               ipblink_del_top(&rcvdt->link);
+               unuse_ipbuf(ipb_h);
                ret = count;
 gb_out:
                dsp_mem_disable_ipbuf();
        }
 
-unlock_out:
-       devstate_unlock(dev);
 up_out:
-       mutex_unlock(&dev->read_mutex);
+       taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
        return ret;
 }
 
-static ssize_t dsp_task_write_wd(struct file *file, const char *buf,
+static ssize_t dsp_task_write_wd(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        struct taskdev *dev = taskdev[minor];
-       unsigned short wd;
-       int have_devstate_lock = 0;
+       u16 wd;
        int ret = 0;
 
        if (count == 0) {
@@ -1049,41 +1025,26 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf,
                count = 2;
        }
 
-       if (taskdev_lock_interruptible(dev, &dev->write_mutex))
-               return -ERESTARTSYS;
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
-       have_devstate_lock = 1;
+       if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+               return -ENODEV;
 
-       if (dev->task->wsz == 0) {
+       if (dev->wsz == 0) {
                long current_state;
                DECLARE_WAITQUEUE(wait, current);
 
                add_wait_queue(&dev->write_wait_q, &wait);
                current_state = current->state;
                set_current_state(TASK_INTERRUPTIBLE);
-               if (dev->task->wsz == 0) {      /* last check */
-                       devstate_unlock(dev);
-                       have_devstate_lock = 0;
+               if (dev->wsz == 0)      /* last check */
                        schedule();
-               }
                set_current_state(current_state);
                remove_wait_queue(&dev->write_wait_q, &wait);
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
+               if (dev->wsz == 0) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
                        goto up_out;
                }
-               if (!have_devstate_lock) {
-                       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-                               ret = -ERESTARTSYS;
-                               goto up_out;
-                       }
-                       have_devstate_lock = 1;
-               }
-               if (dev->task->wsz == 0)        /* should not occur */
-                       goto up_out;
        }
 
        if (copy_from_user(&wd, buf, count)) {
@@ -1091,29 +1052,26 @@ static ssize_t dsp_task_write_wd(struct file *file, const char *buf,
                goto up_out;
        }
 
-       spin_lock(&dev->task->wsz_lock);
-       if (dsp_mbsend(MBCMD(WDSND), dev->task->tid, wd) < 0) {
-               spin_unlock(&dev->task->wsz_lock);
+       spin_lock(&dev->wsz_lock);
+       if (mbcompose_send(WDSND, dev->task->tid, wd) < 0) {
+               spin_unlock(&dev->wsz_lock);
                goto up_out;
        }
        ret = count;
        if (rcvtyp_acv(dev->task->ttyp))
-               dev->task->wsz = 0;
-       spin_unlock(&dev->task->wsz_lock);
+               dev->wsz = 0;
+       spin_unlock(&dev->wsz_lock);
 
 up_out:
-       if (have_devstate_lock)
-               devstate_unlock(dev);
-       mutex_unlock(&dev->write_mutex);
+       taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
        return ret;
 }
 
-static ssize_t dsp_task_write_bk(struct file *file, const char *buf,
+static ssize_t dsp_task_write_bk(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
 {
        unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
        struct taskdev *dev = taskdev[minor];
-       int have_devstate_lock = 0;
        int ret = 0;
 
        if (count == 0) {
@@ -1129,45 +1087,30 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf,
                return -EINVAL;
        }
 
-       if (taskdev_lock_interruptible(dev, &dev->write_mutex))
-               return -ERESTARTSYS;
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
-       have_devstate_lock = 1;
+       if (taskdev_lock_and_statelock_attached(dev, &dev->write_mutex))
+               return -ENODEV;
 
-       if (dev->task->wsz == 0) {
+       if (dev->wsz == 0) {
                long current_state;
                DECLARE_WAITQUEUE(wait, current);
 
                add_wait_queue(&dev->write_wait_q, &wait);
                current_state = current->state;
                set_current_state(TASK_INTERRUPTIBLE);
-               if (dev->task->wsz == 0) {      /* last check */
-                       devstate_unlock(dev);
-                       have_devstate_lock = 0;
+               if (dev->wsz == 0)      /* last check */
                        schedule();
-               }
                set_current_state(current_state);
                remove_wait_queue(&dev->write_wait_q, &wait);
-               if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
+               if (dev->wsz == 0) {
+                       /* failure */
+                       if (signal_pending(current))
+                               ret = -EINTR;
                        goto up_out;
                }
-               if (!have_devstate_lock) {
-                       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-                               ret = -ERESTARTSYS;
-                               goto up_out;
-                       }
-                       have_devstate_lock = 1;
-               }
-               if (dev->task->wsz == 0)        /* should not occur */
-                       goto up_out;
        }
 
-       if (count > dev->task->wsz)
-               count = dev->task->wsz;
+       if (count > dev->wsz)
+               count = dev->wsz;
 
        if (rcvtyp_pvt(dev->task->ttyp)) {
                /* private */
@@ -1175,17 +1118,17 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf,
                unsigned char *dst;
 
                if (dsp_mem_enable(ipbp) < 0) {
-                       ret = -ERESTARTSYS;
+                       ret = -EBUSY;
                        goto up_out;
                }
                dst = MKVIRT(ipbp->ah, ipbp->al);
                if (dsp_address_validate(dst, count, "task %s write buffer",
                                         dev->task->name) < 0) {
-                       ret = -ERESTARTSYS;
+                       ret = -EINVAL;
                        goto pv_out1;
                }
                if (dsp_mem_enable(dst) < 0) {
-                       ret = -ERESTARTSYS;
+                       ret = -EBUSY;
                        goto pv_out1;
                }
                if (copy_from_user_dsp(dst, buf, count)) {
@@ -1194,54 +1137,49 @@ static ssize_t dsp_task_write_bk(struct file *file, const char *buf,
                }
                ipbp->c = count/2;
                ipbp->s = dev->task->tid;
-               spin_lock(&dev->task->wsz_lock);
-               if (dsp_mbsend(MBCMD(BKSNDP), dev->task->tid, 0) == 0) {
+               spin_lock(&dev->wsz_lock);
+               if (mbcompose_send(BKSNDP, dev->task->tid, 0) == 0) {
                        if (rcvtyp_acv(dev->task->ttyp))
-                               dev->task->wsz = 0;
+                               dev->wsz = 0;
                        ret = count;
                }
-               spin_unlock(&dev->task->wsz_lock);
+               spin_unlock(&dev->wsz_lock);
 pv_out2:
                dsp_mem_disable(dst);
 pv_out1:
                dsp_mem_disable(ipbp);
        } else {
                /* global */
-               struct ipbuf *ipbp;
-               unsigned short bid;
+               struct ipbuf_head *ipb_h;
 
                if (dsp_mem_enable_ipbuf() < 0) {
-                       ret = -ERESTARTSYS;
+                       ret = -EBUSY;
                        goto up_out;
                }
-               bid = get_free_ipbuf(dev->task->tid);
-               if (bid == OMAP_DSP_BID_NULL)
+               if ((ipb_h = get_free_ipbuf(dev->task->tid)) == NULL)
                        goto gb_out;
-               ipbp = ipbuf[bid];
-               if (copy_from_user_dsp(ipbp->d, buf, count)) {
-                       release_ipbuf(bid);
+               if (copy_from_user_dsp(ipb_h->p->d, buf, count)) {
+                       release_ipbuf(ipb_h);
                        ret = -EFAULT;
                        goto gb_out;
                }
-               ipbp->c  = count/2;
-               ipbp->sa = dev->task->tid;
-               spin_lock(&dev->task->wsz_lock);
-               if (dsp_mbsend(MBCMD(BKSND), dev->task->tid, bid) == 0) {
+               ipb_h->p->c  = count/2;
+               ipb_h->p->sa = dev->task->tid;
+               spin_lock(&dev->wsz_lock);
+               if (mbcompose_send(BKSND, dev->task->tid, ipb_h->bid) == 0) {
                        if (rcvtyp_acv(dev->task->ttyp))
-                               dev->task->wsz = 0;
+                               dev->wsz = 0;
                        ret = count;
                        ipb_bsycnt_inc(&ipbcfg);
                } else
-                       release_ipbuf(bid);
-               spin_unlock(&dev->task->wsz_lock);
+                       release_ipbuf(ipb_h);
+               spin_unlock(&dev->wsz_lock);
 gb_out:
                dsp_mem_disable_ipbuf();
        }
 
 up_out:
-       if (have_devstate_lock)
-               devstate_unlock(dev);
-       mutex_unlock(&dev->write_mutex);
+       taskdev_unlock_and_stateunlock(dev, &dev->write_mutex);
        return ret;
 }
 
@@ -1252,78 +1190,42 @@ static unsigned int dsp_task_poll(struct file * file, poll_table * wait)
        struct dsptask *task = dev->task;
        unsigned int mask = 0;
 
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return 0;
        poll_wait(file, &dev->read_wait_q, wait);
        poll_wait(file, &dev->write_wait_q, wait);
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0)
-               return 0;
        if (sndtyp_psv(task->ttyp) ||
-           (sndtyp_wd(task->ttyp) && !fifo_empty(&task->rcvdt.fifo)) ||
-           (sndtyp_bk(task->ttyp) && !ipblink_empty(&task->rcvdt.bk.link)))
+           (sndtyp_wd(task->ttyp) && !fifo_empty(&dev->rcvdt.fifo)) ||
+           (sndtyp_bk(task->ttyp) && !ipblink_empty(&dev->rcvdt.bk.link)))
                mask |= POLLIN | POLLRDNORM;
-       if (task->wsz)
+       if (dev->wsz)
                mask |= POLLOUT | POLLWRNORM;
-       devstate_unlock(dev);
+       devstate_read_unlock(dev);
 
        return mask;
 }
 
-static int dsp_task_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg)
+static int dsp_tctl_issue(struct taskdev *dev, u16 cmd, int argc, u16 argv[])
 {
-       unsigned int minor = MINOR(inode->i_rdev);
-       struct taskdev *dev = taskdev[minor];
-       struct mbcmd mb;
-       unsigned char tid;
+       int tctl_argc;
        struct mb_exarg mbarg, *mbargp;
-       int mbargc;
-       unsigned short mbargv[1];
        int interactive;
-       int ret;
-
-       /* LOCK / UNLOCK operations */
-       switch (cmd) {
-       case OMAP_DSP_TASK_IOCTL_LOCK:
-               return taskdev_lock(dev);
-       case OMAP_DSP_TASK_IOCTL_UNLOCK:
-               return taskdev_unlock(dev);
-       }
-
-       /*
-        * actually only interractive commands need to lock
-        * the mutex, but here all commands do it for simplicity.
-        */
-       if (taskdev_lock_interruptible(dev, &dev->ioctl_mutex))
-               return -ERESTARTSYS;
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-               ret = -ERESTARTSYS;
-               goto up_out;
-       }
+       u8 tid;
+       int ret = 0;
 
-       if ((cmd >= 0x0080) && (cmd < 0x0100)) {
-               /*
-                * 0x0080 - 0x00ff
-                * reserved for backward compatibility
-                * user-defined TCTL commands: no arg, non-interactive
-                */
-               printk(KERN_WARNING "omapdsp: "
-                      "TCTL commands in 0x0080 - 0x0100 are obsolete.\n"
-                      "they won't be supported in the future.\n");
-               mbargc = 0;
-               interactive = 0;
-       } else if (cmd < 0x8000) {
+       if (cmd < 0x8000) {
                /*
-                * 0x0000 - 0x7fff (except 0x0080 - 0x00ff)
+                * 0x0000 - 0x7fff
                 * system reserved TCTL commands
                 */
                switch (cmd) {
-               case OMAP_DSP_MBCMD_TCTL_TEN:
-               case OMAP_DSP_MBCMD_TCTL_TDIS:
-                       mbargc = 0;
+               case TCTL_TEN:
+               case TCTL_TDIS:
+                       tctl_argc = 0;
                        interactive = 0;
                        break;
                default:
-                       ret = -ENOIOCTLCMD;
-                       goto unlock_out;
+                       return -EINVAL;
                }
        }
        /*
@@ -1332,94 +1234,123 @@ static int dsp_task_ioctl(struct inode *inode, struct file *file,
         */
        else if (cmd < 0x8100) {
                /* 0x8000-0x80ff: no arg, non-interactive */
-               mbargc = 0;
+               tctl_argc = 0;
                interactive = 0;
        } else if (cmd < 0x8200) {
                /* 0x8100-0x81ff: 1 arg, non-interactive */
-               mbargc = 1;
-               mbargv[0] = arg & 0xffff;
+               tctl_argc = 1;
                interactive = 0;
        } else if (cmd < 0x9000) {
                /* 0x8200-0x8fff: reserved */
-               ret = -ENOIOCTLCMD;
-               goto unlock_out;
+               return -EINVAL;
        } else if (cmd < 0x9100) {
                /* 0x9000-0x90ff: no arg, interactive */
-               mbargc = 0;
+               tctl_argc = 0;
                interactive = 1;
        } else if (cmd < 0x9200) {
                /* 0x9100-0x91ff: 1 arg, interactive */
-               mbargc = 1;
-               mbargv[0] = arg & 0xffff;
+               tctl_argc = 1;
                interactive = 1;
-       } else if (cmd < 0x10000) {
-               /* 0x9200-0xffff: reserved */
-               ret =  -ENOIOCTLCMD;
-               goto unlock_out;
        } else {
-               /*
-                * 0x10000 -
-                * non TCTL ioctls
-                */
-               switch (cmd) {
-               case OMAP_DSP_TASK_IOCTL_BFLSH:
-                       ret = dsp_task_flush_buf(dev->task);
-                       break;
-               case OMAP_DSP_TASK_IOCTL_SETBSZ:
-                       ret = dsp_task_set_fifosz(dev->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 unlock_out;
+               /* 0x9200-0xffff: reserved */
+               return -EINVAL;
        }
 
+       /*
+        * if argc < 0, use tctl_argc as is.
+        * if argc >= 0, check arg count.
+        */
+       if ((argc >= 0) && (argc != tctl_argc))
+               return -EINVAL;
+
        /*
         * issue TCTL
         */
+       if (taskdev_lock_interruptible(dev, &dev->tctl_mutex))
+               return -EINTR;
+
        tid = dev->task->tid;
-       mbcmd_set(mb, MBCMD(TCTL), tid, cmd);
-       if (mbargc > 0) {
-               mbarg.argc = mbargc;
+       if (tctl_argc > 0) {
+               mbarg.argc = tctl_argc;
                mbarg.tid  = tid;
-               mbarg.argv = mbargv;
+               mbarg.argv = argv;
                mbargp = &mbarg;
        } else
                mbargp = NULL;
 
        if (interactive) {
-               dev->task->tctl_stat = -ERESTARTSYS;
-               devstate_unlock(dev);
+               dev->tctl_stat = -EINVAL;
 
-               dsp_mbcmd_send_and_wait_exarg(&mb, mbargp, &dev->ioctl_wait_q);
+               mbcompose_send_and_wait_exarg(TCTL, tid, cmd, mbargp,
+                                             &dev->tctl_wait_q);
                if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
-                       goto up_out;
-               }
-               if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0) {
-                       ret = -ERESTARTSYS;
+                       ret = -EINTR;
                        goto up_out;
                }
-               ret = dev->task->tctl_stat;
-               if (ret < 0) {
+               if ((ret = dev->tctl_stat) < 0) {
                        printk(KERN_ERR "omapdsp: TCTL not responding.\n");
-                       goto unlock_out;
+                       goto up_out;
                }
-       } else {
-               dsp_mbcmd_send_exarg(&mb, mbargp);
+       } else
+               mbcompose_send_exarg(TCTL, tid, cmd, mbargp);
+
+up_out:
+       mutex_unlock(&dev->tctl_mutex);
+       return ret;
+}
+
+static int 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];
+       int ret;
+
+       if (cmd < 0x10000) {
+               /* issue TCTL */
+               u16 mbargv[1];
+
+               mbargv[0] = arg & 0xffff;
+               return dsp_tctl_issue(dev, cmd, -1, mbargv);
+       }
+
+       /* non TCTL ioctls */
+       switch (cmd) {
+
+       case TASK_IOCTL_LOCK:
+               ret = taskdev_lock(dev);
+               break;
+
+       case TASK_IOCTL_UNLOCK:
+               ret = taskdev_unlock(dev);
+               break;
+
+       case TASK_IOCTL_BFLSH:
+               if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+                       return -ENODEV;
+               ret = taskdev_flush_buf(dev);
+               taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+               break;
+
+       case TASK_IOCTL_SETBSZ:
+               if (taskdev_lock_and_statelock_attached(dev, &dev->read_mutex))
+                       return -ENODEV;
+               ret = taskdev_set_fifosz(dev, arg);
+               taskdev_unlock_and_stateunlock(dev, &dev->read_mutex);
+               break;
+
+       case TASK_IOCTL_GETNAME:
                ret = 0;
+               if (copy_to_user((void __user *)arg, dev->name,
+                                strlen(dev->name) + 1))
+                       ret = -EFAULT;
+               break;
+
+       default:
+               ret = -ENOIOCTLCMD;
+
        }
 
-unlock_out:
-       devstate_unlock(dev);
-up_out:
-       mutex_unlock(&dev->ioctl_mutex);
        return ret;
 }
 
@@ -1429,7 +1360,7 @@ static void dsp_task_mmap_open(struct vm_area_struct *vma)
        struct dsptask *task;
        size_t len = vma->vm_end - vma->vm_start;
 
-       BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED));
+       BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
        task = dev->task;
        exmap_use(task->map_base, len);
 }
@@ -1440,7 +1371,7 @@ static void dsp_task_mmap_close(struct vm_area_struct *vma)
        struct dsptask *task;
        size_t len = vma->vm_end - vma->vm_start;
 
-       BUG_ON(!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED));
+       BUG_ON(!(dev->state & TASKDEV_ST_ATTACHED));
        task = dev->task;
        exmap_unuse(task->map_base, len);
 }
@@ -1471,8 +1402,8 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
        struct dsptask *task;
        int ret = 0;
 
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED) < 0)
-               return -ERESTARTSYS;
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
        task = dev->task;
 
        /*
@@ -1525,7 +1456,7 @@ static int dsp_task_mmap(struct file *filp, struct vm_area_struct *vma)
        exmap_use(task->map_base, vma->vm_end - vma->vm_start);
 
 unlock_out:
-       devstate_unlock(dev);
+       devstate_read_unlock(dev);
        return ret;
 }
 
@@ -1537,49 +1468,85 @@ static int dsp_task_open(struct inode *inode, struct file *file)
 
        if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL))
                return -ENODEV;
-       if (devstate_lock(dev, OMAP_DSP_DEVSTATE_NOTASK |
-                              OMAP_DSP_DEVSTATE_ATTACHED) < 0)
-               return -ERESTARTSYS;
-#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN
-       if (dev->usecount > 0) {
-               ret = -EBUSY;
-               goto unlock_out;
-       }
-#endif
 
-       if (dev->state & OMAP_DSP_DEVSTATE_NOTASK) {
-               dev->state = OMAP_DSP_DEVSTATE_ADDREQ;
-               /* wake up twch daemon for tadd */
-               dsp_twch_touch();
-               devstate_unlock(dev);
-               if (devstate_lock(dev, OMAP_DSP_DEVSTATE_ATTACHED |
-                                      OMAP_DSP_DEVSTATE_ADDFAIL) < 0) {
-                       spin_lock(&dev->state_lock);
-                       if (dev->state & OMAP_DSP_DEVSTATE_ADDREQ)
-                               dev->state = OMAP_DSP_DEVSTATE_NOTASK;
-                       spin_unlock(&dev->state_lock);
-                       return -ERESTARTSYS;
-               }
-               if (dev->state & OMAP_DSP_DEVSTATE_ADDFAIL) {
-                       printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
-                              dev->name);
-                       ret = -EBUSY;
-                       dev->state = OMAP_DSP_DEVSTATE_NOTASK;
-                       wake_up_interruptible_all(&dev->state_wait_q);
-                       goto unlock_out;
+restart:
+       mutex_lock(&dev->usecount_lock);
+       down_write(&dev->state_sem);
+
+       /* state can be NOTASK, ATTACHED/FREEZED, KILLING, GARBAGE or INVALID here. */
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
+               case TASKDEV_ST_NOTASK:
+                       break;
+               case TASKDEV_ST_ATTACHED:
+                       goto attached;
+
+               case TASKDEV_ST_INVALID:
+                       up_write(&dev->state_sem);
+                       mutex_unlock(&dev->usecount_lock);
+                       return -ENODEV;
+
+               case TASKDEV_ST_FREEZED:
+               case TASKDEV_ST_KILLING:
+               case TASKDEV_ST_GARBAGE:
+               case TASKDEV_ST_DELREQ:
+                       /* on the kill process. wait until it becomes NOTASK. */
+                       up_write(&dev->state_sem);
+                       mutex_unlock(&dev->usecount_lock);
+                       if (devstate_write_lock(dev, TASKDEV_ST_NOTASK) < 0)
+                               return -EINTR;
+                       devstate_write_unlock(dev);
+                       goto restart;
+       }
+
+       /* NOTASK */
+       dev->state = TASKDEV_ST_ADDREQ;
+       /* wake up twch daemon for tadd */
+       dsp_twch_touch();
+       up_write(&dev->state_sem);
+       if (devstate_write_lock(dev, TASKDEV_ST_ATTACHED |
+                                    TASKDEV_ST_ADDFAIL) < 0) {
+               /* cancelled */
+               if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
+                       mutex_unlock(&dev->usecount_lock);
+                       /* out of control ??? */
+                       return -EINTR;
                }
+               dev->state = TASKDEV_ST_NOTASK;
+               ret = -EINTR;
+               goto change_out;
+       }
+       if (dev->state & TASKDEV_ST_ADDFAIL) {
+               printk(KERN_ERR "omapdsp: task attach failed for %s!\n",
+                      dev->name);
+               ret = -EBUSY;
+               dev->state = TASKDEV_ST_NOTASK;
+               goto change_out;
        }
 
-       /* state_lock covers usecount, proc_list as well. */
+attached:
+       /* ATTACHED */
+#ifndef CONFIG_OMAP_DSP_TASK_MULTIOPEN
+       if (dev->usecount > 0) {
+               up_write(&dev->state_sem);
+               return -EBUSY;
+       }
+#endif
        dev->usecount++;
-       proc_list_add(&dev->proc_list, current);
+       proc_list_add(&dev->proc_list_lock, &dev->proc_list, current, file);
        file->f_op = &dev->fops;
-       devstate_unlock(dev);
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
 
+#ifdef DSP_PTE_FREE    /* not used currently. */
+       dsp_map_update(current);
+       dsp_cur_users_add(current);
+#endif /* DSP_PTE_FREE */
        return 0;
 
-unlock_out:
-       devstate_unlock(dev);
+change_out:
+       wake_up_interruptible_all(&dev->state_wait_q);
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
        return ret;
 }
 
@@ -1588,39 +1555,48 @@ static int dsp_task_release(struct inode *inode, struct file *file)
        unsigned int minor = MINOR(inode->i_rdev);
        struct taskdev *dev = taskdev[minor];
 
-       /* state_lock covers usecount, proc_list as well. */
-       spin_lock(&dev->state_lock);
+#ifdef DSP_PTE_FREE    /* not used currently. */
+       dsp_cur_users_del(current);
+#endif /* DSP_PTE_FREE */
+
+       if (has_taskdev_lock(dev))
+               taskdev_unlock(dev);
+
+       proc_list_del(&dev->proc_list_lock, &dev->proc_list, current, file);
+       mutex_lock(&dev->usecount_lock);
+       if (--dev->usecount > 0) {
+               /* other processes are using this device. no state change. */
+               mutex_unlock(&dev->usecount_lock);
+               return 0;
+       }
+
+       /* usecount == 0 */
+       down_write(&dev->state_sem);
 
-       /* state can be ATTACHED, KILLING or GARBAGE here. */
-       switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) {
+       /* state can be ATTACHED/FREEZED, KILLING or GARBAGE here. */
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
 
-       case OMAP_DSP_DEVSTATE_KILLING:
-               dev->usecount--;
+       case TASKDEV_ST_KILLING:
                break;
 
-       case OMAP_DSP_DEVSTATE_GARBAGE:
-               if(--dev->usecount == 0) {
-                       dev->state = OMAP_DSP_DEVSTATE_NOTASK;
-                       wake_up_interruptible_all(&dev->state_wait_q);
-               }
+       case TASKDEV_ST_GARBAGE:
+               dev->state = TASKDEV_ST_NOTASK;
+               wake_up_interruptible_all(&dev->state_wait_q);
                break;
 
-       case OMAP_DSP_DEVSTATE_ATTACHED:
-               if (dev->lock_pid == current->pid)
-                       taskdev_unlock(dev);
-               proc_list_del(&dev->proc_list, current);
-               if (--dev->usecount == 0) {
-                       if (minor >= n_task) {  /* dynamic task */
-                               dev->state = OMAP_DSP_DEVSTATE_DELREQ;
-                               /* wake up twch daemon for tdel */
-                               dsp_twch_touch();
-                       }
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
+               if (is_dynamic_task(minor)) {
+                       dev->state = TASKDEV_ST_DELREQ;
+                       /* wake up twch daemon for tdel */
+                       dsp_twch_touch();
                }
                break;
 
        }
 
-       spin_unlock(&dev->state_lock);
+       up_write(&dev->state_sem);
+       mutex_unlock(&dev->usecount_lock);
        return 0;
 }
 
@@ -1632,102 +1608,166 @@ int dsp_mkdev(char *name)
        struct taskdev *dev;
        int status;
        unsigned char minor;
+       int ret;
 
-       if (!dsp_is_ready()) {
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
                printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
                return -EINVAL;
        }
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       /* naming check */
+       for (minor = 0; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
+                       printk(KERN_ERR
+                              "omapdsp: task device name %s is already "
+                              "in use.\n", name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       /* find free minor number */
        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;
+       ret = -EBUSY;
+       goto out;
 
 do_make:
-       if ((dev = kmalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL)
-               return -ENOMEM;
-       memset(dev, 0, sizeof(struct taskdev));
+       if ((dev = kzalloc(sizeof(struct taskdev), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
        if ((status = taskdev_init(dev, name, minor)) < 0) {
                kfree(dev);
-               return status;
+               ret = status;
+               goto out;
        }
-       return minor;
+       ret = minor;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
 }
 
 int dsp_rmdev(char *name)
 {
        unsigned char minor;
+       int status;
        int ret;
 
-       if (!dsp_is_ready()) {
+       if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
                printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
                return -EINVAL;
        }
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       /* find in dynamic devices */
        for (minor = n_task; minor < TASKDEV_MAX; minor++) {
+               if (taskdev[minor] && !strcmp(taskdev[minor]->name, name))
+                       goto do_remove;
+       }
+
+       /* find in static devices */
+       for (minor = 0; minor < n_task; minor++) {
                if (taskdev[minor] && !strcmp(taskdev[minor]->name, name)) {
-                       if ((ret = dsp_rmdev_minor(minor)) < 0)
-                               return ret;
-                       return minor;
+                       printk(KERN_ERR
+                              "omapdsp: task device %s is static.\n", name);
+                       ret = -EINVAL;
+                       goto out;
                }
        }
+
+       printk(KERN_ERR "omapdsp: task device %s not found.\n", name);
        return -EINVAL;
+
+do_remove:
+       ret = minor;
+       if ((status = dsp_rmdev_minor(minor)) < 0)
+               ret = status;
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
 }
 
 static int dsp_rmdev_minor(unsigned char minor)
 {
        struct taskdev *dev = taskdev[minor];
 
-       spin_lock(&dev->state_lock);
+       while (!down_write_trylock(&dev->state_sem)) {
+               down_read(&dev->state_sem);
+               if (dev->state & (TASKDEV_ST_ATTACHED |
+                                 TASKDEV_ST_FREEZED)) {
+                       /*
+                        * task is working. kill it.
+                        * ATTACHED -> FREEZED can be changed under
+                        * down_read of state_sem..
+                        */
+                       dev->state = TASKDEV_ST_FREEZED;
+                       wake_up_interruptible_all(&dev->read_wait_q);
+                       wake_up_interruptible_all(&dev->write_wait_q);
+                       wake_up_interruptible_all(&dev->tctl_wait_q);
+               }
+               up_read(&dev->state_sem);
+               schedule();
+       }
 
-       switch (dev->state & OMAP_DSP_DEVSTATE_STATE_MASK) {
+       switch (dev->state & TASKDEV_ST_STATE_MASK) {
 
-       case OMAP_DSP_DEVSTATE_NOTASK:
+       case TASKDEV_ST_NOTASK:
                /* fine */
-               break;
+               goto notask;
 
-       case OMAP_DSP_DEVSTATE_ATTACHED:
+       case TASKDEV_ST_ATTACHED:
+       case TASKDEV_ST_FREEZED:
                /* task is working. kill it. */
-               dev->state = OMAP_DSP_DEVSTATE_KILLING;
-               proclist_send_sigbus(&dev->proc_list);
-               spin_unlock(&dev->state_lock);
-               dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL);
+               dev->state = TASKDEV_ST_KILLING;
+               up_write(&dev->state_sem);
+               dsp_tdel_bh(dev, TDEL_KILL);
                goto invalidate;
 
-       case OMAP_DSP_DEVSTATE_ADDREQ:
+       case TASKDEV_ST_ADDREQ:
                /* open() is waiting. drain it. */
-               dev->state = OMAP_DSP_DEVSTATE_ADDFAIL;
+               dev->state = TASKDEV_ST_ADDFAIL;
                wake_up_interruptible_all(&dev->state_wait_q);
                break;
 
-       case OMAP_DSP_DEVSTATE_DELREQ:
+       case TASKDEV_ST_DELREQ:
                /* nobody is waiting. */
-               dev->state = OMAP_DSP_DEVSTATE_NOTASK;
+               dev->state = TASKDEV_ST_NOTASK;
                wake_up_interruptible_all(&dev->state_wait_q);
                break;
 
-       case OMAP_DSP_DEVSTATE_ADDING:
-       case OMAP_DSP_DEVSTATE_DELING:
-       case OMAP_DSP_DEVSTATE_KILLING:
-       case OMAP_DSP_DEVSTATE_GARBAGE:
-       case OMAP_DSP_DEVSTATE_ADDFAIL:
+       case TASKDEV_ST_ADDING:
+       case TASKDEV_ST_DELING:
+       case TASKDEV_ST_KILLING:
+       case TASKDEV_ST_GARBAGE:
+       case TASKDEV_ST_ADDFAIL:
                /* transient state. wait for a moment. */
                break;
 
        }
 
-       spin_unlock(&dev->state_lock);
+       up_write(&dev->state_sem);
 
 invalidate:
        /* wait for some time and hope the state is settled */
-       devstate_lock_timeout(dev, OMAP_DSP_DEVSTATE_NOTASK, HZ);
-       if (!(dev->state & OMAP_DSP_DEVSTATE_NOTASK)) {
+       devstate_read_lock_timeout(dev, TASKDEV_ST_NOTASK, 5 * HZ);
+       if (!(dev->state & TASKDEV_ST_NOTASK)) {
                printk(KERN_WARNING
                       "omapdsp: illegal device state (%s) on rmdev %s.\n",
                       devstate_name(dev->state), dev->name);
        }
-       dev->state = OMAP_DSP_DEVSTATE_INVALID;
-       devstate_unlock(dev);
+notask:
+       dev->state = TASKDEV_ST_INVALID;
+       devstate_read_unlock(dev);
 
        taskdev_delete(minor);
        kfree(dev);
@@ -1749,25 +1789,26 @@ static void dsptask_dev_release(struct device *dev)
 
 static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
 {
-       struct class_device *cdev;
-
        taskdev[minor] = dev;
 
+       spin_lock_init(&dev->proc_list_lock);
        INIT_LIST_HEAD(&dev->proc_list);
        init_waitqueue_head(&dev->read_wait_q);
        init_waitqueue_head(&dev->write_wait_q);
-       init_waitqueue_head(&dev->ioctl_wait_q);
+       init_waitqueue_head(&dev->tctl_wait_q);
        mutex_init(&dev->read_mutex);
        mutex_init(&dev->write_mutex);
-       mutex_init(&dev->ioctl_mutex);
+       mutex_init(&dev->tctl_mutex);
        mutex_init(&dev->lock);
+       spin_lock_init(&dev->wsz_lock);
+       dev->tctl_ret = -EINVAL;
        dev->lock_pid = 0;
 
-       strncpy(dev->name, name, OMAP_DSP_TNM_LEN);
-       dev->name[OMAP_DSP_TNM_LEN-1] = '\0';
-       dev->state = (minor < n_task) ? OMAP_DSP_DEVSTATE_ATTACHED :
-                                       OMAP_DSP_DEVSTATE_NOTASK;
+       strncpy(dev->name, name, TNM_LEN);
+       dev->name[TNM_LEN-1] = '\0';
+       dev->state = (minor < n_task) ? TASKDEV_ST_ATTACHED : TASKDEV_ST_NOTASK;
        dev->usecount = 0;
+       mutex_init(&dev->usecount_lock);
        memcpy(&dev->fops, &dsp_task_fops, sizeof(struct file_operations));
 
        dev->dev.parent = &dsp_device.dev;
@@ -1778,12 +1819,12 @@ static int taskdev_init(struct taskdev *dev, char *name, unsigned char minor)
        device_create_file(&dev->dev, &dev_attr_devname);
        device_create_file(&dev->dev, &dev_attr_devstate);
        device_create_file(&dev->dev, &dev_attr_proc_list);
-       cdev = class_device_create(dsp_task_class, NULL,
-                                  MKDEV(OMAP_DSP_TASK_MAJOR, minor),
-                                  NULL, "dsptask%d", minor);
+       class_device_create(dsp_task_class, NULL,
+                           MKDEV(OMAP_DSP_TASK_MAJOR, minor),
+                           NULL, "dsptask%d", minor);
 
        init_waitqueue_head(&dev->state_wait_q);
-       spin_lock_init(&dev->state_lock);
+       init_rwsem(&dev->state_sem);
 
        return 0;
 }
@@ -1799,16 +1840,14 @@ static void taskdev_delete(unsigned char minor)
        device_remove_file(&dev->dev, &dev_attr_proc_list);
        class_device_destroy(dsp_task_class, MKDEV(OMAP_DSP_TASK_MAJOR, minor));
        device_unregister(&dev->dev);
-       proc_list_flush(&dev->proc_list);
+       proc_list_flush(&dev->proc_list_lock, &dev->proc_list);
        taskdev[minor] = NULL;
 }
 
-static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
+static int taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
 {
-       unsigned short ttyp = task->ttyp;
+       u16 ttyp = task->ttyp;
 
-       dev->task = task;
-       task->dev = dev;
        dev->fops.read =
                sndtyp_acv(ttyp) ?
                        sndtyp_wd(ttyp) ? dsp_task_read_wd_acv:
@@ -1816,9 +1855,31 @@ static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
                /* sndtyp_psv */
                        sndtyp_wd(ttyp) ? dsp_task_read_wd_psv:
                        /* sndtyp_bk */   dsp_task_read_bk_psv;
+       if (sndtyp_wd(ttyp)) {
+               /* word */
+               size_t fifosz;
+
+               fifosz = sndtyp_psv(ttyp) ? 2 : /* passive */
+                                           32; /* active */
+               if (init_fifo(&dev->rcvdt.fifo, fifosz) < 0) {
+                       printk(KERN_ERR
+                              "omapdsp: unable to allocate receive buffer. "
+                              "(%d bytes for %s)\n", fifosz, dev->name);
+                       return -ENOMEM;
+               }
+       } else {
+               /* block */
+               INIT_IPBLINK(&dev->rcvdt.bk.link);
+               dev->rcvdt.bk.rp = 0;
+       }
+
        dev->fops.write =
                rcvtyp_wd(ttyp) ? dsp_task_write_wd:
                /* rcvbyp_bk */   dsp_task_write_bk;
+       dev->wsz = rcvtyp_acv(ttyp) ? 0 :               /* active */
+                  rcvtyp_wd(ttyp)  ? 2 :               /* passive word */
+                                     ipbcfg.lsz*2;     /* passive block */
+
        if (task->map_length)
                dev->fops.mmap = dsp_task_mmap;
 
@@ -1832,11 +1893,16 @@ static void taskdev_attach_task(struct taskdev *dev, struct dsptask *task)
        device_create_file(&dev->dev, &dev_attr_wsz);
        if (task->map_length)
                device_create_file(&dev->dev, &dev_attr_mmap);
+
+       dev->task = task;
+       task->dev = dev;
+
+       return 0;
 }
 
 static void taskdev_detach_task(struct taskdev *dev)
 {
-       unsigned short ttyp = dev->task->ttyp;
+       u16 ttyp = dev->task->ttyp;
 
        device_remove_file(&dev->dev, &dev_attr_taskname);
        device_remove_file(&dev->dev, &dev_attr_ttyp);
@@ -1849,52 +1915,46 @@ static void taskdev_detach_task(struct taskdev *dev)
        if (dev->task->map_length)
                device_remove_file(&dev->dev, &dev_attr_mmap);
 
-       if (dev->task) {
-               dev->task = NULL;
-               dev->fops.read = NULL;
-               dev->fops.write = NULL;
-               printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name);
-       }
+       dev->fops.read = NULL;
+       taskdev_flush_buf(dev);
+       if (sndtyp_wd(ttyp))
+               free_fifo(&dev->rcvdt.fifo);
+
+       dev->fops.write = NULL;
+       dev->wsz = 0;
+
+       printk(KERN_INFO "omapdsp: taskdev %s disabled.\n", dev->name);
+       dev->task = NULL;
 }
 
 /*
  * tadd / tdel / tkill
  */
-int dsp_tadd(unsigned char minor, unsigned long adr)
+static int dsp_tadd(struct taskdev *dev, dsp_long_t adr)
 {
-       struct taskdev *dev;
        struct dsptask *task;
-       struct mbcmd mb;
        struct mb_exarg arg;
-       unsigned char tid, tid_response;
-       unsigned short argv[2];
-       int ret = minor;
-
-       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
-               printk(KERN_ERR
-                      "omapdsp: no task device with minor %d\n", minor);
-               return -EINVAL;
-       }
+       u8 tid, tid_response;
+       u16 argv[2];
+       int ret = 0;
 
-       spin_lock(&dev->state_lock);
-       if (!(dev->state & OMAP_DSP_DEVSTATE_ADDREQ)) {
+       if (!devstate_write_lock_and_test(dev, TASKDEV_ST_ADDREQ)) {
                printk(KERN_ERR
                       "omapdsp: taskdev %s is not requesting for tadd. "
                       "(state is %s)\n", dev->name, devstate_name(dev->state));
-               spin_unlock(&dev->state_lock);
                return -EINVAL;
        }
-       dev->state = OMAP_DSP_DEVSTATE_ADDING;
-       spin_unlock(&dev->state_lock);
+       dev->state = TASKDEV_ST_ADDING;
+       devstate_write_unlock(dev);
 
-       if (adr == OMAP_DSP_TADD_ABORTADR) {
+       if (adr == TADD_ABORTADR) {
                /* aborting tadd intentionally */
                printk(KERN_INFO "omapdsp: tadd address is ABORTADR.\n");
                goto fail_out;
        }
        if (adr >= DSPSPACE_SIZE) {
                printk(KERN_ERR
-                      "omapdsp: illegal address 0x%08lx for tadd\n", adr);
+                      "omapdsp: illegal address 0x%08x for tadd\n", adr);
                ret = -EINVAL;
                goto fail_out;
        }
@@ -1904,13 +1964,12 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
        argv[1] = adr & 0xffff; /* addrl */
 
        if (mutex_lock_interruptible(&cfg_lock)) {
-               ret = -ERESTARTSYS;
+               ret = -EINTR;
                goto fail_out;
        }
-       cfg_tid = OMAP_DSP_TID_ANON;
-       cfg_cmd = MBCMD(TADD);
-       mbcmd_set(mb, MBCMD(TADD), 0, 0);
-       arg.tid  = OMAP_DSP_TID_ANON;
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TADD;
+       arg.tid  = TID_ANON;
        arg.argc = 2;
        arg.argv = argv;
 
@@ -1919,14 +1978,14 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
                ret = -EBUSY;
                goto fail_out;
        }
-       dsp_mbcmd_send_and_wait_exarg(&mb, &arg, &cfg_wait_q);
+       mbcompose_send_and_wait_exarg(TADD, 0, 0, &arg, &cfg_wait_q);
 
        tid = cfg_tid;
-       cfg_tid = OMAP_DSP_TID_ANON;
+       cfg_tid = TID_ANON;
        cfg_cmd = 0;
        mutex_unlock(&cfg_lock);
 
-       if (tid == OMAP_DSP_TID_ANON) {
+       if (tid == TID_ANON) {
                printk(KERN_ERR "omapdsp: tadd failed!\n");
                ret = -EINVAL;
                goto fail_out;
@@ -1936,15 +1995,13 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
                ret = -EINVAL;
                goto fail_out;
        }
-       if ((task = kmalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
+       if ((task = kzalloc(sizeof(struct dsptask), GFP_KERNEL)) == NULL) {
                ret = -ENOMEM;
                goto del_out;
        }
-       memset(task, 0, sizeof(struct dsptask));
 
        if ((ret = dsp_task_config(task, tid)) < 0)
                goto free_out;
-       taskdev_attach_task(dev, task);
 
        if (strcmp(dev->name, task->name)) {
                printk(KERN_ERR
@@ -1954,11 +2011,14 @@ int dsp_tadd(unsigned char minor, unsigned long adr)
                goto free_out;
        }
 
+       if ((ret = taskdev_attach_task(dev, task)) < 0)
+               goto free_out;
+
        dsp_task_init(task);
        printk(KERN_INFO "omapdsp: taskdev %s enabled.\n", dev->name);
-       dev->state = OMAP_DSP_DEVSTATE_ATTACHED;
+       dev->state = TASKDEV_ST_ATTACHED;
        wake_up_interruptible_all(&dev->state_wait_q);
-       return minor;
+       return 0;
 
 free_out:
        kfree(task);
@@ -1966,19 +2026,18 @@ free_out:
 del_out:
        printk(KERN_ERR "omapdsp: deleting the task...\n");
 
-       dev->state = OMAP_DSP_DEVSTATE_DELING;
+       dev->state = TASKDEV_ST_DELING;
 
        if (mutex_lock_interruptible(&cfg_lock)) {
                printk(KERN_ERR "omapdsp: aborting tdel process. "
                                "DSP side could be corrupted.\n");
                goto fail_out;
        }
-       cfg_tid = OMAP_DSP_TID_ANON;
-       cfg_cmd = MBCMD(TDEL);
-       mbcmd_set(mb, MBCMD(TDEL), tid, OMAP_DSP_MBCMD_TDEL_KILL);
-       dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TDEL;
+       mbcompose_send_and_wait(TDEL, tid, TDEL_KILL, &cfg_wait_q);
        tid_response = cfg_tid;
-       cfg_tid = OMAP_DSP_TID_ANON;
+       cfg_tid = TID_ANON;
        cfg_cmd = 0;
        mutex_unlock(&cfg_lock);
 
@@ -1987,84 +2046,161 @@ del_out:
                                "DSP side could be corrupted.\n");
 
 fail_out:
-       dev->state = OMAP_DSP_DEVSTATE_ADDFAIL;
+       dev->state = TASKDEV_ST_ADDFAIL;
        wake_up_interruptible_all(&dev->state_wait_q);
        return ret;
 }
 
-int dsp_tdel(unsigned char minor)
+int dsp_tadd_minor(unsigned char minor, dsp_long_t adr)
 {
        struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
 
        if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
                printk(KERN_ERR
                       "omapdsp: no task device with minor %d\n", minor);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
-       spin_lock(&dev->state_lock);
-       if (!(dev->state & OMAP_DSP_DEVSTATE_DELREQ)) {
+       ret = minor;
+       if ((status = dsp_tadd(dev, adr)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tdel(struct taskdev *dev)
+{
+       if (!devstate_write_lock_and_test(dev, TASKDEV_ST_DELREQ)) {
                printk(KERN_ERR
                       "omapdsp: taskdev %s is not requesting for tdel. "
                       "(state is %s)\n", dev->name, devstate_name(dev->state));
-               spin_unlock(&dev->state_lock);
                return -EINVAL;
        }
-       dev->state = OMAP_DSP_DEVSTATE_DELING;
-       spin_unlock(&dev->state_lock);
+       dev->state = TASKDEV_ST_DELING;
+       devstate_write_unlock(dev);
 
-       return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_SAFE);
+       return dsp_tdel_bh(dev, TDEL_SAFE);
 }
 
-int dsp_tkill(unsigned char minor)
+int dsp_tdel_minor(unsigned char minor)
 {
        struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
 
        if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
                printk(KERN_ERR
                       "omapdsp: no task device with minor %d\n", minor);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
-       spin_lock(&dev->state_lock);
-       if (!(dev->state & OMAP_DSP_DEVSTATE_ATTACHED)) {
+
+       ret = minor;
+       if ((status = dsp_tdel(dev)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tkill(struct taskdev *dev)
+{
+       while (!down_write_trylock(&dev->state_sem)) {
+               if (!devstate_read_lock_and_test(dev, (TASKDEV_ST_ATTACHED |
+                                                      TASKDEV_ST_FREEZED))) {
+                       printk(KERN_ERR
+                              "omapdsp: task has not been attached for "
+                              "taskdev %s\n", dev->name);
+                       return -EINVAL;
+               }
+               /* ATTACHED -> FREEZED can be changed under read semaphore. */
+               dev->state = TASKDEV_ST_FREEZED;
+               wake_up_interruptible_all(&dev->read_wait_q);
+               wake_up_interruptible_all(&dev->write_wait_q);
+               wake_up_interruptible_all(&dev->tctl_wait_q);
+               devstate_read_unlock(dev);
+               schedule();
+       }
+
+       if (!(dev->state & (TASKDEV_ST_ATTACHED |
+                           TASKDEV_ST_FREEZED))) {
                printk(KERN_ERR
                       "omapdsp: task has not been attached for taskdev %s\n",
                       dev->name);
-               spin_unlock(&dev->state_lock);
+               devstate_write_unlock(dev);
                return -EINVAL;
        }
-       dev->state = OMAP_DSP_DEVSTATE_KILLING;
-       proclist_send_sigbus(&dev->proc_list);
-       spin_unlock(&dev->state_lock);
+       if (!is_dynamic_task(dev->task->tid)) {
+               printk(KERN_ERR "omapdsp: task %s is not a dynamic task.\n",
+                      dev->name);
+               devstate_write_unlock(dev);
+               return -EINVAL;
+       }
+       dev->state = TASKDEV_ST_KILLING;
+       devstate_write_unlock(dev);
 
-       return dsp_tdel_bh(minor, OMAP_DSP_MBCMD_TDEL_KILL);
+       return dsp_tdel_bh(dev, TDEL_KILL);
 }
 
-static int dsp_tdel_bh(unsigned char minor, unsigned short type)
+int dsp_tkill_minor(unsigned char minor)
+{
+       struct taskdev *dev;
+       int status;
+       int ret;
+
+       if (mutex_lock_interruptible(&devmgr_lock))
+               return -EINTR;
+
+       if ((minor >= TASKDEV_MAX) || ((dev = taskdev[minor]) == NULL)) {
+               printk(KERN_ERR
+                      "omapdsp: no task device with minor %d\n", minor);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = minor;
+       if ((status = dsp_tkill(dev)) < 0)
+               ret = status;
+
+out:
+       mutex_unlock(&devmgr_lock);
+       return ret;
+}
+
+static int dsp_tdel_bh(struct taskdev *dev, u16 type)
 {
-       struct taskdev *dev = taskdev[minor];
        struct dsptask *task;
-       struct mbcmd mb;
-       unsigned char tid, tid_response;
-       int ret = minor;
+       u8 tid, tid_response;
+       int ret = 0;
 
        task = dev->task;
        tid = task->tid;
        if (mutex_lock_interruptible(&cfg_lock)) {
-               if (type == OMAP_DSP_MBCMD_TDEL_SAFE) {
-                       dev->state = OMAP_DSP_DEVSTATE_DELREQ;
-                       return -ERESTARTSYS;
+               if (type == TDEL_SAFE) {
+                       dev->state = TASKDEV_ST_DELREQ;
+                       return -EINTR;
                } else {
-                       tid_response = OMAP_DSP_TID_ANON;
-                       ret = -ERESTARTSYS;
+                       tid_response = TID_ANON;
+                       ret = -EINTR;
                        goto detach_out;
                }
        }
-       cfg_tid = OMAP_DSP_TID_ANON;
-       cfg_cmd = MBCMD(TDEL);
-       mbcmd_set(mb, MBCMD(TDEL), tid, type);
-       dsp_mbcmd_send_and_wait(&mb, &cfg_wait_q);
+       cfg_tid = TID_ANON;
+       cfg_cmd = MBOX_CMD_DSP_TDEL;
+       mbcompose_send_and_wait(TDEL, tid, type, &cfg_wait_q);
        tid_response = cfg_tid;
-       cfg_tid = OMAP_DSP_TID_ANON;
+       cfg_tid = TID_ANON;
        cfg_cmd = 0;
        mutex_unlock(&cfg_lock);
 
@@ -2075,14 +2211,14 @@ detach_out:
 
        if (tid_response != tid) {
                printk(KERN_ERR "omapdsp: %s failed!\n",
-                      (type == OMAP_DSP_MBCMD_TDEL_SAFE) ? "tdel" : "tkill");
+                      (type == TDEL_SAFE) ? "tdel" : "tkill");
                ret = -EINVAL;
        }
-       spin_lock(&dev->state_lock);
-       dev->state = (dev->usecount > 0) ? OMAP_DSP_DEVSTATE_GARBAGE :
-                                          OMAP_DSP_DEVSTATE_NOTASK;
+       down_write(&dev->state_sem);
+       dev->state = (dev->usecount > 0) ? TASKDEV_ST_GARBAGE :
+                                          TASKDEV_ST_NOTASK;
        wake_up_interruptible_all(&dev->state_wait_q);
-       spin_unlock(&dev->state_lock);
+       up_write(&dev->state_sem);
 
        return ret;
 }
@@ -2094,112 +2230,114 @@ long taskdev_state_stale(unsigned char minor)
 {
        if (taskdev[minor]) {
                long state = taskdev[minor]->state;
-               taskdev[minor]->state |= OMAP_DSP_DEVSTATE_STALE;
+               taskdev[minor]->state |= TASKDEV_ST_STALE;
                return state;
        } else
-               return OMAP_DSP_DEVSTATE_NOTASK;
+               return TASKDEV_ST_NOTASK;
 }
 
 /*
- * functions called from mailbox1 interrupt routine
+ * functions called from mailbox interrupt routine
  */
-void mbx1_wdsnd(struct mbcmd *mb)
+void mbox_wdsnd(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
        struct dsptask *task = dsptask[tid];
 
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: WDSND with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: WDSND with illegal tid! %d\n", tid);
                return;
        }
        if (sndtyp_bk(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: WDSND from block sending task! (task%d)\n", tid);
+                      "mbox: WDSND from block sending task! (task%d)\n", tid);
                return;
        }
        if (sndtyp_psv(task->ttyp) &&
            !waitqueue_active(&task->dev->read_wait_q)) {
                printk(KERN_WARNING
-                      "mbx: WDSND from passive sending task (task%d) "
+                      "mbox: WDSND from passive sending task (task%d) "
                       "without request!\n", tid);
                return;
        }
 
-       write_word_to_fifo(&task->rcvdt.fifo, mb->data);
+       write_word_to_fifo(&task->dev->rcvdt.fifo, mb->data);
        wake_up_interruptible(&task->dev->read_wait_q);
 }
 
-void mbx1_wdreq(struct mbcmd *mb)
+void mbox_wdreq(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
        struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
 
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: WDREQ with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: WDREQ with illegal tid! %d\n", tid);
                return;
        }
        if (rcvtyp_psv(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: WDREQ from passive receiving task! (task%d)\n",
+                      "mbox: WDREQ from passive receiving task! (task%d)\n",
                       tid);
                return;
        }
 
-       spin_lock(&task->wsz_lock);
-       task->wsz = 2;
-       spin_unlock(&task->wsz_lock);
-       wake_up_interruptible(&task->dev->write_wait_q);
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = 2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
 }
 
-void mbx1_bksnd(struct mbcmd *mb)
+void mbox_bksnd(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
-       unsigned short bid = mb->data;
+       u8 tid = mb->cmd_l;
+       u16 bid = mb->data;
        struct dsptask *task = dsptask[tid];
-       unsigned short cnt;
+       struct ipbuf_head *ipb_h;
+       u16 cnt;
 
        if (bid >= ipbcfg.ln) {
-               printk(KERN_ERR "mbx: BKSND with illegal bid! %d\n", bid);
+               printk(KERN_ERR "mbox: BKSND with illegal bid! %d\n", bid);
                return;
        }
+       ipb_h = bid_to_ipbuf(bid);
        ipb_bsycnt_dec(&ipbcfg);
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: BKSND with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: BKSND with illegal tid! %d\n", tid);
                goto unuse_ipbuf_out;
        }
        if (sndtyp_wd(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKSND from word sending task! (task%d)\n", tid);
+                      "mbox: BKSND from word sending task! (task%d)\n", tid);
                goto unuse_ipbuf_out;
        }
        if (sndtyp_pvt(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKSND from private sending task! (task%d)\n", tid);
+                      "mbox: BKSND from private sending task! (task%d)\n", tid);
                goto unuse_ipbuf_out;
        }
-       if (sync_with_dsp(&ipbuf[bid]->sd, tid, 10) < 0) {
-               printk(KERN_ERR "mbx: BKSND - IPBUF sync failed!\n");
+       if (sync_with_dsp(&ipb_h->p->sd, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: BKSND - IPBUF sync failed!\n");
                return;
        }
 
        /* should be done in DSP, but just in case. */
-       ipbuf[bid]->next = OMAP_DSP_BID_NULL;
+       ipb_h->p->next = BID_NULL;
 
-       cnt = ipbuf[bid]->c;
+       cnt = ipb_h->p->c;
        if (cnt > ipbcfg.lsz) {
-               printk(KERN_ERR "mbx: BKSND cnt(%d) > ipbuf line size(%d)!\n",
+               printk(KERN_ERR "mbox: BKSND cnt(%d) > ipbuf line size(%d)!\n",
                       cnt, ipbcfg.lsz);
                goto unuse_ipbuf_out;
        }
 
        if (cnt == 0) {
                /* 0-byte send from DSP */
-               unuse_ipbuf_nowait(bid);
+               unuse_ipbuf_nowait(ipb_h);
                goto done;
        }
-       spin_lock(&task->rcvdt.bk.link.lock);
-       ipblink_add_tail(&task->rcvdt.bk.link, bid, ipbuf);
-       spin_unlock(&task->rcvdt.bk.link.lock);
+       ipblink_add_tail(&task->dev->rcvdt.bk.link, bid);
        /* we keep coming bid and return alternative line to DSP. */
        balance_ipbuf();
 
@@ -2208,80 +2346,83 @@ done:
        return;
 
 unuse_ipbuf_out:
-       unuse_ipbuf_nowait(bid);
+       unuse_ipbuf_nowait(ipb_h);
        return;
 }
 
-void mbx1_bkreq(struct mbcmd *mb)
+void mbox_bkreq(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
-       unsigned short cnt = mb->data;
+       u8 tid = mb->cmd_l;
+       u16 cnt = mb->data;
        struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
 
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: BKREQ with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: BKREQ with illegal tid! %d\n", tid);
                return;
        }
        if (rcvtyp_wd(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKREQ from word receiving task! (task%d)\n", tid);
+                      "mbox: BKREQ from word receiving task! (task%d)\n", tid);
                return;
        }
        if (rcvtyp_pvt(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKREQ from private receiving task! (task%d)\n",
+                      "mbox: BKREQ from private receiving task! (task%d)\n",
                       tid);
                return;
        }
        if (rcvtyp_psv(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKREQ from passive receiving task! (task%d)\n",
+                      "mbox: BKREQ from passive receiving task! (task%d)\n",
                       tid);
                return;
        }
 
-       spin_lock(&task->wsz_lock);
-       task->wsz = cnt*2;
-       spin_unlock(&task->wsz_lock);
-       wake_up_interruptible(&task->dev->write_wait_q);
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = cnt*2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
 }
 
-void mbx1_bkyld(struct mbcmd *mb)
+void mbox_bkyld(struct mbcmd *mb)
 {
-       unsigned short bid = mb->data;
+       u16 bid = mb->data;
+       struct ipbuf_head *ipb_h;
 
        if (bid >= ipbcfg.ln) {
-               printk(KERN_ERR "mbx: BKYLD with illegal bid! %d\n", bid);
+               printk(KERN_ERR "mbox: BKYLD with illegal bid! %d\n", bid);
                return;
        }
+       ipb_h = bid_to_ipbuf(bid);
 
        /* should be done in DSP, but just in case. */
-       ipbuf[bid]->next = OMAP_DSP_BID_NULL;
+       ipb_h->p->next = BID_NULL;
 
        /* we don't need to sync with DSP */
        ipb_bsycnt_dec(&ipbcfg);
-       release_ipbuf(bid);
+       release_ipbuf(ipb_h);
 }
 
-void mbx1_bksndp(struct mbcmd *mb)
+void mbox_bksndp(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
        struct dsptask *task = dsptask[tid];
-       struct rcvdt_bk_struct *rcvdt = &task->rcvdt.bk;
-       struct ipbuf_p *ipbp = rcvdt->ipbuf_pvt_r;
+       struct ipbuf_p *ipbp;
 
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: BKSNDP with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: BKSNDP with illegal tid! %d\n", tid);
                return;
        }
        if (sndtyp_wd(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKSNDP from word sending task! (task%d)\n", tid);
+                      "mbox: BKSNDP from word sending task! (task%d)\n", tid);
                return;
        }
        if (sndtyp_gbl(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKSNDP from non-private sending task! (task%d)\n",
+                      "mbox: BKSNDP from non-private sending task! (task%d)\n",
                       tid);
                return;
        }
@@ -2292,94 +2433,102 @@ void mbx1_bksndp(struct mbcmd *mb)
         * until then DSP can't send next data.
         */
 
+       ipbp = task->ipbuf_pvt_r;
        if (sync_with_dsp(&ipbp->s, tid, 10) < 0) {
-               printk(KERN_ERR "mbx: BKSNDP - IPBUF sync failed!\n");
+               printk(KERN_ERR "mbox: BKSNDP - IPBUF sync failed!\n");
                return;
        }
-       printk(KERN_DEBUG "mbx: ipbuf_pvt_r->a = 0x%08lx\n",
+       printk(KERN_DEBUG "mbox: ipbuf_pvt_r->a = 0x%08lx\n",
               MKLONG(ipbp->ah, ipbp->al));
-       spin_lock(&rcvdt->link.lock);
-       ipblink_add_pvt(&rcvdt->link);
-       spin_unlock(&rcvdt->link.lock);
+       ipblink_add_pvt(&task->dev->rcvdt.bk.link);
        wake_up_interruptible(&task->dev->read_wait_q);
 }
 
-void mbx1_bkreqp(struct mbcmd *mb)
+void mbox_bkreqp(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
        struct dsptask *task = dsptask[tid];
-       struct ipbuf_p *ipbp = task->ipbuf_pvt_w;
+       struct taskdev *dev;
+       struct ipbuf_p *ipbp;
 
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: BKREQP with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: BKREQP with illegal tid! %d\n", tid);
                return;
        }
        if (rcvtyp_wd(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKREQP from word receiving task! (task%d)\n", tid);
+                      "mbox: BKREQP from word receiving task! (task%d)\n", tid);
                return;
        }
        if (rcvtyp_gbl(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKREQP from non-private receiving task! (task%d)\n", tid);
+                      "mbox: BKREQP from non-private receiving task! (task%d)\n", tid);
                return;
        }
        if (rcvtyp_psv(task->ttyp)) {
                printk(KERN_ERR
-                      "mbx: BKREQP from passive receiving task! (task%d)\n", tid);
+                      "mbox: BKREQP from passive receiving task! (task%d)\n", tid);
                return;
        }
 
-       if (sync_with_dsp(&ipbp->s, OMAP_DSP_TID_FREE, 10) < 0) {
-               printk(KERN_ERR "mbx: BKREQP - IPBUF sync failed!\n");
+       ipbp = task->ipbuf_pvt_w;
+       if (sync_with_dsp(&ipbp->s, TID_FREE, 10) < 0) {
+               printk(KERN_ERR "mbox: BKREQP - IPBUF sync failed!\n");
                return;
        }
-       printk(KERN_DEBUG "mbx: ipbuf_pvt_w->a = 0x%08lx\n",
+       printk(KERN_DEBUG "mbox: ipbuf_pvt_w->a = 0x%08lx\n",
               MKLONG(ipbp->ah, ipbp->al));
-       spin_lock(&task->wsz_lock);
-       task->wsz = ipbp->c*2;
-       spin_unlock(&task->wsz_lock);
-       wake_up_interruptible(&task->dev->write_wait_q);
+       dev = task->dev;
+       spin_lock(&dev->wsz_lock);
+       dev->wsz = ipbp->c*2;
+       spin_unlock(&dev->wsz_lock);
+       wake_up_interruptible(&dev->write_wait_q);
 }
 
-void mbx1_tctl(struct mbcmd *mb)
+void mbox_tctl(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
        struct dsptask *task = dsptask[tid];
 
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: TCTL with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: TCTL with illegal tid! %d\n", tid);
                return;
        }
 
-       if (!waitqueue_active(&task->dev->ioctl_wait_q)) {
-               printk(KERN_WARNING "mbx: unexpected TCTL from DSP!\n");
+       if (!waitqueue_active(&task->dev->tctl_wait_q)) {
+               printk(KERN_WARNING "mbox: unexpected TCTL from DSP!\n");
                return;
        }
 
-       task->tctl_stat = mb->data;
-       wake_up_interruptible(&task->dev->ioctl_wait_q);
+       task->dev->tctl_stat = mb->data;
+       wake_up_interruptible(&task->dev->tctl_wait_q);
 }
 
-void mbx1_tcfg(struct mbcmd *mb)
+void mbox_tcfg(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
        struct dsptask *task = dsptask[tid];
-       unsigned short *tnm;
-       volatile unsigned short *buf;
+       u16 *tnm;
+       volatile u16 *buf;
        int i;
 
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: TCFG with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: TCFG with illegal tid! %d\n", tid);
                return;
        }
-       if ((task->state != TASK_STATE_CFGREQ) || (cfg_cmd != MBCMD(TCFG))) {
-               printk(KERN_WARNING "mbx: unexpected TCFG from DSP!\n");
+       if ((task->state != TASK_ST_CFGREQ) || (cfg_cmd != MBOX_CMD_DSP_TCFG)) {
+               printk(KERN_WARNING "mbox: unexpected TCFG from DSP!\n");
                return;
        }
 
+       if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+               printk(KERN_ERR "mbox: TCFG - ipbuf_sys_da read failed!\n");
+               dsp_mem_disable(ipbuf_sys_da);
+               goto out;
+       }
        if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
-               printk(KERN_ERR "mbx: TCFG - IPBUF sync failed!\n");
+               printk(KERN_ERR "mbox: TCFG - IPBUF sync failed!\n");
+               dsp_mem_disable(ipbuf_sys_da);
                goto out;
        }
 
@@ -2387,82 +2536,86 @@ void mbx1_tcfg(struct mbcmd *mb)
         * read configuration data on system IPBUF
         */
        buf = ipbuf_sys_da->d;
-       task->ttyp                 = buf[0];
-       task->rcvdt.bk.ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
-       task->ipbuf_pvt_w          = MKVIRT(buf[3], buf[4]);
-       task->map_base             = MKVIRT(buf[5], buf[6]);
-       task->map_length           = MKLONG(buf[7], buf[8]) << 1;       /* word -> byte */
-       tnm                        = MKVIRT(buf[9], buf[10]);
+       task->ttyp        = buf[0];
+       task->ipbuf_pvt_r = MKVIRT(buf[1], buf[2]);
+       task->ipbuf_pvt_w = MKVIRT(buf[3], buf[4]);
+       task->map_base    = MKVIRT(buf[5], buf[6]);
+       task->map_length  = MKLONG(buf[7], buf[8]) << 1;        /* word -> byte */
+       tnm               = MKVIRT(buf[9], buf[10]);
        release_ipbuf_pvt(ipbuf_sys_da);
+       dsp_mem_disable(ipbuf_sys_da);
 
        /*
         * copy task name string
         */
-       if (dsp_address_validate(tnm, OMAP_DSP_TNM_LEN, "task name buffer") <0) {
+       if (dsp_address_validate(tnm, TNM_LEN, "task name buffer") < 0) {
                task->name[0] = '\0';
                goto out;
        }
 
-       for (i = 0; i < OMAP_DSP_TNM_LEN-1; i++) {
+       for (i = 0; i < TNM_LEN-1; i++) {
                /* avoiding byte access */
-               unsigned short tmp = tnm[i];
+               u16 tmp = tnm[i];
                task->name[i] = tmp & 0x00ff;
                if (!tmp)
                        break;
        }
-       task->name[OMAP_DSP_TNM_LEN-1] = '\0';
+       task->name[TNM_LEN-1] = '\0';
 
-       task->state = TASK_STATE_READY;
+       task->state = TASK_ST_READY;
 out:
        wake_up_interruptible(&cfg_wait_q);
 }
 
-void mbx1_tadd(struct mbcmd *mb)
+void mbox_tadd(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
 
-       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBCMD(TADD))) {
-               printk(KERN_WARNING "mbx: unexpected TADD from DSP!\n");
+       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TADD)) {
+               printk(KERN_WARNING "mbox: unexpected TADD from DSP!\n");
                return;
        }
        cfg_tid = tid;
        wake_up_interruptible(&cfg_wait_q);
 }
 
-void mbx1_tdel(struct mbcmd *mb)
+void mbox_tdel(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
 
-       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBCMD(TDEL))) {
-               printk(KERN_WARNING "mbx: unexpected TDEL from DSP!\n");
+       if ((!waitqueue_active(&cfg_wait_q)) || (cfg_cmd != MBOX_CMD_DSP_TDEL)) {
+               printk(KERN_WARNING "mbox: unexpected TDEL from DSP!\n");
                return;
        }
        cfg_tid = tid;
        wake_up_interruptible(&cfg_wait_q);
 }
 
-void mbx1_err_fatal(unsigned char tid)
+void mbox_err_fatal(u8 tid)
 {
        struct dsptask *task = dsptask[tid];
+       struct taskdev *dev;
 
        if ((tid >= TASKDEV_MAX) || (task == NULL)) {
-               printk(KERN_ERR "mbx: FATAL ERR with illegal tid! %d\n", tid);
+               printk(KERN_ERR "mbox: FATAL ERR with illegal tid! %d\n", tid);
                return;
        }
 
-       spin_lock(&task->dev->state_lock);
-       proclist_send_sigbus(&task->dev->proc_list);
-       spin_unlock(&task->dev->state_lock);
+       /* wake up waiting processes */
+       dev = task->dev;
+       wake_up_interruptible_all(&dev->read_wait_q);
+       wake_up_interruptible_all(&dev->write_wait_q);
+       wake_up_interruptible_all(&dev->tctl_wait_q);
 }
 
-static short *dbg_buf;
-static unsigned short dbg_buf_sz, dbg_line_sz;
+static u16 *dbg_buf;
+static u16 dbg_buf_sz, dbg_line_sz;
 static int dbg_rp;
 
-int dsp_dbg_config(short *buf, unsigned short sz, unsigned short lsz)
+int dsp_dbg_config(u16 *buf, u16 sz, u16 lsz)
 {
 #ifdef OLD_BINARY_SUPPORT
-       if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) {
+       if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
                dbg_buf = NULL;
                dbg_buf_sz = 0;
                dbg_line_sz = 0;
@@ -2495,31 +2648,31 @@ void dsp_dbg_stop(void)
 }
 
 #ifdef OLD_BINARY_SUPPORT
-static void mbx1_dbg_old(struct mbcmd *mb);
+static void mbox_dbg_old(struct mbcmd *mb);
 #endif
 
-void mbx1_dbg(struct mbcmd *mb)
+void mbox_dbg(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
        int cnt = mb->data;
        char s[80], *s_end = &s[79], *p;
-       unsigned short *src;
+       u16 *src;
        int i;
 
 #ifdef OLD_BINARY_SUPPORT
-       if ((mbx_revision == MBREV_3_0) || (mbx_revision == MBREV_3_2)) {
-               mbx1_dbg_old(mb);
+       if ((mbox_revision == MBREV_3_0) || (mbox_revision == MBREV_3_2)) {
+               mbox_dbg_old(mb);
                return;
        }
 #endif
 
        if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
-           (tid != OMAP_DSP_TID_ANON)) {
-               printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid);
+           (tid != TID_ANON)) {
+               printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
                return;
        }
        if (dbg_buf == NULL) {
-               printk(KERN_ERR "mbx: DBG command received, but "
+               printk(KERN_ERR "mbox: DBG command received, but "
                       "dbg_buf has not been configured yet.\n");
                return;
        }
@@ -2530,7 +2683,7 @@ void mbx1_dbg(struct mbcmd *mb)
        src = &dbg_buf[dbg_rp];
        p = s;
        for (i = 0; i < cnt; i++) {
-               unsigned short tmp;
+               u16 tmp;
                /*
                 * Be carefull that dbg_buf should not be read with
                 * 1-byte access since it might be placed in DARAM/SARAM
@@ -2565,36 +2718,40 @@ void mbx1_dbg(struct mbcmd *mb)
 }
 
 #ifdef OLD_BINARY_SUPPORT
-static void mbx1_dbg_old(struct mbcmd *mb)
+static void mbox_dbg_old(struct mbcmd *mb)
 {
-       unsigned char tid = mb->cmd_l;
+       u8 tid = mb->cmd_l;
        char s[80], *s_end = &s[79], *p;
-       unsigned short *src;
-       volatile unsigned short *buf;
+       u16 *src;
+       volatile u16 *buf;
        int cnt;
        int i;
 
        if (((tid >= TASKDEV_MAX) || (dsptask[tid] == NULL)) &&
-           (tid != OMAP_DSP_TID_ANON)) {
-               printk(KERN_ERR "mbx: DBG with illegal tid! %d\n", tid);
+           (tid != TID_ANON)) {
+               printk(KERN_ERR "mbox: DBG with illegal tid! %d\n", tid);
                return;
        }
-       if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
-               printk(KERN_ERR "mbx: DBG - IPBUF sync failed!\n");
+       if (dsp_mem_enable(ipbuf_sys_da) < 0) {
+               printk(KERN_ERR "mbox: DBG - ipbuf_sys_da read failed!\n");
                return;
        }
+       if (sync_with_dsp(&ipbuf_sys_da->s, tid, 10) < 0) {
+               printk(KERN_ERR "mbox: DBG - IPBUF sync failed!\n");
+               goto out1;
+       }
        buf = ipbuf_sys_da->d;
        cnt = buf[0];
        src = MKVIRT(buf[1], buf[2]);
        if (dsp_address_validate(src, cnt, "dbg buffer") < 0)
-               return;
+               goto out2;
 
        if (dsp_mem_enable(src) < 0)
-               return;
+               goto out2;
 
        p = s;
        for (i = 0; i < cnt; i++) {
-               unsigned short tmp;
+               u16 tmp;
                /*
                 * Be carefull that ipbuf should not be read with
                 * 1-byte access since it might be placed in DARAM/SARAM
@@ -2623,28 +2780,33 @@ static void mbx1_dbg_old(struct mbcmd *mb)
                printk(KERN_INFO "%s\n", s);
        }
 
-       release_ipbuf_pvt(ipbuf_sys_da);
        dsp_mem_disable(src);
+out2:
+       release_ipbuf_pvt(ipbuf_sys_da);
+out1:
+       dsp_mem_disable(ipbuf_sys_da);
 }
 #endif /* OLD_BINARY_SUPPORT */
 
 /*
- * sysfs files
+ * sysfs files: for each device
  */
+
+/* devname */
 static ssize_t devname_show(struct device *d, struct device_attribute *attr,
                            char *buf)
 {
-       struct taskdev *dev = to_taskdev(d);
-       return sprintf(buf, "%s\n", dev->name);
+       return sprintf(buf, "%s\n", to_taskdev(d)->name);
 }
 
+/* devstate */
 static ssize_t devstate_show(struct device *d, struct device_attribute *attr,
                             char *buf)
 {
-       struct taskdev *dev = to_taskdev(d);
-       return sprintf(buf, "%s\n", devstate_name(dev->state));
+       return sprintf(buf, "%s\n", devstate_name(to_taskdev(d)->state));
 }
 
+/* proc_list */
 static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
                              char *buf)
 {
@@ -2653,32 +2815,47 @@ static ssize_t proc_list_show(struct device *d, struct device_attribute *attr,
        int len = 0;
 
        dev = to_taskdev(d);
-       spin_lock(&dev->state_lock);
+       spin_lock(&dev->proc_list_lock);
        list_for_each_entry(pl, &dev->proc_list, list_head) {
-               len += sprintf(buf + len, "%d\n", pl->pid);
+               /* need to lock tasklist_lock before calling
+                * find_task_by_pid_type. */
+               if (find_task_by_pid_type(PIDTYPE_PID, pl->pid) != NULL)
+                       len += sprintf(buf + len, "%d\n", pl->pid);
+               read_unlock(&tasklist_lock);
        }
-       spin_unlock(&dev->state_lock);
+       spin_unlock(&dev->proc_list_lock);
 
        return len;
 }
 
+/* taskname */
 static ssize_t taskname_show(struct device *d, struct device_attribute *attr,
                             char *buf)
 {
        struct taskdev *dev = to_taskdev(d);
        int len;
 
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
        len = sprintf(buf, "%s\n", dev->task->name);
 
+       devstate_read_unlock(dev);
        return len;
 }
 
+/* ttyp */
 static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
                         char *buf)
 {
-       unsigned short ttyp = to_taskdev(d)->task->ttyp;
+       struct taskdev *dev = to_taskdev(d);
+       u16 ttyp;
        int len = 0;
 
+       if (!devstate_read_lock_and_test(dev, TASKDEV_ST_ATTACHED))
+               return -ENODEV;
+
+       ttyp = dev->task->ttyp;
        len += sprintf(buf + len, "0x%04x\n", ttyp);
        len += sprintf(buf + len, "%s %s send\n",
                        (sndtyp_acv(ttyp)) ? "active" :
@@ -2693,44 +2870,48 @@ static ssize_t ttyp_show(struct device *d, struct device_attribute *attr,
                        (rcvtyp_pvt(ttyp)) ? "private block" :
                                             "global block");
 
+       devstate_read_unlock(dev);
        return len;
 }
 
+/* fifosz */
 static ssize_t fifosz_show(struct device *d, struct device_attribute *attr,
                           char *buf)
 {
-       struct fifo_struct *fifo = &to_taskdev(d)->task->rcvdt.fifo;
+       struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo;
        return sprintf(buf, "%d\n", fifo->sz);
 }
 
 static int fifosz_store(struct device *d, struct device_attribute *attr,
                        const char *buf, size_t count)
 {
-       struct dsptask *task = to_taskdev(d)->task;
+       struct taskdev *dev = to_taskdev(d);
        unsigned long fifosz;
        int ret;
 
        fifosz = simple_strtol(buf, NULL, 10);
-       ret = dsp_task_set_fifosz(task, fifosz);
+       ret = taskdev_set_fifosz(dev, fifosz);
 
        return (ret < 0) ? ret : strlen(buf);
 }
 
+/* fifocnt */
 static ssize_t fifocnt_show(struct device *d, struct device_attribute *attr,
                            char *buf)
 {
-       struct fifo_struct *fifo = &to_taskdev(d)->task->rcvdt.fifo;
+       struct fifo_struct *fifo = &to_taskdev(d)->rcvdt.fifo;
        return sprintf(buf, "%d\n", fifo->cnt);
 }
 
-static __inline__ char *bid_name(unsigned short bid)
+/* ipblink */
+static __inline__ char *bid_name(u16 bid)
 {
        static char s[6];
 
        switch (bid) {
-       case OMAP_DSP_BID_NULL:
+       case BID_NULL:
                return "NULL";
-       case OMAP_DSP_BID_PVT:
+       case BID_PVT:
                return "PRIVATE";
        default:
                sprintf(s, "%d", bid);
@@ -2741,7 +2922,7 @@ static __inline__ char *bid_name(unsigned short bid)
 static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
                            char *buf)
 {
-       struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->task->rcvdt.bk;
+       struct rcvdt_bk_struct *rcvdt = &to_taskdev(d)->rcvdt.bk;
        int len;
 
        spin_lock(&rcvdt->link.lock);
@@ -2752,12 +2933,14 @@ static ssize_t ipblink_show(struct device *d, struct device_attribute *attr,
        return len;
 }
 
+/* wsz */
 static ssize_t wsz_show(struct device *d, struct device_attribute *attr,
                        char *buf)
 {
-       return sprintf(buf, "%d\n", to_taskdev(d)->task->wsz);
+       return sprintf(buf, "%d\n", to_taskdev(d)->wsz);
 }
 
+/* mmap */
 static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
                         char *buf)
 {
@@ -2766,25 +2949,27 @@ static ssize_t mmap_show(struct device *d, struct device_attribute *attr,
 }
 
 /*
- * called from ipbuf_read_proc()
+ * called from ipbuf_show()
  */
-int ipbuf_is_held(unsigned char tid, unsigned short bid)
+int ipbuf_is_held(u8 tid, u16 bid)
 {
        struct dsptask *task = dsptask[tid];
-       unsigned short b;
+       struct ipblink *link;
+       u16 b;
        int ret = 0;
 
        if (task == NULL)
                return 0;
 
-       spin_lock(&task->rcvdt.bk.link.lock);
-       ipblink_for_each(b, &task->rcvdt.bk.link, ipbuf) {
+       link = &task->dev->rcvdt.bk.link;
+       spin_lock(&link->lock);
+       ipblink_for_each(b, link) {
                if (b == bid) { /* found */
                        ret = 1;
                        break;
                }
        }
-       spin_unlock(&task->rcvdt.bk.link.lock);
+       spin_unlock(&link->lock);
 
        return ret;
 }