Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 104768
b: refs/heads/master
c: 328a14e
h: refs/heads/master
v: v3
  • Loading branch information
Hans J. Koch authored and Greg Kroah-Hartman committed Jul 22, 2008
1 parent 460c0d9 commit b197efe
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 934da4766e5f72797118f7c014efaef567a812fc
refs/heads/master: 328a14e70e7f46997cb50d4258dd93d5377f98c6
40 changes: 39 additions & 1 deletion trunk/Documentation/DocBook/uio-howto.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
</abstract>

<revhistory>
<revision>
<revnumber>0.5</revnumber>
<date>2008-05-22</date>
<authorinitials>hjk</authorinitials>
<revremark>Added description of write() function.</revremark>
</revision>
<revision>
<revnumber>0.4</revnumber>
<date>2007-11-26</date>
Expand Down Expand Up @@ -64,7 +70,7 @@
<?dbhtml filename="copyright.html"?>
<title>Copyright and License</title>
<para>
Copyright (c) 2006 by Hans-Jürgen Koch.</para>
Copyright (c) 2006-2008 by Hans-Jürgen Koch.</para>
<para>
This documentation is Free Software licensed under the terms of the
GPL version 2.
Expand Down Expand Up @@ -189,6 +195,30 @@ interested in translating it, please email me
represents the total interrupt count. You can use this number
to figure out if you missed some interrupts.
</para>
<para>
For some hardware that has more than one interrupt source internally,
but not separate IRQ mask and status registers, there might be
situations where userspace cannot determine what the interrupt source
was if the kernel handler disables them by writing to the chip's IRQ
register. In such a case, the kernel has to disable the IRQ completely
to leave the chip's register untouched. Now the userspace part can
determine the cause of the interrupt, but it cannot re-enable
interrupts. Another cornercase is chips where re-enabling interrupts
is a read-modify-write operation to a combined IRQ status/acknowledge
register. This would be racy if a new interrupt occurred
simultaneously.
</para>
<para>
To address these problems, UIO also implements a write() function. It
is normally not used and can be ignored for hardware that has only a
single interrupt source or has separate IRQ mask and status registers.
If you need it, however, a write to <filename>/dev/uioX</filename>
will call the <function>irqcontrol()</function> function implemented
by the driver. You have to write a 32-bit value that is usually either
0 or 1 to disable or enable interrupts. If a driver does not implement
<function>irqcontrol()</function>, <function>write()</function> will
return with <varname>-ENOSYS</varname>.
</para>

<para>
To handle interrupts properly, your custom kernel module can
Expand Down Expand Up @@ -362,6 +392,14 @@ device is actually used.
<function>open()</function>, you will probably also want a custom
<function>release()</function> function.
</para></listitem>

<listitem><para>
<varname>int (*irqcontrol)(struct uio_info *info, s32 irq_on)
</varname>: Optional. If you need to be able to enable or disable
interrupts from userspace by writing to <filename>/dev/uioX</filename>,
you can implement this function. The parameter <varname>irq_on</varname>
will be 0 to disable interrupts and 1 to enable them.
</para></listitem>
</itemizedlist>

<para>
Expand Down
26 changes: 26 additions & 0 deletions trunk/drivers/uio/uio.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,31 @@ static ssize_t uio_read(struct file *filep, char __user *buf,
return retval;
}

static ssize_t uio_write(struct file *filep, const char __user *buf,
size_t count, loff_t *ppos)
{
struct uio_listener *listener = filep->private_data;
struct uio_device *idev = listener->dev;
ssize_t retval;
s32 irq_on;

if (idev->info->irq == UIO_IRQ_NONE)
return -EIO;

if (count != sizeof(s32))
return -EINVAL;

if (!idev->info->irqcontrol)
return -ENOSYS;

if (copy_from_user(&irq_on, buf, count))
return -EFAULT;

retval = idev->info->irqcontrol(idev->info, irq_on);

return retval ? retval : sizeof(s32);
}

static int uio_find_mem_index(struct vm_area_struct *vma)
{
int mi;
Expand Down Expand Up @@ -546,6 +571,7 @@ static const struct file_operations uio_fops = {
.open = uio_open,
.release = uio_release,
.read = uio_read,
.write = uio_write,
.mmap = uio_mmap,
.poll = uio_poll,
.fasync = uio_fasync,
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/uio_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct uio_device;
* @mmap: mmap operation for this uio device
* @open: open operation for this uio device
* @release: release operation for this uio device
* @irqcontrol: disable/enable irqs when 0/1 is written to /dev/uioX
*/
struct uio_info {
struct uio_device *uio_dev;
Expand All @@ -66,6 +67,7 @@ struct uio_info {
int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
int (*open)(struct uio_info *info, struct inode *inode);
int (*release)(struct uio_info *info, struct inode *inode);
int (*irqcontrol)(struct uio_info *info, s32 irq_on);
};

extern int __must_check
Expand Down

0 comments on commit b197efe

Please sign in to comment.