⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mousedrivers.tmpl

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 TMPL
📖 第 1 页 / 共 3 页
字号:
<!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        0x300static struct miscdevice our_mouse = {        OURMOUSE_MINOR, "ourmouse", &amp;our_mouse_fops};__init ourmouse_init(void){        if(check_region(OURMOUSE_BASE, 3))                return -ENODEV;        request_region(OURMOUSE_BASE, 3, "ourmouse");        misc_register(&amp;our_mouse);        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 check nobody else has taken our     address space. Having done so we reserve it to ensure nobody stamps     on our device while probing for other ISA bus devices. Such a probe     might confuse our device.  </para>  <para>    Then we tell the misc driver that we wish to own a minor 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.  </para>  <para>    Next, in order to be able to use and test our code we need to add some     module code to support it. This too is fairly simple:  </para>  <programlisting>#ifdef MODULEint init_module(void){        if(ourmouse_init()&lt;0)                return -ENODEV:        return 0;}void cleanup_module(void){        misc_deregister(&amp;our_mouse);        free_region(OURMOUSE_BASE, 3);}#endif  </programlisting>  <para>    The module code provides the normal two functions. The     <function>init_module</function> function is called when the module is     loaded. In our case it 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>cleanup_module</function> function is called when the     module is 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>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -