]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/cbus/retu-user.c
Merge branch 'omap-fixes'
[linux-2.6-omap-h63xx.git] / drivers / cbus / retu-user.c
1 /**
2  * drivers/cbus/retu-user.c
3  *
4  * Retu user space interface functions
5  *
6  * Copyright (C) 2004, 2005 Nokia Corporation
7  *
8  * Written by Mikko Ylinen <mikko.k.ylinen@nokia.com>
9  *
10  * This file is subject to the terms and conditions of the GNU General
11  * Public License. See the file "COPYING" in the main directory of this
12  * archive for more details.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include <linux/types.h>
25 #include <linux/kernel.h>
26 #include <linux/interrupt.h>
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/fs.h>
30 #include <linux/miscdevice.h>
31 #include <linux/poll.h>
32 #include <linux/list.h>
33 #include <linux/spinlock.h>
34 #include <linux/mutex.h>
35
36 #include <asm/uaccess.h>
37
38 #include "retu.h"
39
40 #include "user_retu_tahvo.h"
41
42 /* Maximum size of IRQ node buffer/pool */
43 #define RETU_MAX_IRQ_BUF_LEN    16
44
45 #define PFX                     "retu-user: "
46
47 /* Bitmap for marking the interrupt sources as having the handlers */
48 static u32 retu_irq_bits;
49
50 /* For allowing only one user process to subscribe to the retu interrupts */
51 static struct file *retu_irq_subscr = NULL;
52
53 /* For poll and IRQ passing */
54 struct retu_irq {
55         u32 id;
56         struct list_head node;
57 };
58
59 static spinlock_t retu_irqs_lock;
60 static struct retu_irq *retu_irq_block;
61 static LIST_HEAD(retu_irqs);
62 static LIST_HEAD(retu_irqs_reserve);
63
64 /* Wait queue - used when user wants to read the device */
65 DECLARE_WAIT_QUEUE_HEAD(retu_user_waitqueue);
66
67 /* Semaphore to protect irq subscription sequence */
68 static struct mutex retu_mutex;
69
70 /* This array specifies RETU register types (read/write/toggle) */
71 static const u8 retu_access_bits[] = {
72         1,
73         4,
74         3,
75         3,
76         1,
77         3,
78         3,
79         0,
80         3,
81         3,
82         3,
83         3,
84         3,
85         3,
86         3,
87         4,
88         4,
89         3,
90         0,
91         0,
92         0,
93         0,
94         1,
95         3,
96         3,
97         3,
98         3,
99         3,
100         3,
101         3,
102         3,
103         3
104 };
105
106 /*
107  * The handler for all RETU interrupts.
108  *
109  * arg is the interrupt source in RETU.
110  */
111 static void retu_user_irq_handler(unsigned long arg)
112 {
113         struct retu_irq *irq;
114
115         retu_ack_irq(arg);
116
117         spin_lock(&retu_irqs_lock);
118         if (list_empty(&retu_irqs_reserve)) {
119                 spin_unlock(&retu_irqs_lock);
120                 return;
121         }
122         irq = list_entry((&retu_irqs_reserve)->next, struct retu_irq, node);
123         irq->id = arg;
124         list_move_tail(&irq->node, &retu_irqs);
125         spin_unlock(&retu_irqs_lock);
126
127         /* wake up waiting thread */
128         wake_up(&retu_user_waitqueue);
129 }
130
131 /*
132  * This routine sets up the interrupt handler and marks an interrupt source
133  * in RETU as a candidate for signal delivery to the user process.
134  */
135 static int retu_user_subscribe_to_irq(int id, struct file *filp)
136 {
137         int ret;
138
139         mutex_lock(&retu_mutex);
140         if ((retu_irq_subscr != NULL) && (retu_irq_subscr != filp)) {
141                 mutex_unlock(&retu_mutex);
142                 return -EBUSY;
143         }
144         /* Store the file pointer of the first user process registering IRQs */
145         retu_irq_subscr = filp;
146         mutex_unlock(&retu_mutex);
147
148         if (retu_irq_bits & (1 << id))
149                 return 0;
150
151         ret = retu_request_irq(id, retu_user_irq_handler, id, "");
152         if (ret < 0)
153                 return ret;
154
155         /* Mark that this interrupt has a handler */
156         retu_irq_bits |= 1 << id;
157
158         return 0;
159 }
160
161 /*
162  * Unregisters all RETU interrupt handlers.
163  */
164 static void retu_unreg_irq_handlers(void)
165 {
166         int id;
167
168         if (!retu_irq_bits)
169                 return;
170
171         for (id = 0; id < MAX_RETU_IRQ_HANDLERS; id++)
172                 if (retu_irq_bits & (1 << id))
173                         retu_free_irq(id);
174
175         retu_irq_bits = 0;
176 }
177
178 /*
179  * Write to RETU register.
180  * Returns 0 upon success, a negative error value otherwise.
181  */
182 static int retu_user_write_with_mask(u32 field, u16 value)
183 {
184         u32 mask;
185         u32 reg;
186         u_short tmp;
187         unsigned long flags;
188
189         mask = MASK(field);
190         reg = REG(field);
191
192         /* Detect bad mask and reg */
193         if (mask == 0 || reg > RETU_REG_MAX ||
194             retu_access_bits[reg] == READ_ONLY) {
195                 printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
196                        reg, mask);
197                 return -EINVAL;
198         }
199
200         /* Justify value according to mask */
201         while (!(mask & 1)) {
202                 value = value << 1;
203                 mask = mask >> 1;
204         }
205
206         spin_lock_irqsave(&retu_lock, flags);
207         if (retu_access_bits[reg] == TOGGLE) {
208                 /* No need to detect previous content of register */
209                 tmp = 0;
210         } else {
211                 /* Read current value of register */
212                 tmp = retu_read_reg(reg);
213         }
214
215         /* Generate new value */
216         tmp = (tmp & ~MASK(field)) | (value & MASK(field));
217         /* Write data to RETU */
218         retu_write_reg(reg, tmp);
219         spin_unlock_irqrestore(&retu_lock, flags);
220
221         return 0;
222 }
223
224 /*
225  * Read RETU register.
226  */
227 static u32 retu_user_read_with_mask(u32 field)
228 {
229         u_short value;
230         u32 mask, reg;
231
232         mask = MASK(field);
233         reg = REG(field);
234
235         /* Detect bad mask and reg */
236         if (mask == 0 || reg > RETU_REG_MAX) {
237                 printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
238                        reg, mask);
239                 return -EINVAL;
240         }
241
242         /* Read the register */
243         value = retu_read_reg(reg) & mask;
244
245         /* Right justify value */
246         while (!(mask & 1)) {
247                 value = value >> 1;
248                 mask = mask >> 1;
249         }
250
251         return value;
252 }
253
254 /*
255  * Close device
256  */
257 static int retu_close(struct inode *inode, struct file *filp)
258 {
259         /* Unregister all interrupts that have been registered */
260         if (retu_irq_subscr == filp) {
261                 retu_unreg_irq_handlers();
262                 retu_irq_subscr = NULL;
263         }
264
265         return 0;
266 }
267
268 /*
269  * Device control (ioctl)
270  */
271 static int retu_ioctl(struct inode *inode, struct file *filp,
272                       unsigned int cmd, unsigned long arg)
273 {
274         struct retu_tahvo_write_parms par;
275         int ret;
276
277         switch (cmd) {
278         case URT_IOCT_IRQ_SUBSCR:
279                 return retu_user_subscribe_to_irq(arg, filp);
280         case RETU_IOCH_READ:
281                 return retu_user_read_with_mask(arg);
282         case RETU_IOCX_WRITE:
283                 ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
284                 if (ret)
285                         printk(KERN_ERR "copy_from_user failed: %d\n", ret);
286                 par.result = retu_user_write_with_mask(par.field, par.value);
287                 ret = copy_to_user((void __user *) arg, &par, sizeof(par));
288                 if (ret)
289                         printk(KERN_ERR "copy_to_user failed: %d\n", ret);
290                 break;
291         case RETU_IOCH_ADC_READ:
292                 return retu_read_adc(arg);
293         default:
294                 return -ENOIOCTLCMD;
295         }
296         return 0;
297 }
298
299 /*
300  * Read from device
301  */
302 static ssize_t retu_read(struct file *filp, char *buf, size_t count,
303                          loff_t * offp)
304 {
305         struct retu_irq *irq;
306
307         u32 nr, i;
308
309         /* read not permitted if neither filp nor anyone has registered IRQs */
310         if (retu_irq_subscr != filp)
311                 return -EPERM;
312
313         if ((count < sizeof(u32)) || ((count % sizeof(u32)) != 0))
314                 return -EINVAL;
315
316         nr = count / sizeof(u32);
317
318         for (i = 0; i < nr; i++) {
319                 unsigned long flags;
320                 u32 irq_id;
321                 int ret;
322
323                 ret = wait_event_interruptible(retu_user_waitqueue,
324                                                !list_empty(&retu_irqs));
325                 if (ret < 0)
326                         return ret;
327
328                 spin_lock_irqsave(&retu_irqs_lock, flags);
329                 irq = list_entry((&retu_irqs)->next, struct retu_irq, node);
330                 irq_id = irq->id;
331                 list_move(&irq->node, &retu_irqs_reserve);
332                 spin_unlock_irqrestore(&retu_irqs_lock, flags);
333
334                 ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id,
335                                    sizeof(irq_id));
336                 if (ret)
337                         printk(KERN_ERR "copy_to_user failed: %d\n", ret);
338         }
339
340         return count;
341 }
342
343 /*
344  * Poll method
345  */
346 static unsigned retu_poll(struct file *filp, struct poll_table_struct *pt)
347 {
348         if (!list_empty(&retu_irqs))
349                 return POLLIN;
350
351         poll_wait(filp, &retu_user_waitqueue, pt);
352
353         if (!list_empty(&retu_irqs))
354                 return POLLIN;
355         else
356                 return 0;
357 }
358
359 static struct file_operations retu_user_fileops = {
360         .owner = THIS_MODULE,
361         .ioctl = retu_ioctl,
362         .read = retu_read,
363         .release = retu_close,
364         .poll = retu_poll
365 };
366
367 static struct miscdevice retu_device = {
368         .minor = MISC_DYNAMIC_MINOR,
369         .name = "retu",
370         .fops = &retu_user_fileops
371 };
372
373 /*
374  * Initialization
375  *
376  * @return 0 if successful, error value otherwise.
377  */
378 int retu_user_init(void)
379 {
380         struct retu_irq *irq;
381         int res, i;
382
383         irq = kmalloc(sizeof(*irq) * RETU_MAX_IRQ_BUF_LEN, GFP_KERNEL);
384         if (irq == NULL) {
385                 printk(KERN_ERR PFX "kmalloc failed\n");
386                 return -ENOMEM;
387         }
388         memset(irq, 0, sizeof(*irq) * RETU_MAX_IRQ_BUF_LEN);
389         for (i = 0; i < RETU_MAX_IRQ_BUF_LEN; i++)
390                 list_add(&irq[i].node, &retu_irqs_reserve);
391
392         retu_irq_block = irq;
393
394         spin_lock_init(&retu_irqs_lock);
395         mutex_init(&retu_mutex);
396
397         /* Request a misc device */
398         res = misc_register(&retu_device);
399         if (res < 0) {
400                 printk(KERN_ERR PFX "unable to register misc device for %s\n",
401                        retu_device.name);
402                 kfree(irq);
403                 return res;
404         }
405
406         return 0;
407 }
408
409 /*
410  * Cleanup.
411  */
412 void retu_user_cleanup(void)
413 {
414         /* Unregister our misc device */
415         misc_deregister(&retu_device);
416         /* Unregister and disable all RETU interrupts used by this module */
417         retu_unreg_irq_handlers();
418         kfree(retu_irq_block);
419 }
420
421 MODULE_DESCRIPTION("Retu ASIC user space functions");
422 MODULE_LICENSE("GPL");
423 MODULE_AUTHOR("Mikko Ylinen");