Full support for Ginger Console
[linux-ginger.git] / drivers / cbus / retu-user.c
blob0f35dc54cab36ca9eb4d37373fdfbfc68fda6138
1 /**
2 * drivers/cbus/retu-user.c
4 * Retu 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>
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/sched.h>
35 #include <linux/mutex.h>
37 #include <asm/uaccess.h>
39 #include "retu.h"
41 #include "user_retu_tahvo.h"
43 /* Maximum size of IRQ node buffer/pool */
44 #define RETU_MAX_IRQ_BUF_LEN 16
46 #define PFX "retu-user: "
48 /* Bitmap for marking the interrupt sources as having the handlers */
49 static u32 retu_irq_bits;
51 /* For allowing only one user process to subscribe to the retu interrupts */
52 static struct file *retu_irq_subscr = NULL;
54 /* For poll and IRQ passing */
55 struct retu_irq {
56 u32 id;
57 struct list_head node;
60 static spinlock_t retu_irqs_lock;
61 static struct retu_irq *retu_irq_block;
62 static LIST_HEAD(retu_irqs);
63 static LIST_HEAD(retu_irqs_reserve);
65 /* Wait queue - used when user wants to read the device */
66 DECLARE_WAIT_QUEUE_HEAD(retu_user_waitqueue);
68 /* Semaphore to protect irq subscription sequence */
69 static struct mutex retu_mutex;
71 /* This array specifies RETU register types (read/write/toggle) */
72 static const u8 retu_access_bits[] = {
108 * The handler for all RETU interrupts.
110 * arg is the interrupt source in RETU.
112 static void retu_user_irq_handler(unsigned long arg)
114 struct retu_irq *irq;
116 retu_ack_irq(arg);
118 spin_lock(&retu_irqs_lock);
119 if (list_empty(&retu_irqs_reserve)) {
120 spin_unlock(&retu_irqs_lock);
121 return;
123 irq = list_entry((&retu_irqs_reserve)->next, struct retu_irq, node);
124 irq->id = arg;
125 list_move_tail(&irq->node, &retu_irqs);
126 spin_unlock(&retu_irqs_lock);
128 /* wake up waiting thread */
129 wake_up(&retu_user_waitqueue);
133 * This routine sets up the interrupt handler and marks an interrupt source
134 * in RETU as a candidate for signal delivery to the user process.
136 static int retu_user_subscribe_to_irq(int id, struct file *filp)
138 int ret;
140 mutex_lock(&retu_mutex);
141 if ((retu_irq_subscr != NULL) && (retu_irq_subscr != filp)) {
142 mutex_unlock(&retu_mutex);
143 return -EBUSY;
145 /* Store the file pointer of the first user process registering IRQs */
146 retu_irq_subscr = filp;
147 mutex_unlock(&retu_mutex);
149 if (retu_irq_bits & (1 << id))
150 return 0;
152 ret = retu_request_irq(id, retu_user_irq_handler, id, "");
153 if (ret < 0)
154 return ret;
156 /* Mark that this interrupt has a handler */
157 retu_irq_bits |= 1 << id;
159 return 0;
163 * Unregisters all RETU interrupt handlers.
165 static void retu_unreg_irq_handlers(void)
167 int id;
169 if (!retu_irq_bits)
170 return;
172 for (id = 0; id < MAX_RETU_IRQ_HANDLERS; id++)
173 if (retu_irq_bits & (1 << id))
174 retu_free_irq(id);
176 retu_irq_bits = 0;
180 * Write to RETU register.
181 * Returns 0 upon success, a negative error value otherwise.
183 static int retu_user_write_with_mask(u32 field, u16 value)
185 u32 mask;
186 u32 reg;
187 u_short tmp;
188 unsigned long flags;
190 mask = MASK(field);
191 reg = REG(field);
193 /* Detect bad mask and reg */
194 if (mask == 0 || reg > RETU_REG_MAX ||
195 retu_access_bits[reg] == READ_ONLY) {
196 printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
197 reg, mask);
198 return -EINVAL;
201 /* Justify value according to mask */
202 while (!(mask & 1)) {
203 value = value << 1;
204 mask = mask >> 1;
207 spin_lock_irqsave(&retu_lock, flags);
208 if (retu_access_bits[reg] == TOGGLE) {
209 /* No need to detect previous content of register */
210 tmp = 0;
211 } else {
212 /* Read current value of register */
213 tmp = retu_read_reg(reg);
216 /* Generate new value */
217 tmp = (tmp & ~MASK(field)) | (value & MASK(field));
218 /* Write data to RETU */
219 retu_write_reg(reg, tmp);
220 spin_unlock_irqrestore(&retu_lock, flags);
222 return 0;
226 * Read RETU register.
228 static u32 retu_user_read_with_mask(u32 field)
230 u_short value;
231 u32 mask, reg;
233 mask = MASK(field);
234 reg = REG(field);
236 /* Detect bad mask and reg */
237 if (mask == 0 || reg > RETU_REG_MAX) {
238 printk(KERN_ERR PFX "invalid arguments (reg=%#x, mask=%#x)\n",
239 reg, mask);
240 return -EINVAL;
243 /* Read the register */
244 value = retu_read_reg(reg) & mask;
246 /* Right justify value */
247 while (!(mask & 1)) {
248 value = value >> 1;
249 mask = mask >> 1;
252 return value;
256 * Close device
258 static int retu_close(struct inode *inode, struct file *filp)
260 /* Unregister all interrupts that have been registered */
261 if (retu_irq_subscr == filp) {
262 retu_unreg_irq_handlers();
263 retu_irq_subscr = NULL;
266 return 0;
270 * Device control (ioctl)
272 static int retu_ioctl(struct inode *inode, struct file *filp,
273 unsigned int cmd, unsigned long arg)
275 struct retu_tahvo_write_parms par;
276 int ret;
278 switch (cmd) {
279 case URT_IOCT_IRQ_SUBSCR:
280 return retu_user_subscribe_to_irq(arg, filp);
281 case RETU_IOCH_READ:
282 return retu_user_read_with_mask(arg);
283 case RETU_IOCX_WRITE:
284 ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
285 if (ret)
286 printk(KERN_ERR "copy_from_user failed: %d\n", ret);
287 par.result = retu_user_write_with_mask(par.field, par.value);
288 ret = copy_to_user((void __user *) arg, &par, sizeof(par));
289 if (ret)
290 printk(KERN_ERR "copy_to_user failed: %d\n", ret);
291 break;
292 case RETU_IOCH_ADC_READ:
293 return retu_read_adc(arg);
294 default:
295 return -ENOIOCTLCMD;
297 return 0;
301 * Read from device
303 static ssize_t retu_read(struct file *filp, char *buf, size_t count,
304 loff_t * offp)
306 struct retu_irq *irq;
308 u32 nr, i;
310 /* read not permitted if neither filp nor anyone has registered IRQs */
311 if (retu_irq_subscr != filp)
312 return -EPERM;
314 if ((count < sizeof(u32)) || ((count % sizeof(u32)) != 0))
315 return -EINVAL;
317 nr = count / sizeof(u32);
319 for (i = 0; i < nr; i++) {
320 unsigned long flags;
321 u32 irq_id;
322 int ret;
324 ret = wait_event_interruptible(retu_user_waitqueue,
325 !list_empty(&retu_irqs));
326 if (ret < 0)
327 return ret;
329 spin_lock_irqsave(&retu_irqs_lock, flags);
330 irq = list_entry((&retu_irqs)->next, struct retu_irq, node);
331 irq_id = irq->id;
332 list_move(&irq->node, &retu_irqs_reserve);
333 spin_unlock_irqrestore(&retu_irqs_lock, flags);
335 ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id,
336 sizeof(irq_id));
337 if (ret)
338 printk(KERN_ERR "copy_to_user failed: %d\n", ret);
341 return count;
345 * Poll method
347 static unsigned retu_poll(struct file *filp, struct poll_table_struct *pt)
349 if (!list_empty(&retu_irqs))
350 return POLLIN;
352 poll_wait(filp, &retu_user_waitqueue, pt);
354 if (!list_empty(&retu_irqs))
355 return POLLIN;
356 else
357 return 0;
360 static struct file_operations retu_user_fileops = {
361 .owner = THIS_MODULE,
362 .ioctl = retu_ioctl,
363 .read = retu_read,
364 .release = retu_close,
365 .poll = retu_poll
368 static struct miscdevice retu_device = {
369 .minor = MISC_DYNAMIC_MINOR,
370 .name = "retu",
371 .fops = &retu_user_fileops
375 * Initialization
377 * @return 0 if successful, error value otherwise.
379 int retu_user_init(void)
381 struct retu_irq *irq;
382 int res, i;
384 irq = kmalloc(sizeof(*irq) * RETU_MAX_IRQ_BUF_LEN, GFP_KERNEL);
385 if (irq == NULL) {
386 printk(KERN_ERR PFX "kmalloc failed\n");
387 return -ENOMEM;
389 memset(irq, 0, sizeof(*irq) * RETU_MAX_IRQ_BUF_LEN);
390 for (i = 0; i < RETU_MAX_IRQ_BUF_LEN; i++)
391 list_add(&irq[i].node, &retu_irqs_reserve);
393 retu_irq_block = irq;
395 spin_lock_init(&retu_irqs_lock);
396 mutex_init(&retu_mutex);
398 /* Request a misc device */
399 res = misc_register(&retu_device);
400 if (res < 0) {
401 printk(KERN_ERR PFX "unable to register misc device for %s\n",
402 retu_device.name);
403 kfree(irq);
404 return res;
407 return 0;
411 * Cleanup.
413 void retu_user_cleanup(void)
415 /* Unregister our misc device */
416 misc_deregister(&retu_device);
417 /* Unregister and disable all RETU interrupts used by this module */
418 retu_unreg_irq_handlers();
419 kfree(retu_irq_block);
422 MODULE_DESCRIPTION("Retu ASIC user space functions");
423 MODULE_LICENSE("GPL");
424 MODULE_AUTHOR("Mikko Ylinen");