Sophie

Sophie

distrib > Mandriva > 9.0 > i586 > by-pkgid > 98e91bc877e03cf3582cd163550eb7e3 > files > 711

kernel-doc-html-2.4.19-16mdk.i586.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML
><HEAD
><TITLE
>Asynchronous I/O</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
REL="HOME"
TITLE="Mouse Drivers"
HREF="book1.html"><LINK
REL="PREVIOUS"
TITLE="Debugging the mouse driver"
HREF="c131.html"></HEAD
><BODY
CLASS="CHAPTER"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Mouse Drivers</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="c131.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
></TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
>&nbsp;</TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="CHAPTER"
><H1
><A
NAME="ASYNCIO"
></A
>Asynchronous I/O</H1
><P
>    This leaves the missing feature - Asynchronous I/O. Normally UNIX 
    programs use the <TT
CLASS="FUNCTION"
>poll</TT
> call (or its variant form 
    <TT
CLASS="FUNCTION"
>select</TT
>) to wait for an event to occur on one of 
    multiple input or output devices. This model works well for most tasks 
    but because <TT
CLASS="FUNCTION"
>poll</TT
> and <TT
CLASS="FUNCTION"
>select</TT
> 
    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.
  </P
><P
>    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.
  </P
><P
>    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.
  </P
><P
>    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.
  </P
><P
>    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:
  </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="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 */
};
  </PRE
></TD
></TR
></TABLE
><P
>    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 <TT
CLASS="FUNCTION"
>fasync_mouse</TT
> routine 
    we just added. This routine uses the helper functions to keep the queue 
    of handles up to date:
  </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="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, &#38;mouse_fasync);

         if (retval &#60; 0)
                 return retval;
        return 0;
}
  </PRE
></TD
></TR
></TABLE
><P
>    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:
  </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="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);
        MOD_DEC_USE_COUNT;
        return 0;
}
  </PRE
></TD
></TR
></TABLE
><P
>    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.
  </P
><P
>    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.
  </P
><P
>    We update our interrupt handler a little:
  </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="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(&#38;mouse_lock);
                mouse_event = 1;
                mouse_dx += delta_x;
                mouse_dy += delta_y;

                if(mouse_dx &#60; -4096)
                        mouse_dx = -4096;
                if(mouse_dx &#62; 4096)
                        mouse_dx = 4096;

                if(mouse_dy &#60; -4096)
                        mouse_dy = -4096;
                if(mouse_dy &#62; 4096)
                        mouse_dy = 4096;

                mouse_buttons = new_buttons;
                spin_unlock(&#38;mouse_lock);

                /* Now we do asynchronous I/O */
                kill_fasync(&#38;mouse_fasync, SIGIO); 
                
                wake_up_interruptible(&#38;mouse_wait);
        }
}
  </PRE
></TD
></TR
></TABLE
><P
>    The new code simply calls the <TT
CLASS="FUNCTION"
>kill_fasync</TT
> 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.
  </P
><P
>    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 <TT
CLASS="APPLICATION"
>X window system</TT
>, will work 
    with <TT
CLASS="APPLICATION"
>GPM</TT
> and should work with every other 
    application you need. <TT
CLASS="APPLICATION"
>Doom</TT
> is of course the 
    ideal way to test your new mouse driver is functioning properly. Be sure 
    to test it thoroughly.
  </P
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="c131.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="book1.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>&nbsp;</TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Debugging the mouse driver</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>&nbsp;</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>