From: Christoph Hellwig <hch@lst.de>

It's been totally obsoleted by the input layer

Acked-by: Alan Cox <alan@redhat.com>

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/Documentation/DocBook/Makefile          |    6 
 25-akpm/Documentation/DocBook/mousedrivers.tmpl | 1017 ------------------------
 2 files changed, 3 insertions(+), 1020 deletions(-)

diff -puN Documentation/DocBook/Makefile~remove-mousedriverssgml Documentation/DocBook/Makefile
--- 25/Documentation/DocBook/Makefile~remove-mousedriverssgml	2004-10-26 18:57:01.570205432 -0700
+++ 25-akpm/Documentation/DocBook/Makefile	2004-10-26 18:57:01.575204672 -0700
@@ -8,9 +8,9 @@
 
 DOCBOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
 	    kernel-hacking.sgml kernel-locking.sgml via-audio.sgml \
-	    mousedrivers.sgml deviceiobook.sgml procfs-guide.sgml \
-	    tulip-user.sgml writing_usb_driver.sgml scsidrivers.sgml \
-	    sis900.sgml kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml \
+	    deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \
+	    writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \
+	    kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml \
 	    gadget.sgml libata.sgml mtdnand.sgml librs.sgml
 
 ###
diff -puN Documentation/DocBook/mousedrivers.tmpl~remove-mousedriverssgml Documentation/DocBook/mousedrivers.tmpl
--- 25/Documentation/DocBook/mousedrivers.tmpl~remove-mousedriverssgml	2004-10-26 18:57:01.572205128 -0700
+++ 25-akpm/Documentation/DocBook/mousedrivers.tmpl	2004-10-26 18:57:01.581203760 -0700
@@ -1,1017 +0,0 @@
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
-
-<book id="MouseGuide">
- <bookinfo>
-  <title>Mouse Drivers</title>
-  
-  <authorgroup>
-   <author>
-    <firstname>Alan</firstname>
-    <surname>Cox</surname>
-    <affiliation>
-     <address>
-      <email>alan@redhat.com</email>
-     </address>
-    </affiliation>
-   </author>
-  </authorgroup>
-
-  <copyright>
-   <year>2000</year>
-   <holder>Alan Cox</holder>
-  </copyright>
-
-  <legalnotice>
-   <para>
-     This documentation is free software; you can redistribute
-     it and/or modify it under the terms of the GNU General Public
-     License as published by the Free Software Foundation; either
-     version 2 of the License, or (at your option) any later
-     version.
-   </para>
-      
-   <para>
-     This program is distributed in the hope that it will be
-     useful, but WITHOUT ANY WARRANTY; without even the implied
-     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-     See the GNU General Public License for more details.
-   </para>
-      
-   <para>
-     You should have received a copy of the GNU General Public
-     License along with this program; if not, write to the Free
-     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-     MA 02111-1307 USA
-   </para>
-      
-   <para>
-     For more details see the file COPYING in the source
-     distribution of Linux.
-   </para>
-  </legalnotice>
- </bookinfo>
-
- <toc></toc>
-
- <chapter id="intro">
-  <title>Introduction</title>
-  <note>
-   <title>Earlier publication</title>
-    <para>
-      Parts of this document first appeared in Linux Magazine under a
-      ninety day exclusivity.
-   </para>
-  </note> 
-
-  <para>
-    Mice are conceptually one of the simplest device interfaces in the 
-    Linux operating system. Not all mice are handled by the kernel. 
-    Instead there is a two layer abstraction.
-  </para>
-
-  <para>
-    The kernel mouse drivers and userspace drivers for the serial mice are
-    all managed by a system daemon called <application>gpm</application> 
-    - the general purpose mouse driver. <application>gpm</application> 
-    handles cutting and pasting on the text consoles. It provides a 
-    general library for mouse-aware applications and it handles the 
-    sharing of mouse services with the 
-    <application>X Window System</application> user interface.
-  </para>
-  <para>
-    Sometimes a mouse speaks a sufficiently convoluted protocol that the
-    protocol is handled by <application>Gpm</application> itself. Most 
-    of the mouse drivers follow a common interface called the bus mouse 
-    protocol.
-  </para>
-  <para>
-    Each read from a bus mouse interface device returns a block of data. 
-    The first three bytes of each read are defined as follows: 
-
-   <table frame="all">
-    <title>Mouse Data Encoding</title>
-    <tgroup cols="2" align="left">
-     <tbody>
-      <row>
-       <entry>Byte 0</entry>
-       <entry>0x80 + the buttons currently down.</entry>
-      </row>
-      <row>
-       <entry>Byte 1</entry>
-       <entry>A signed value for the shift in X position</entry>
-      </row>
-      <row>
-       <entry>Byte 2</entry>
-       <entry>A signed value for the shift in Y position</entry>
-      </row>
-     </tbody>
-    </tgroup>
-   </table>
-
-    An application can choose to read more than 3 bytes. The rest of the 
-    bytes will be zero, or may optionally return some additional 
-    device-specific information.
-  </para>
-  <para>
-    The position values are truncated if they exceed the 8bit range (that
-    is -127 &lt;= delta &lt;= 127). While the value -128 does fit into a 
-    byte is not allowed.
-  </para>
-  <para>
-    The <mousebutton>buttons</mousebutton> are numbered left to right as 
-    0, 1, 2, 3.. and each button sets the relevant bit. So a user pressing 
-    the left and right button of a three button mouse will set bits 0 and 2.
-  </para>
-  <para>
-    All mice are required to support the <function>poll</function> 
-    operation. Indeed pretty much every user of a mouse device uses 
-    <function>poll</function> to wait for mouse events to occur.
-  </para>
-  <para>
-    Finally the mice support asynchronous I/O. This is a topic we have not 
-    yet covered but which I will explain after looking at a simple mouse 
-    driver.
-  </para>
- </chapter>
-
- <chapter id="driver">
-  <title>A simple mouse driver</title>
-  <para>
-    First we will need the set up functions for our mouse device. To keep 
-    this simple our imaginary mouse device has three I/O ports fixed at I/O 
-    address 0x300 and always lives on interrupt 5.  The ports will be the X 
-    position, the Y position and the buttons in that order.
-  </para>
-
-  <programlisting>
-#define OURMOUSE_BASE        0x300
-
-static struct miscdevice our_mouse = {
-        OURMOUSE_MINOR, "ourmouse", &amp;our_mouse_fops
-};
-
-__init ourmouse_init(void)
-{
-
-        if (request_region(OURMOUSE_BASE, 3, "ourmouse") < 0) {
-		printk(KERN_ERR "ourmouse: request_region failed.\n");
-                return -ENODEV;
-	}
-
-        if (misc_register(&amp;our_mouse) < 0) {
-		printk(KERN_ERR "ourmouse: cannot register misc device.\n");
-		release_region(OURMOUSE_BASE, 3);
-		return -EBUSY;
-	}
-
-        return 0;
-}
-  </programlisting>
-
-  <para>
-    The <structname>miscdevice</structname> is new here. Linux normally 
-    parcels devices out by major number, and each device has 256 units. 
-    For things like mice this is extremely wasteful so a device exists 
-    which is used to accumulate all the odd individual devices that 
-    computers tend to have.
-  </para>
-  <para>
-    Minor numbers in this space are allocated by a central source, although 
-    you can look in the kernel <filename>Documentation/devices.txt</filename>
-    file and pick a free one for development use. This kernel file also 
-    carries instructions for registering a device. This may change over time 
-    so it is a good idea to obtain a current copy of this file first.
-  </para>
-  <para>
-    Our code then is fairly simple. We reserve our I/O address space with
-    request_region, checking to make sure that it succeeded (i.e. the
-    space wasn't reserved by anyone else). 
-  </para>
-  <para>
-    Then we ask the misc driver to allocate our minor device number. We also
-    hand it our name (which is used in 
-    <filename class="directory">/proc/misc</filename>) and a set of file 
-    operations that are to be used. The file operations work exactly like the 
-    file operations you would register for a normal character device. The misc 
-    device itself is simply acting as a redirector for requests.
-    Since misc_register can fail, it is important to check for failure
-    and act accordingly (which in the case of a mouse driver is to abort,
-    since you can't use the mouse without a working device node).
-  </para>
-  <para>
-    Next, in order to be able to use and test our code we need to add some 
-    startup and shutdown code to support it. This too is fairly simple:
-  </para>
-  <programlisting>
-static int init(void)
-{
-        if(ourmouse_init()&lt;0)
-                return -ENODEV:
-        return 0;
-}
-
-static void cleanup(void)
-{
-        misc_deregister(&amp;our_mouse);
-        free_region(OURMOUSE_BASE, 3);
-}
-module_init(init);
-module_exit(cleanup);
-  </programlisting>
-
-  <para>
-    The <function>module_init</function> macro sets the function to call when the module is inserted (or at boot if the module were built into the kernel).  In our case it is <function>init</function>, which simply calls the initialising function we wrote
-    and returns an error if this fails. This ensures the module will only 
-    be loaded if it was successfully set up.
-  </para>
-  <para>
-    The <function>module_exit</function> macro sets the function to call when the
-    module is unloaded: if this is not set, the module cannot be unloaded. We give the miscellaneous device entry back, and
-    then free our I/O resources. If we didn't free the I/O resources then 
-    the next time the module loaded it would think someone else had its I/O 
-    space.
-  </para>
-  <para>
-    Once the <function>misc_deregister</function> has been called any 
-    attempts to open the mouse device will fail with the error  
-    <errorcode>ENODEV</errorcode> (<errorname>No such device</errorname>).
-  </para>
-  <para>
-    Next we need to fill in our file operations. A mouse doesn't need many 
-    of these. We need to provide open, release, read and poll. That makes 
-    for a nice simple structure:
-  </para>
-
-  <programlisting>
-struct file_operations our_mouse_fops = {
-        owner: THIS_MODULE,            /* Automatic usage management */
-        read:  read_mouse,             /* You can read a mouse */
-        write: write_mouse,            /* This won't do a lot */
-        poll:  poll_mouse,             /* Poll */
-        open:  open_mouse,             /* Called on open */
-        release: close_mouse,          /* Called on close */
-};
-  </programlisting>
-
-  <para>
-    There is nothing particularly special needed here. We provide functions 
-    for all the relevant or required operations and little else. There is 
-    nothing stopping us providing an ioctl function for this mouse. Indeed 
-    if you have a configurable mouse it may be very appropriate to provide 
-    configuration interfaces via ioctl calls.
-  </para>
-  <para>
-    The syntax we use is not standard C as such. GCC provides the ability
-    to initialise fields by name, and this generally makes the method table
-    much easier to read than counting through NULL pointers and remembering
-    the order by hand.
-  </para>
-  <para>
-    The owner field is used to manage the locking of module load an
-    unloading. It is obviously important that a module is not unloaded while
-    in use. When your device is opened the module specified by "owner" is 
-    locked. When it is finally released the module is unlocked.
-  </para>
-  <para>
-    The open and close routines need to manage enabling and disabling the 
-    interrupts for the mouse as well as stopping the mouse being unloaded
-    when it is no longer required. 
-  </para>
-
-  <programlisting>
-static int mouse_users = 0;                /* User count */
-static int mouse_dx = 0;                   /* Position changes */
-static int mouse_dy = 0;
-static int mouse_event = 0;                /* Mouse has moved */
-
-static int open_mouse(struct inode *inode, struct file *file)
-{
-        if(mouse_users++)
-                return 0;
-
-        if(request_irq(mouse_intr, OURMOUSE_IRQ, 0, "ourmouse", NULL))
-        {
-                mouse_users--;
-                return -EBUSY;
-        }
-        mouse_dx = 0;
-        mouse_dy = 0;
-        mouse_event = 0;
-        mouse_buttons = 0;
-	return 0;
-}
-  </programlisting>
-  <para>
-    The open function has to do a small amount of housework. We keep a count 
-    of the number of times the mouse is open. This is because we do not want 
-    to request the interrupt multiple times. If the mouse has at least one 
-    user then it is set up and we simply add to the user count and return
-    <returnvalue>0</returnvalue> for success.
-  </para>
-  <para>
-    We grab the interrupt and thus start mouse interrupts. If the interrupt 
-    has been borrowed by some other driver then <function>request_irq</function>
-    will fail and we will return an error. If we were capable of sharing an 
-    interrupt line we would specify <constant>SA_SHIRQ</constant> instead of 
-    <constant>zero</constant>. Provided that everyone claiming an interrupt 
-    sets this flag, they get to share the line. <hardware>PCI</hardware> can 
-    share interrupts, <hardware>ISA</hardware> normally however cannot. 
-  </para>
-  <para>
-    We do the housekeeping. We make the current mouse position the starting
-    point for accumulated changes and declare that nothing has happened
-    since the mouse driver was opened.
-  </para>
-  <para>
-    The release function needs to unwind all these:
-  </para>
-  <programlisting>
-static int close_mouse(struct inode *inode, struct file *file)
-{
-        if(--mouse_users)
-                return 0;
-        free_irq(OURMOUSE_IRQ, NULL);
-        return 0;
-}
-  </programlisting>
-  <para>
-    We count off a user and provided that there are still other users need 
-    take no further action. The last person closing the mouse causes us to 
-    free up the interrupt. This stops interrupts from the mouse from using 
-    our CPU time, and ensures that the mouse can now be unloaded.
-  </para>
-  <para>
-    We can fill in the write handler at this point as the write function for 
-    our mouse simply declines to allow writes:
-  </para>
-
-  <programlisting>
-static ssize_t write_mouse(struct file *file, const char *buffer, size_t
-                                count, loff_t *ppos)
-{
-        return -EINVAL;
-}
-  </programlisting>
-
-  <para>
-    This is pretty much self-explanatory. Whenever you write you get told 
-    it was an invalid function.
-  </para>
-  <para>
-    To make the poll and read functions work we have to consider how we 
-    handle the mouse interrupt. 
-  </para>
-
-  <programlisting>
-static struct wait_queue *mouse_wait;
-static spinlock_t mouse_lock = SPIN_LOCK_UNLOCKED;
-
-static void ourmouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        char delta_x;
-        char delta_y;
-        unsigned char new_buttons;
-
-        delta_x = inb(OURMOUSE_BASE);
-        delta_y = inb(OURMOUSE_BASE+1);
-        new_buttons = inb(OURMOUSE_BASE+2);
-
-        if(delta_x || delta_y || new_buttons != mouse_buttons)
-        {
-                /* Something happened */
-
-                spin_lock(&amp;mouse_lock);
-                mouse_event = 1;
-                mouse_dx += delta_x;
-                mouse_dy += delta_y;
-                mouse_buttons = new_buttons;
-                spin_unlock(&amp;mouse_lock);
-                
-                wake_up_interruptible(&amp;mouse_wait);
-        }
-}
-  </programlisting>
-
-  <para>
-    The interrupt handler reads the mouse status. The next thing we do is 
-    to check whether something has changed. If the mouse was smart it would
-    only interrupt us if something had changed, but let's assume our mouse 
-    is stupid as most mice actually tend to be. 
-  </para>
-  <para>
-    If the mouse has changed we need to update the status variables. What we
-    don't want is the mouse functions reading these variables to read them
-    during a change. We add a spinlock that protects these variables while we
-    play with them.
-  </para>
-  <para>
-    If a change has occurred we also need to wake sleeping processes, so we 
-    add a wakeup call and a <structname>wait_queue</structname> to use when 
-    we wish to await a mouse event.
-  </para>
-  <para>
-    Now we have the wait queue we can implement the poll function for the 
-    mouse relatively easily:
-  </para>
-
-  <programlisting>
-static unsigned int mouse_poll(struct file *file, poll_table *wait)
-{
-        poll_wait(file, &amp;mouse_wait, wait);
-        if(mouse_event)
-                return POLLIN | POLLRDNORM;
-        return 0;
-}
-  </programlisting>
-
-  <para>
-    This is fairly standard poll code. First we add the wait queue to the 
-    list of queues we want to monitor for an event. Secondly we check if an 
-    event has occurred. We only have one kind of event - the 
-    <varname>mouse_event</varname> flag tells us that something happened. 
-    We know that this something can only be mouse data. We return the flags 
-    indicating input and normal reading will succeed.
-  </para>
-  <para>
-    You may be wondering what happens if the function returns saying 'no 
-    event yet'. In this case the wake up from the wait queue we added to 
-    the poll table will cause the function to be called again. Eventually 
-    we will be woken up and have an event ready. At this point the 
-    <function>poll</function> call will exit back to the user.
-  </para>
-  <para>
-    After the poll completes the user will want to read the data. We now 
-    need to think about how our <function>mouse_read</function> function 
-    will work:
-  </para>
-  <programlisting>
-static ssize_t mouse_read(struct file *file, char *buffer, 
-                size_t count, loff_t *pos)
-{
-        int dx, dy;
-        unsigned char button;
-        unsigned long flags;
-        int n;
-
-        if(count&lt;3)
-                return -EINVAL;
-
-        /*
-          *        Wait for an event
-         */
-
-        while(!mouse_event)
-        {
-                if(file-&gt;f_flags&amp;O_NDELAY)
-                        return -EAGAIN;
-                interruptible_sleep_on(&amp;mouse_wait);
-                if(signal_pending(current))
-                        return -ERESTARTSYS;
-        }
-  </programlisting>
-
-  <para>
-    We start by validating that the user is reading enough data. We could 
-    handle partial reads if we wanted but it isn't terribly useful and the 
-    mouse drivers don't bother to try.
-  </para>
-  <para>
-    Next we wait for an event to occur. The loop is fairly standard event
-    waiting in Linux. Having checked that the event has not yet occurred, we
-    then check if an event is pending and if not we need to sleep. 
-  </para>
-  <para>
-    A user process can set the <constant>O_NDELAY</constant> flag on a file 
-    to indicate that it wishes to be told immediately if no event is 
-    pending. We check this and give the appropriate error if so. 
-  </para>
-  <para>
-    Next we sleep until the mouse or a signal awakens us. A signal will 
-    awaken us as we have used <function>wakeup_interruptible</function>. 
-    This is important as it means a user can kill processes waiting for 
-    the mouse - clearly a desirable property. If we are interrupted we 
-    exit the call and the kernel will then process signals and maybe 
-    restart the call again - from the beginning.
-  </para>
-  <para>
-    This code contains a classic Linux bug. All will be revealed later in this
-    article as well as explanations for how to avoid it.
-  </para>
-  <programlisting>
-        /* Grab the event */
-
-        spinlock_irqsave(&amp;mouse_lock, flags);
-
-        dx = mouse_dx;
-        dy = mouse_dy;
-        button = mouse_buttons;
-
-        if(dx&lt;=-127)
-                dx=-127;
-        if(dx&gt;=127)
-                dx=127;
-        if(dy&lt;=-127)
-                dy=-127;
-        if(dy&gt;=127)
-                dy=127;
-
-        mouse_dx -= dx;
-        mouse_dy -= dy;
-        
-        if(mouse_dx == 0 &amp;&amp; mouse_dy == 0)
-                mouse_event = 0;
-
-        spin_unlock_irqrestore(&amp;mouse_lock, flags);
-  </programlisting>
-  <para>
-    This is the next stage. Having established that there is an event 
-    going, we capture it. To be sure that the event is not being updated 
-    as we capture it we also take the spinlock and thus prevent parallel 
-    updates. Note here we use <function>spinlock_irqsave</function>. We 
-    need to disable interrupts on the local processor otherwise bad things 
-    will happen.
-  </para>
-  <para>
-    What will occur is that we take the spinlock. While we hold the lock 
-    an interrupt will occur. At this point our interrupt handler will try 
-    and take the spinlock. It will sit in a loop waiting for the read 
-    routine to release the lock. However because we are sitting in a loop 
-    in the interrupt handler we will never release the lock. The machine 
-    hangs and the user gets upset.
-  </para>
-  <para>
-    By blocking the interrupt on this processor we ensure that the lock 
-    holder will always give the lock back without deadlocking.
-  </para>
-  <para>
-    There is a little cleverness in the reporting mechanism too. We can 
-    only report a move of 127 per read. We don't however want to lose 
-    information by throwing away further movement. Instead we keep 
-    returning as much information as possible. Each time we return a 
-    report we remove the amount from the pending movement in 
-    <varname>mouse_dx</varname> and <varname>mouse_dy</varname>. Eventually 
-    when these counts hit zero we clear the <varname>mouse_event</varname>
-    flag as there is nothing else left to report.
-  </para>
-
-  <programlisting>
-        if(put_user(button|0x80, buffer))
-                return -EFAULT;
-        if(put_user((char)dx, buffer+1))
-                return -EFAULT;
-        if(put_user((char)dy, buffer+2))
-                return -EFAULT;
-
-        for(n=3; n < count; n++)
-                if(put_user(0x00, buffer+n))
-                        return -EFAULT;
-
-        return count;
-}
-  </programlisting>
-
-  <para>
-    Finally we must put the results in the user supplied buffer. We cannot 
-    do this while holding the lock as a write to user memory may sleep. 
-    For example the user memory may be residing on disk at this instant. 
-    Thus we did our computation beforehand and now copy the data. Each 
-    <function>put_user call</function> is filling in one byte of the buffer. 
-    If it returns an error we inform the program that it passed us an 
-    invalid buffer and abort.
-  </para>
-  <para>
-    Having written the data we blank the rest of the buffer that was read 
-    and report the read as being successful.
-  </para>
- </chapter>
-
- <chapter id="debugging">
-  <title>Debugging the mouse driver</title>
-
-  <para>
-    We now have an almost perfectly usable mouse driver. If you were to 
-    actually try and use it however you would eventually find a couple of 
-    problems with it. A few programs will also not work with as it does not 
-    yet support asynchronous I/O.
-  </para>
-  <para>
-    First let us look at the bugs. The most obvious one isn't really a driver
-    bug but a failure to consider the consequences. Imagine you bumped the 
-    mouse hard by accident and sent it skittering across the desk. The mouse 
-    interrupt routine will add up all that movement and report it in steps of 
-    127 until it has reported all of it. Clearly there is a point beyond 
-    which mouse movement isn't worth reporting. We need to add this as a 
-    limit to the interrupt handler:
-  </para>
-
-  <programlisting>
-static void ourmouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        char delta_x;
-        char delta_y;
-        unsigned char new_buttons;
-
-        delta_x = inb(OURMOUSE_BASE);
-        delta_y = inb(OURMOUSE_BASE+1);
-        new_buttons = inb(OURMOUSE_BASE+2);
-
-        if(delta_x || delta_y || new_buttons != mouse_buttons)
-        {
-                /* Something happened */
-
-                spin_lock(&amp;mouse_lock);
-                mouse_event = 1;
-                mouse_dx += delta_x;
-                mouse_dy += delta_y;
-
-                if(mouse_dx &lt; -4096)
-                        mouse_dx = -4096;
-                if(mouse_dx &gt; 4096)
-                        mouse_dx = 4096;
-
-                if(mouse_dy &lt; -4096)
-                        mouse_dy = -4096;
-                if(mouse_dy &gt; 4096)
-                        mouse_dy = 4096;
-
-                mouse_buttons = new_buttons;
-                spin_unlock(&amp;mouse_lock);
-                
-                wake_up_interruptible(&amp;mouse_wait);
-        }
-}
-  </programlisting>
-
-  <para>
-    By adding these checks we limit the range of accumulated movement to
-    something sensible. 
-  </para>
-  <para>
-    The second bug is a bit more subtle, and that is perhaps why this is 
-    such a common mistake. Remember, I said the waiting loop for the read 
-    handler had a bug in it. Think about what happens when we execute:
-  </para>
-
-  <programlisting>
-        while(!mouse_event)
-        {
-  </programlisting>
-
-  <para>
-    and an interrupt occurs at this point here. This causes a mouse movement
-    and wakes up the queue. 
-  </para>
-
-  <programlisting>
-                interruptible_sleep_on(&amp;mouse_wait);
-  </programlisting>
-
-  <para>
-    Now we sleep on the queue. We missed the wake up and the application 
-    will not see an event until the next mouse event occurs. This will 
-    lead to just the odd instance when a mouse button gets delayed. The 
-    consequences to the user will probably be almost undetectable with a 
-    mouse driver. With other drivers this bug could be a lot more severe.
-  </para>
-  <para>
-    There are two ways to solve this. The first is to disable interrupts 
-    during the testing and the sleep. This works because when a task sleeps 
-    it ceases to disable interrupts, and when it resumes it disables them 
-    again. Our code thus becomes:
-  </para>
-
-  <programlisting>
-        save_flags(flags);
-        cli();
-
-        while(!mouse_event)
-        {
-                if(file-&gt;f_flags&amp;O_NDELAY)
-                {
-                        restore_flags(flags);
-                        return -EAGAIN;
-                }
-                interruptible_sleep_on(&amp;mouse_wait);
-                if(signal_pending(current))
-                {
-                        restore_flags(flags);
-                        return -ERESTARTSYS;
-                }
-        }
-        restore_flags(flags);
-  </programlisting>
-
-  <para>
-    This is the sledgehammer approach. It works but it means we spend a 
-    lot more time turning interrupts on and off. It also affects 
-    interrupts globally and has bad properties on multiprocessor machines 
-    where turning interrupts off globally is not a simple operation, but 
-    instead involves kicking each processor, waiting for them to disable 
-    interrupts and reply.
-  </para>
-  <para>
-    The real problem is the race between the event testing and the sleeping. 
-    We can avoid that by using the scheduling functions more directly. 
-    Indeed this is the way they generally should be used for an interrupt.
-  </para>
-
-  <programlisting>
-        struct wait_queue wait = { current, NULL };
-
-        add_wait_queue(&amp;mouse_wait, &amp;wait);
-        set_current_state(TASK_INTERRUPTIBLE);
-        
-        while(!mouse_event)
-        {
-                if(file-&gt;f_flags&amp;O_NDELAY)
-                {
-                        remove_wait_queue(&amp;mouse_wait, &amp;wait);
-                        set_current_state(TASK_RUNNING);
-                        return -EWOULDBLOCK;
-                }
-                if(signal_pending(current))
-                {
-                        remove_wait_queue(&amp;mouse_wait, &amp;wait);
-                        current-&gt;state = TASK_RUNNING;
-                        return -ERESTARTSYS;
-                }
-                schedule();
-                set_current_state(TASK_INTERRUPTIBLE);
-        }
-        
-        remove_wait_wait(&amp;mouse_wait, &amp;wait);
-        set_current_state(TASK_RUNNING);
-  </programlisting>
-
-  <para>
-    At first sight this probably looks like deep magic. To understand how 
-    this works you need to understand how scheduling and events work on 
-    Linux. Having a good grasp of this is one of the keys to writing clean 
-    efficient device drivers.
-  </para>
-  <para>
-    <function>add_wait_queue</function> does what its name suggests. It adds 
-    an entry to the <varname>mouse_wait</varname> list. The entry in this 
-    case is the entry for our current process (<varname>current</varname>
-    is the current task pointer). 
-  </para>
-  <para>
-    So we start by adding an entry for ourself onto the 
-    <varname>mouse_wait</varname> list. This does not put us to sleep 
-    however. We are merely tagged onto the list. 
-  </para>
-  <para>
-    Next we set our status to <constant>TASK_INTERRUPTIBLE</constant>. Again 
-    this does not mean we are now asleep. This flag says what should happen 
-    next time the process sleeps. <constant>TASK_INTERRUPTIBLE</constant> says 
-    that the process should not be rescheduled. It will run from now until it 
-    sleeps and then will need to be woken up.
-  </para>
-  <para>
-    The <function>wakeup_interruptible</function> call in the interrupt 
-    handler can now be explained in more detail. This function is also very 
-    simple. It goes along the list of processes on the queue it is given and 
-    any that are marked as <constant>TASK_INTERRUPTIBLE</constant> it changes 
-    to <constant>TASK_RUNNING</constant> and tells the kernel that new 
-    processes are runnable.
-  </para>
-  <para>
-    Behind all the wrappers in the original code what is happening is this
-  </para>
-
-  <procedure>
-   <step>
-    <para>
-      We add ourself to the mouse wait queue
-    </para>
-   </step>
-   <step>
-    <para>
-      We mark ourself as sleeping
-    </para>
-   </step>
-   <step>
-    <para>
-      We ask the kernel to schedule tasks again
-    </para>
-   </step>
-   <step>
-    <para>
-      The kernel sees we are asleep and schedules someone else.
-    </para>
-   </step>
-   <step>
-    <para>
-      The mouse interrupt sets our state to <constant>TASK_RUNNING</constant> 
-      and makes a note that the kernel should reschedule tasks
-    </para>
-   </step>
-   <step>
-    <para>
-      The kernel sees we are running again and continues our execution
-    </para>
-   </step>
-  </procedure>
-  <para>
-    This is why the apparent magic works. Because we mark ourself as
-    <constant>TASK_INTERRUPTIBLE</constant> and as we add ourselves 
-    to the queue before we check if there are events pending, the race 
-    condition is removed.
-  </para>
-  <para>
-    Now if an interrupt occurs after we check the queue status and before 
-    we call the <function>schedule</function> function in order to sleep, 
-    things work out. Instead of missing an event, we are set back to 
-    <constant>TASK_RUNNING</constant> by the mouse interrupt. We still call 
-    <function>schedule</function> but it will continue running our task. 
-    We go back around the loop and this time there may be an event.
-  </para>
-  <para>
-    There will not always be an event. Thus we set ourselves back to
-    <constant>TASK_INTERRUPTIBLE</constant> before resuming the loop. 
-    Another process doing a read may already have cleared the event flag, 
-    and if so we will need to go back to sleep again. Eventually we will 
-    get our event and escape.
-  </para>
-  <para>
-    Finally when we exit the loop we remove ourselves from the 
-    <varname>mouse_wait</varname> queue as we are no longer interested
-    in mouse events, and we set ourself back to 
-    <constant>TASK_RUNNABLE</constant> as we do not wish to go to sleep 
-    again just yet.
-  </para>
-  <note>
-   <title>Note</title> 
-   <para>
-     This isn't an easy topic. Don't be afraid to reread the description a 
-     few times and also look at other device drivers to see how it works. 
-     Finally if you can't grasp it just yet, you can use the code as 
-     boilerplate to write other drivers and trust me instead.
-   </para>
-  </note>
- </chapter>
-
- <chapter id="asyncio">
-  <title>Asynchronous I/O</title>
-  <para>
-    This leaves the missing feature - Asynchronous I/O. Normally UNIX 
-    programs use the <function>poll</function> call (or its variant form 
-    <function>select</function>) to wait for an event to occur on one of 
-    multiple input or output devices. This model works well for most tasks 
-    but because <function>poll</function> and <function>select</function> 
-    wait for an event isn't suitable for tasks that are also continually 
-    doing computation work. Such programs really want the kernel to kick 
-    them when something happens rather than watch for events.
-  </para>
-  <para>
-    Poll is akin to having a row of lights in front of you. You can see at a
-    glance which ones if any are lit. You cannot however get anything useful
-    done while watching them. Asynchronous I/O uses signals which work more 
-    like a door bell. Instead of you watching, it tells you that something 
-    is up.
-  </para>
-  <para>
-    Asynchronous I/O sends the signal SIGIO to a user process when the I/O 
-    events occur. In this case that means when people move the mouse. The 
-    SIGIO signal causes the user process to jump to its signal handler and 
-    execute code in that handler before returning to whatever was going on 
-    previously. It is the application equivalent of an interrupt handler.
-  </para>
-  <para>
-    Most of the code needed for this operation is common to all its users. 
-    The kernel provides a simple set of functions for managing asynchronous 
-    I/O.
-  </para>
-  <para>
-    Our first job is to allow users to set asynchronous I/O on file handles. 
-    To do that we need to add a new function to the file operations table for 
-    our mouse:
-  </para>
-
-  <programlisting>
-struct file_operations our_mouse_fops = {
-        owner: THIS_MODULE
-        read:  read_mouse,      /* You can read a mouse */
-        write: write_mouse,     /* This won't do a lot */
-        poll:  poll_mouse,      /* Poll */
-        open:  open_mouse,      /* Called on open */
-        release: close_mouse,   /* Called on close */
-        fasync: fasync_mouse,   /* Asynchronous I/O */
-};
-  </programlisting>
-
-  <para>
-    Once we have installed this entry the kernel knows we support 
-    asynchronous I/O and will allow all the relevant operations on the 
-    device. Whenever a user adds or removes asynchronous I/O notification 
-    on a file handle it calls our <function>fasync_mouse</function> routine 
-    we just added. This routine uses the helper functions to keep the queue 
-    of handles up to date:
-  </para>
-
-  <programlisting>
-static struct fasync_struct *mouse_fasync = NULL;
-
-static int fasync_mouse(int fd, struct file *filp, int on)
-{
-         int retval = fasync_helper(fd, filp, on, &amp;mouse_fasync);
-
-         if (retval &lt; 0)
-                 return retval;
-        return 0;
-}
-  </programlisting>
-
-  <para>
-    The fasync helper adds and deletes entries by managing the supplied 
-    list. We also need to remove entries from this list when the file is 
-    closed. This requires we add one line to our close function:
-  </para>
-
-  <programlisting>
-static int close_mouse(struct inode *inode, struct file *file)
-{
-        fasync_mouse(-1, file, 0)
-        if(--mouse_users)
-                return 0;
-        free_irq(OURMOUSE_IRQ, NULL);
-        return 0;
-}
-  </programlisting>
-
-  <para>
-    When we close the file we now call our own fasync handler as if the 
-    user had requested that this file cease to be used for asynchronous 
-    I/O. This rather neatly cleans up any loose ends. We certainly don't 
-    wait to deliver a signal for a file that no longer exists.
-  </para>
-  <para>
-    At this point the mouse driver supports all the asynchronous I/O 
-    operations, and applications using them will not error. They won't 
-    however work yet. We need to actually send the signals. Again the 
-    kernel provides a function for handling this.
-  </para>
-  <para>
-    We update our interrupt handler a little:
-  </para>
-
-  <programlisting>
-static void ourmouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        char delta_x;
-        char delta_y;
-        unsigned char new_buttons;
-
-        delta_x = inb(OURMOUSE_BASE);
-        delta_y = inb(OURMOUSE_BASE+1);
-        new_buttons = inb(OURMOUSE_BASE+2);
-
-        if(delta_x || delta_y || new_buttons != mouse_buttons)
-        {
-                /* Something happened */
-
-                spin_lock(&amp;mouse_lock);
-                mouse_event = 1;
-                mouse_dx += delta_x;
-                mouse_dy += delta_y;
-
-                if(mouse_dx &lt; -4096)
-                        mouse_dx = -4096;
-                if(mouse_dx &gt; 4096)
-                        mouse_dx = 4096;
-
-                if(mouse_dy &lt; -4096)
-                        mouse_dy = -4096;
-                if(mouse_dy &gt; 4096)
-                        mouse_dy = 4096;
-
-                mouse_buttons = new_buttons;
-                spin_unlock(&amp;mouse_lock);
-
-                /* Now we do asynchronous I/O */
-                kill_fasync(&amp;mouse_fasync, SIGIO); 
-                
-                wake_up_interruptible(&amp;mouse_wait);
-        }
-}
-  </programlisting>
-
-  <para>
-    The new code simply calls the <function>kill_fasync</function> routine
-    provided by the kernel if the queue is non-empty. This sends the 
-    required signal (SIGIO in this case) to the process each file handle 
-    says should be informed about the exciting new mouse movement that 
-    just happened.
-  </para>
-  <para>
-    With this in place and the bugs in the original version fixed, you now 
-    have a fully functional mouse driver using the bus mouse protocol. It 
-    will work with the <application>X window system</application>, will work 
-    with <application>GPM</application> and should work with every other 
-    application you need. <application>Doom</application> is of course the 
-    ideal way to test your new mouse driver is functioning properly. Be sure 
-    to test it thoroughly.
-  </para>
- </chapter>
-</book>
-
_