aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans J. Koch <hjk@linutronix.de>2008-05-23 07:50:14 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-07-22 00:54:55 -0400
commit328a14e70e7f46997cb50d4258dd93d5377f98c6 (patch)
tree7cc64b122fc45af454d4dde9f561b329d9f2b0c4
parent934da4766e5f72797118f7c014efaef567a812fc (diff)
UIO: Add write function to allow irq masking
Sometimes it is necessary to enable/disable the interrupt of a UIO device from the userspace part of the driver. With this patch, the UIO kernel driver can implement an "irqcontrol()" function that does this. Userspace can write an s32 value to /dev/uioX (usually 0 or 1 to turn the irq off or on). The UIO core will then call the driver's irqcontrol function. Signed-off-by: Hans J. Koch <hjk@linutronix.de> Acked-by: Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> Acked-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--Documentation/DocBook/uio-howto.tmpl40
-rw-r--r--drivers/uio/uio.c26
-rw-r--r--include/linux/uio_driver.h2
3 files changed, 67 insertions, 1 deletions
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
index fdd7f4f887b7..c4d187313963 100644
--- a/Documentation/DocBook/uio-howto.tmpl
+++ b/Documentation/DocBook/uio-howto.tmpl
@@ -30,6 +30,12 @@
30 30
31<revhistory> 31<revhistory>
32 <revision> 32 <revision>
33 <revnumber>0.5</revnumber>
34 <date>2008-05-22</date>
35 <authorinitials>hjk</authorinitials>
36 <revremark>Added description of write() function.</revremark>
37 </revision>
38 <revision>
33 <revnumber>0.4</revnumber> 39 <revnumber>0.4</revnumber>
34 <date>2007-11-26</date> 40 <date>2007-11-26</date>
35 <authorinitials>hjk</authorinitials> 41 <authorinitials>hjk</authorinitials>
@@ -64,7 +70,7 @@
64<?dbhtml filename="copyright.html"?> 70<?dbhtml filename="copyright.html"?>
65<title>Copyright and License</title> 71<title>Copyright and License</title>
66<para> 72<para>
67 Copyright (c) 2006 by Hans-Jürgen Koch.</para> 73 Copyright (c) 2006-2008 by Hans-Jürgen Koch.</para>
68<para> 74<para>
69This documentation is Free Software licensed under the terms of the 75This documentation is Free Software licensed under the terms of the
70GPL version 2. 76GPL version 2.
@@ -189,6 +195,30 @@ interested in translating it, please email me
189 represents the total interrupt count. You can use this number 195 represents the total interrupt count. You can use this number
190 to figure out if you missed some interrupts. 196 to figure out if you missed some interrupts.
191 </para> 197 </para>
198 <para>
199 For some hardware that has more than one interrupt source internally,
200 but not separate IRQ mask and status registers, there might be
201 situations where userspace cannot determine what the interrupt source
202 was if the kernel handler disables them by writing to the chip's IRQ
203 register. In such a case, the kernel has to disable the IRQ completely
204 to leave the chip's register untouched. Now the userspace part can
205 determine the cause of the interrupt, but it cannot re-enable
206 interrupts. Another cornercase is chips where re-enabling interrupts
207 is a read-modify-write operation to a combined IRQ status/acknowledge
208 register. This would be racy if a new interrupt occurred
209 simultaneously.
210 </para>
211 <para>
212 To address these problems, UIO also implements a write() function. It
213 is normally not used and can be ignored for hardware that has only a
214 single interrupt source or has separate IRQ mask and status registers.
215 If you need it, however, a write to <filename>/dev/uioX</filename>
216 will call the <function>irqcontrol()</function> function implemented
217 by the driver. You have to write a 32-bit value that is usually either
218 0 or 1 to disable or enable interrupts. If a driver does not implement
219 <function>irqcontrol()</function>, <function>write()</function> will
220 return with <varname>-ENOSYS</varname>.
221 </para>
192 222
193 <para> 223 <para>
194 To handle interrupts properly, your custom kernel module can 224 To handle interrupts properly, your custom kernel module can
@@ -362,6 +392,14 @@ device is actually used.
362<function>open()</function>, you will probably also want a custom 392<function>open()</function>, you will probably also want a custom
363<function>release()</function> function. 393<function>release()</function> function.
364</para></listitem> 394</para></listitem>
395
396<listitem><para>
397<varname>int (*irqcontrol)(struct uio_info *info, s32 irq_on)
398</varname>: Optional. If you need to be able to enable or disable
399interrupts from userspace by writing to <filename>/dev/uioX</filename>,
400you can implement this function. The parameter <varname>irq_on</varname>
401will be 0 to disable interrupts and 1 to enable them.
402</para></listitem>
365</itemizedlist> 403</itemizedlist>
366 404
367<para> 405<para>
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 5a7ca2e6094d..3a6934bf7131 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -427,6 +427,31 @@ static ssize_t uio_read(struct file *filep, char __user *buf,
427 return retval; 427 return retval;
428} 428}
429 429
430static ssize_t uio_write(struct file *filep, const char __user *buf,
431 size_t count, loff_t *ppos)
432{
433 struct uio_listener *listener = filep->private_data;
434 struct uio_device *idev = listener->dev;
435 ssize_t retval;
436 s32 irq_on;
437
438 if (idev->info->irq == UIO_IRQ_NONE)
439 return -EIO;
440
441 if (count != sizeof(s32))
442 return -EINVAL;
443
444 if (!idev->info->irqcontrol)
445 return -ENOSYS;
446
447 if (copy_from_user(&irq_on, buf, count))
448 return -EFAULT;
449
450 retval = idev->info->irqcontrol(idev->info, irq_on);
451
452 return retval ? retval : sizeof(s32);
453}
454
430static int uio_find_mem_index(struct vm_area_struct *vma) 455static int uio_find_mem_index(struct vm_area_struct *vma)
431{ 456{
432 int mi; 457 int mi;
@@ -546,6 +571,7 @@ static const struct file_operations uio_fops = {
546 .open = uio_open, 571 .open = uio_open,
547 .release = uio_release, 572 .release = uio_release,
548 .read = uio_read, 573 .read = uio_read,
574 .write = uio_write,
549 .mmap = uio_mmap, 575 .mmap = uio_mmap,
550 .poll = uio_poll, 576 .poll = uio_poll,
551 .fasync = uio_fasync, 577 .fasync = uio_fasync,
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
index 973386d439da..cf65e964102b 100644
--- a/include/linux/uio_driver.h
+++ b/include/linux/uio_driver.h
@@ -53,6 +53,7 @@ struct uio_device;
53 * @mmap: mmap operation for this uio device 53 * @mmap: mmap operation for this uio device
54 * @open: open operation for this uio device 54 * @open: open operation for this uio device
55 * @release: release operation for this uio device 55 * @release: release operation for this uio device
56 * @irqcontrol: disable/enable irqs when 0/1 is written to /dev/uioX
56 */ 57 */
57struct uio_info { 58struct uio_info {
58 struct uio_device *uio_dev; 59 struct uio_device *uio_dev;
@@ -66,6 +67,7 @@ struct uio_info {
66 int (*mmap)(struct uio_info *info, struct vm_area_struct *vma); 67 int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
67 int (*open)(struct uio_info *info, struct inode *inode); 68 int (*open)(struct uio_info *info, struct inode *inode);
68 int (*release)(struct uio_info *info, struct inode *inode); 69 int (*release)(struct uio_info *info, struct inode *inode);
70 int (*irqcontrol)(struct uio_info *info, s32 irq_on);
69}; 71};
70 72
71extern int __must_check 73extern int __must_check