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