2 * drivers/cbus/tahvo-user.c
4 * Tahvo user space interface functions
6 * Copyright (C) 2004, 2005 Nokia Corporation
8 * Written by Mikko Ylinen <mikko.k.ylinen@nokia.com>
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.
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.
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
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>
30 #include <linux/miscdevice.h>
31 #include <linux/poll.h>
32 #include <linux/list.h>
33 #include <linux/spinlock.h>
35 #include <asm/uaccess.h>
39 #include "user_retu_tahvo.h"
41 /* Maximum size of IRQ node buffer/pool */
42 #define TAHVO_MAX_IRQ_BUF_LEN 16
44 #define PFX "tahvo-user: "
46 /* Bitmap for marking the interrupt sources as having the handlers */
47 static u32 tahvo_irq_bits;
49 /* For allowing only one user process to subscribe to the tahvo interrupts */
50 static struct file *tahvo_irq_subscr = NULL;
52 /* For poll and IRQ passing */
55 struct list_head node;
58 static spinlock_t tahvo_irqs_lock;
59 static struct tahvo_irq *tahvo_irq_block;
60 static LIST_HEAD(tahvo_irqs);
61 static LIST_HEAD(tahvo_irqs_reserve);
63 /* Wait queue - used when user wants to read the device */
64 DECLARE_WAIT_QUEUE_HEAD(tahvo_user_waitqueue);
66 /* Semaphore to protect irq subscription sequence */
67 static struct semaphore tahvo_sem;
69 /* This array specifies TAHVO register types (read/write/toggle) */
70 static const u8 tahvo_access_bits[] = {
88 * The handler for all TAHVO interrupts.
90 * arg is the interrupt source in TAHVO.
92 static void tahvo_user_irq_handler(unsigned long arg)
94 struct tahvo_irq *irq;
96 /* user has to re-enable the interrupt once ready
97 * for receiving them again */
98 tahvo_disable_irq(arg);
101 spin_lock(&tahvo_irqs_lock);
102 if (list_empty(&tahvo_irqs_reserve)) {
103 spin_unlock(&tahvo_irqs_lock);
106 irq = list_entry((&tahvo_irqs_reserve)->next, struct tahvo_irq, node);
108 list_move_tail(&irq->node, &tahvo_irqs);
109 spin_unlock(&tahvo_irqs_lock);
111 /* wake up waiting thread */
112 wake_up(&tahvo_user_waitqueue);
116 * This routine sets up the interrupt handler and marks an interrupt source
117 * in TAHVO as a candidate for signal delivery to the user process.
119 static int tahvo_user_subscribe_to_irq(int id, struct file *filp)
124 if ((tahvo_irq_subscr != NULL) && (tahvo_irq_subscr != filp)) {
128 /* Store the file pointer of the first user process registering IRQs */
129 tahvo_irq_subscr = filp;
132 if (tahvo_irq_bits & (1 << id))
135 ret = tahvo_request_irq(id, tahvo_user_irq_handler, id, "");
139 /* Mark that this interrupt has a handler */
140 tahvo_irq_bits |= 1 << id;
146 * Unregister all TAHVO interrupt handlers
148 static void tahvo_unreg_irq_handlers(void)
155 for (id = 0; id < MAX_TAHVO_IRQ_HANDLERS; id++)
156 if (tahvo_irq_bits & (1 << id))
163 * Write to TAHVO register.
164 * Returns 0 upon success, a negative error value otherwise.
166 static int tahvo_user_write_with_mask(u32 field, u16 value)
176 /* Detect bad mask and reg */
177 if (mask == 0 || reg > TAHVO_REG_MAX ||
178 tahvo_access_bits[reg] == READ_ONLY) {
179 printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
184 /* Justify value according to mask */
185 while (!(mask & 1)) {
190 spin_lock_irqsave(&tahvo_lock, flags);
191 if (tahvo_access_bits[reg] == TOGGLE) {
192 /* No need to detect previous content of register */
195 /* Read current value of register */
196 tmp = tahvo_read_reg(reg);
198 /* Generate a new value */
199 tmp = (tmp & ~MASK(field)) | (value & MASK(field));
200 /* Write data to TAHVO */
201 tahvo_write_reg(reg, tmp);
202 spin_unlock_irqrestore(&tahvo_lock, flags);
208 * Read TAHVO register.
210 static u32 tahvo_user_read_with_mask(u32 field)
218 /* Detect bad mask and reg */
219 if (mask == 0 || reg > TAHVO_REG_MAX) {
220 printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
225 /* Read the register */
226 value = tahvo_read_reg(reg) & mask;
228 /* Right justify value */
229 while (!(mask & 1)) {
240 static int tahvo_close(struct inode *inode, struct file *filp)
242 /* Unregister all interrupts that have been registered */
243 if (tahvo_irq_subscr == filp) {
244 tahvo_unreg_irq_handlers();
245 tahvo_irq_subscr = NULL;
252 * Device control (ioctl)
254 static int tahvo_ioctl(struct inode *inode, struct file *filp,
255 unsigned int cmd, unsigned long arg)
257 struct retu_tahvo_write_parms par;
260 case URT_IOCT_IRQ_SUBSCR:
261 return tahvo_user_subscribe_to_irq(arg, filp);
262 case TAHVO_IOCH_READ:
263 return tahvo_user_read_with_mask(arg);
264 case TAHVO_IOCX_WRITE:
265 copy_from_user(&par, (void __user *) arg, sizeof(par));
266 par.result = tahvo_user_write_with_mask(par.field, par.value);
267 copy_to_user((void __user *) arg, &par, sizeof(par));
278 static ssize_t tahvo_read(struct file *filp, char *buf, size_t count,
281 struct tahvo_irq *irq;
285 /* read not permitted if neither filp nor anyone has registered IRQs */
286 if (tahvo_irq_subscr != filp)
289 if ((count < sizeof(u32)) || ((count % sizeof(u32)) != 0))
292 nr = count / sizeof(u32);
294 for (i = 0; i < nr; i++) {
299 ret = wait_event_interruptible(tahvo_user_waitqueue,
300 !list_empty(&tahvo_irqs));
304 spin_lock_irqsave(&tahvo_irqs_lock, flags);
305 irq = list_entry((&tahvo_irqs)->next, struct tahvo_irq, node);
307 list_move(&irq->node, &tahvo_irqs_reserve);
308 spin_unlock_irqrestore(&tahvo_irqs_lock, flags);
310 copy_to_user(buf + i * sizeof(irq_id), &irq_id, sizeof(irq_id));
319 static unsigned tahvo_poll(struct file *filp, struct poll_table_struct *pt)
321 if (!list_empty(&tahvo_irqs))
324 poll_wait(filp, &tahvo_user_waitqueue, pt);
326 if (!list_empty(&tahvo_irqs))
332 static struct file_operations tahvo_user_fileops = {
333 .owner = THIS_MODULE,
334 .ioctl = tahvo_ioctl,
336 .release = tahvo_close,
340 static struct miscdevice tahvo_device = {
341 .minor = MISC_DYNAMIC_MINOR,
343 .fops = &tahvo_user_fileops
349 * @return 0 if successful, error value otherwise.
351 int tahvo_user_init(void)
353 struct tahvo_irq *irq;
356 irq = kmalloc(sizeof(*irq) * TAHVO_MAX_IRQ_BUF_LEN, GFP_KERNEL);
358 printk(KERN_ERR PFX "kmalloc failed\n");
361 memset(irq, 0, sizeof(*irq) * TAHVO_MAX_IRQ_BUF_LEN);
362 for (i = 0; i < TAHVO_MAX_IRQ_BUF_LEN; i++)
363 list_add(&irq[i].node, &tahvo_irqs_reserve);
365 tahvo_irq_block = irq;
367 spin_lock_init(&tahvo_irqs_lock);
368 sema_init(&tahvo_sem, 1);
370 /* Request a misc device */
371 res = misc_register(&tahvo_device);
373 printk(KERN_ERR PFX "unable to register misc device for %s\n",
385 void tahvo_user_cleanup(void)
387 /* Unregister our misc device */
388 misc_deregister(&tahvo_device);
389 /* Unregister and disable all TAHVO interrupts */
390 tahvo_unreg_irq_handlers();
391 kfree(tahvo_irq_block);
394 MODULE_DESCRIPTION("Tahvo ASIC user space functions");
395 MODULE_LICENSE("GPL");
396 MODULE_AUTHOR("Mikko Ylinen");