]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/dsp/taskwatch.c
ARM: OMAP: DSPGW: DSP Gateway driver 3.3.1
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / dsp / taskwatch.c
1 /*
2  * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
3  *
4  * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
5  *
6  * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License 
10  * version 2 as published by the Free Software Foundation. 
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23
24 #include <linux/module.h>
25 #include <linux/fs.h>
26 #include <linux/poll.h>
27 #include <linux/sched.h>
28 #include <asm/uaccess.h>
29 #include "dsp_mbcmd.h"
30 #include "dsp.h"
31 #include "ioctl.h"
32
33 static DECLARE_WAIT_QUEUE_HEAD(read_wait_q);
34 static unsigned int change_cnt;
35
36 void dsp_twch_touch(void)
37 {
38         change_cnt++;
39         wake_up_interruptible(&read_wait_q);
40 }
41
42 /*
43  * @count: represents the device counts of the user's interst
44  */
45 static ssize_t dsp_twch_read(struct file *file, char __user *buf, size_t count,
46                              loff_t *ppos)
47 {
48         long taskstat[TASKDEV_MAX];
49         int devcount = count / sizeof(long);
50         int i;
51
52         if (dsp_cfgstat_get_stat() != CFGSTAT_READY) {
53                 printk(KERN_ERR "omapdsp: dsp has not been configured.\n");
54                 return -EINVAL;
55         }
56
57         if (change_cnt == 0) {
58                 long current_state;
59                 DECLARE_WAITQUEUE(wait, current);
60
61                 add_wait_queue(&read_wait_q, &wait);
62                 current_state = current->state;
63                 set_current_state(TASK_INTERRUPTIBLE);
64                 if (change_cnt == 0)    /* last check */
65                         schedule();
66                 set_current_state(current_state);
67                 remove_wait_queue(&read_wait_q, &wait);
68
69                 /* unconfigured while waiting ;-( */
70                 if (dsp_cfgstat_get_stat() != CFGSTAT_READY)
71                         return -EINVAL;
72         }
73
74         if (devcount > TASKDEV_MAX)
75                 devcount = TASKDEV_MAX;
76
77         count = devcount * sizeof(long);
78         change_cnt = 0;
79         for (i = 0; i < devcount; i++) {
80                 /*
81                  * once the device state is read, the 'STALE' bit will be set
82                  * so that the Dynamic Loader can distinguish the new request
83                  * from the old one.
84                  */
85                 taskstat[i] = taskdev_state_stale(i);
86         }
87
88         if (copy_to_user(buf, taskstat, count))
89                 return -EFAULT;
90
91         return count;
92 }
93
94 static unsigned int dsp_twch_poll(struct file *file, poll_table *wait)
95 {
96         unsigned int mask = 0;
97
98         poll_wait(file, &read_wait_q, wait);
99         if (change_cnt)
100                 mask |= POLLIN | POLLRDNORM;
101
102         return mask;
103 }
104
105 static int dsp_twch_ioctl(struct inode *inode, struct file *file,
106                           unsigned int cmd, unsigned long arg)
107 {
108         int ret;
109
110         switch (cmd) {
111         case TWCH_IOCTL_MKDEV:
112                 {
113                         char name[TNM_LEN];
114                         if (copy_from_user(name, (void __user *)arg, TNM_LEN))
115                                 return -EFAULT;
116                         name[TNM_LEN-1] = '\0';
117                         ret = dsp_mkdev(name);
118                         break;
119                 }
120
121         case TWCH_IOCTL_RMDEV:
122                 {
123                         char name[TNM_LEN];
124                         if (copy_from_user(name, (void __user *)arg, TNM_LEN))
125                                 return -EFAULT;
126                         name[TNM_LEN-1] = '\0';
127                         ret = dsp_rmdev(name);
128                         break;
129                 }
130
131         case TWCH_IOCTL_TADD:
132                 {
133                         struct omap_dsp_taddinfo ti;
134                         if (copy_from_user(&ti, (void __user *)arg, sizeof(ti)))
135                                 return -EFAULT;
136                         ret = dsp_tadd_minor(ti.minor, ti.taskadr);
137                         break;
138                 }
139
140         case TWCH_IOCTL_TDEL:
141                 ret = dsp_tdel_minor(arg);
142                 break;
143
144         case TWCH_IOCTL_TKILL:
145                 ret = dsp_tkill_minor(arg);
146                 break;
147
148         default:
149                 return -ENOIOCTLCMD;
150         }
151
152         return ret;
153 }
154
155 struct file_operations dsp_twch_fops = {
156         .owner = THIS_MODULE,
157         .read  = dsp_twch_read,
158         .poll  = dsp_twch_poll,
159         .ioctl = dsp_twch_ioctl,
160 };
161
162 void dsp_twch_start(void)
163 {
164         change_cnt = 1;         /* first read will not wait */
165 }
166
167 void dsp_twch_stop(void)
168 {
169         wake_up_interruptible(&read_wait_q);
170 }