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

📄 the input subsystem2.htm

📁 LINUX内核编程的一些程序例子
💻 HTM
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0063)http://www.geocities.com/marco_corvi/games/lkpe/input/input.htm -->
<HTML><HEAD><TITLE>The Input Subsystem</TITLE>
<META http-equiv=Content-Type content="text/html; charset=windows-1252"><LINK 
href="The Input Subsystem2_file/style.css" rel=stylesheet>
<META content="MSHTML 6.00.2800.1170" name=GENERATOR></HEAD>
<BODY>
<H2>The Input Subsystem</H2>
<DIV>References:<BR>B. Hards, "The Linux USB Input Subsystem, Part I", Linux 
Journal 106, Feb. 2003, 20-25 <BR>B. Hards, "Using the Input Subsystem, Part 
II", Linux Journal 107, Mar. 2003, 22-30 <BR>The source code in the 
<CODE>drivers/input</CODE> subdirectory <BR>The include file 
<CODE>include/linux/input.h</CODE> <BR></DIV><BR clear=all><BR clear=all><BR 
clear=all>
<DIV>The Input subsystem is an abstraction layer between input devices 
(keyboard, mouse, joystick, and so on) and input handlers. The input devices 
capture inputs from the user actions or from other sources and produce input 
events. For instance a key press results in an input event. The input events go 
through the Input core and are dispatched to the interested handlers. The Input 
core provides a many-to-many mapping between input devices and event handlers. 
</DIV>
<DIV>An input event is a data structure with four field (see the file 
<CODE>include/linux/input.h</CODE>), 
<UL>
  <LI>struct timeval <CODE>time</CODE> of the event; 
  <LI>unsigned short <CODE>type</CODE>, the type of the event; 
  <LI>unsigned short <CODE>code</CODE>, the code of the event (a sort of 
  subtype); 
  <LI>unsigned int <CODE>value</CODE>, a value number assigend to the event. 
  </LI></UL><BR>There are hundreds of events. They are grouped in few event types. 
For example "keys" events (EV_KEY), relative motion events (EV_REL), led events 
(EV_LED). "Keys" event are really many. Relative axes and led events are just a 
few. </DIV>
<DIV>There are three important data structures: 
<UL>
  <LI><CODE>input_dev</CODE>, which represents an input device; 
  <LI><CODE>input_handler</CODE>, which represents an input handler; 
  <LI><CODE>input_handle</CODE>, which represents a connection between an input 
  device and an input handler. </LI></UL><BR></DIV>
<DIV>The <CODE>input_dev</CODE> contains several fields. In particular 
<UL>
  <LI><CODE>private</CODE>, a pointer to private data; 
  <LI><CODE>name</CODE>, a string identifying the device; 
  <LI><CODE>idbus</CODE>, bus identifier; 
  <LI><CODE>idvendor</CODE>, <CODE>idproduct</CODE>, and <CODE>idversion</CODE> 
  (in 2.5 these, together with <CODE>idbus</CODE>, are packed in an 
  <CODE>id</CODE> structure); 
  <LI>several bitmasks: <CODE>evbit</CODE>, <CODE>keybit</CODE>, etc.; 
  <LI>a <CODE>timer</CODE>; 
  <LI>several method pointers: <CODE>open</CODE>, <CODE>close</CODE>, 
  <CODE>event</CODE>, <CODE>upload_effect</CODE> and <CODE>erase_effect</CODE>; 
  <LI><CODE>handle</CODE>, a pointer to an input_handle; 
  <LI><CODE>next</CODE>, a pointer to the next input_dev since the input devices 
  are linked in a list. </LI></UL><BR></DIV>
<DIV>The <CODE>input_handler</CODE> data structure contains 
<UL>
  <LI>the pointer to the <CODE>private</CODE> data; 
  <LI>method pointers: <CODE>event</CODE>, <CODE>connect</CODE> and 
  <CODE>disconnect</CODE>, as well as a pointer to file_operations; 
  <LI><CODE>handle</CODE>, a pointer to an <CODE>input_handle</CODE>; 
  <LI><CODE>next</CODE>, for the linked list of input_handler's. 
</LI></UL><BR></DIV>
<DIV>Finally the <CODE>input_handle</CODE> contains 
<UL>
  <LI>the pointer to the <CODE>private</CODE> data; 
  <LI>an integer <CODE>open</CODE>; 
  <LI><CODE>dev</CODE>, a pointer to an input_dev; 
  <LI><CODE>handler</CODE>, a pointer to an input_handler; 
  <LI>two pointers, <CODE>dnext</CODE> and <CODE>hnext</CODE>, for the linked 
  lists of input_handle's attached to a input_dev, and to a input_handler, 
  respectively. </LI></UL><BR></DIV>
<DIV>Input devices, input handlers and input handles are connected in a sparse 
matrix structure, in which the input handles are the nodes of the matrix. The 
devices are the entries to the columns of the matrix, and the handlers are the 
entries to the rows. See the figure below. 
<DIV><IMG height=360 src="The Input Subsystem2_file/input.gif" width=400 
align=center> <BR clear=all>
<H3>The Input Core </H3>
<DIV>
<UL>
  <LI><CODE>input_event( dev, type, code, value )</CODE> reports events. It 
  returns immediately if the device has not set the bit for the 
  <CODE>type</CODE>. The it switches on the event <CODE>type</CODE>. Each event 
  is handled only if the corresponding bit of the proper device bitset is set. 
  Key events ... For absolute motion events the <CODE>code</CODE> entry of the 
  device <CODE>abs[]</CODE> array is modified (with some fuzziness) before 
  handling them. Relative motion events are skipped if the <CODE>value</CODE> is 
  0. LED and sound events toggle the device <CODE>led</CODE> and 
  <CODE>snd</CODE>, respectively, and call the device <CODE>event()</CODE> 
  function if it exists defore handling. Repeat events set the <CODE>code</CODE> 
  entry of the device <CODE>rep[]</CODE> array to <CODE>value</CODE> before 
  handling. After these controls and preliminary things it dispatches the event 
  to the list of handles attaches to the device: traversing the list 
  <CODE>dnext</CODE> it calls the <CODE>event()</CODE> method for each open 
  handle. 
  <LI><CODE>input_repeat_key( dev )</CODE> It invokes the 
  <CODE>input_event()</CODE> method with the device <CODE>dev</CODE>, a "key" 
  event type, the code of the device <CODE>repaet_key</CODE>, and value 2 
  <LI><CODE>input_open_device( handle )</CODE> is called when a handle' device 
  is opened. It invokes the <CODE>open</CODE> method of the handle's device and 
  increases the handle <CODE>open</CODE> counter. 
  <LI><CODE>input_close_device( handle )</CODE> is called when the handle' 
  device is closed. It invokes the <CODE>close</CODE> method of the handle's 
  device and decreases the open counter. 
  <LI><CODE>input_link_handle( handle )</CODE> inserts handle in the first 
  position of both the device list (of the handle's dev) and the handler list 
  (of the handle's handler). 
  <LI><CODE>input_unlink_handle( handle )</CODE> remove the handle from both the 
  device list and the handler list 
  <LI><CODE>input_register_device( dev )</CODE> is called by an input device 
  that wants to register with the input core. It initializes the device repeat 
  timer to default values (in particular the timer function is 
  <CODE>input_repeat_key</CODE>). Then it assignes the device number (the first 
  free number). Finally it scans the list of input_handler trying to connect 
  each handler with the device: if it succeeds it inserts the newly created 
  handle. It increases <CODE>input_number</CODE>. 
  <LI><CODE>input_unregister_device( dev )</CODE> is called by a device that 
  drops from the input core. It deletes the repeat timer. For each handle in the 
  device list of <CODE>dev</CODE> it unlinks the handle and disconnect it from 
  the associated handler. Finally it removes the device and decreases 
  <CODE>input_number</CODE>. 
  <LI><CODE>input_register_handler( handler )</CODE> is called by an input 
  handler that wants to register with the input core. It adds the handler to the 
  list <CODE>input_handler</CODE> and add it to the <CODE>input_table</CODE>. 
  Then it adds a handle for each device that can be connected to the handler. 
  <LI><CODE>input_unregister_handler( handler )</CODE> is called by a handler to 
  unregister from the input core. It disconnects the handler from all the 
  devices to which it is connected. Then it removes the handler from the list 
  <CODE>input_handler</CODE> and remove it from the <CODE>input_table</CODE>. 
  <LI><CODE>input_open_file( inode, file )</CODE>. This is the only file 
  operation of the input core driver. [ STILL TO DO ] </LI></UL></DIV>
<H3>Anatomy of a handler</H3>
<DIV>Sample input handlers are contained in the drivers/input subdirectory of 
the source tree. They provide the user interfaces. Here we consider the event 
handler <CODE>evdev.c</CODE>. Two data structures are used to store event device 
and event informations: 
<UL>
  <LI><CODE>evdev</CODE>, which contains, besides other things, an input_handle, 
  a wait_queue_head, and a pointer to an evdev_list; 
  <LI><CODE>evdev_list</CODE>, with a buffer of input_event's, a fasync_struct 
  pointer, a pointer to its evdev, and the next evdev_list pointer. </LI></UL>The 
evdev's are stored in a static <CODE>evdev_table</CODE>; </DIV>
<DIV>The user interface methods (API) are 
<UL>
  <LI><CODE>evdev_fasync( fd, file, on )</CODE>. It gets the 
  <CODE>evdev_list</CODE> stored in the <CODE>file</CODE>'s 
  <CODE>private_data</CODE>, and invokes the the fasync_helper with the 
  <CODE>evdev_list</CODE>'s <CODE>fasync</CODE> function [FIXME], 
  <BR>&nbsp;&nbsp;&nbsp;fasync_helper(fd, file, on, &amp;list-&gt;fasync); 
  <LI><CODE>evdev_open( inode, file )</CODE>. The <CODE>inode</CODE>'s minor 
  specifes which evdev to open. A new evdev_list structure is allocated and 
  linked into the evdev's evdev_list, and the <CODE>file</CODE> 
  <CODE>private_data</CODE> is made to point to the newly created evdev_list, 
  <BR>
  <DIV align=left>&nbsp;&nbsp;&nbsp;list-&gt;evdev = 
  evdev_table[i];<BR>&nbsp;&nbsp;&nbsp;list-&gt;next = 
  evdev_table[i]-&gt;list;<BR>&nbsp;&nbsp;&nbsp;evdev_table[i]-&gt;list = 
  list;<BR>&nbsp;&nbsp;&nbsp;file-&gt;private_data = list; </DIV>After this 
  bookkeeping, if the evdev was not already open (and if it exists), the 
  input_core <CODE>input_open_device</CODE> is invoked with the evdev's 
  <CODE>handle</CODE>. 
  <LI><CODE>evdev_release( inode, file )</CODE>. This does the opposite 
  operations of the open method: if this was the last list of the evdev, the 
  evdev is closed with the input_core (and possibly unregistered and deallocated 
  if its <CODE>exist</CODE> flag is not set). Finally the evdev_list is freed. 
  <LI>evdev_write( file, buffer, count )</CODE> allows the user process to write 
  events into the evdev <CODE>buffer</CODE>. The user <CODE>buffer</CODE> must 
  contain one or more <CODE>struct input_event</CODE>. <CODE>count</CODE> is the 
  number of bytes used in the user <CODE>buffer</CODE>. 
  <LI><CODE>evdev_read( file, buffer, count, ppos )</CODE>. Reading is the 
  reverse operation: events are copied from the evdev's <CODE>buffer</CODE> to 
  the user <CODE>buffer</CODE>. There is one catch. If the evdev's 
  <CODE>buffer</CODE> is empty the process is put to sleep. 
  <LI><CODE>evdev_poll( file, wait ).</CODE> 
  <LI><CODE>evdev_ioctl( inode, file, cmd, arg ).</CODE> </LI></UL></DIV>
<DIV>Finally the methods related to the input_core are 
<UL>
  <LI><CODE>evdev_event</CODE>: given an input_handle, retrieves the associated 
  evdev (contained in the <CODE>private</CODE> field), and its list of 
  evdev_list's. Then for each evdev_list in the list, the event informations 
  (time, type, code and value) are put on the next free slot of the 
  <CODE>buffer</CODE>, and the <CODE>fasync</CODE> is signalled [FIXME]. Finally 
  the processes on the <CODE>evdev</CODE>'s wait_queue are waken up. 
  <LI><CODE>evdev_connect( handler, dev )</CODE>. Finds the first unused entry 
  in the evdev_table, and allocates a new evdev for it. Initialize its 
  wait_queue, its <CODE>handle</CODE> <BR>
  <DIV align=left>&nbsp;&nbsp;&nbsp;evdev-&gt;handle.dev = 
  dev;<BR>&nbsp;&nbsp;&nbsp;evdev-&gt;handle.handler = 
  handler;<BR>&nbsp;&nbsp;&nbsp;evdev-&gt;handle.private = evdev; 
  <DIV>and register with the input_core. </DIV></DIV>
  <LI><CODE>evdev_disconnect( handle )</CODE>. The evdev is contained in the 
  handle's <CODE>private</CODE> field. If the evdev is open it is closed and the 
  processes on its wait_queue are waken up. Otherwise it is unregistered, 
  dropped from the evdev_table, and deallocated. 
  <LI><CODE>evdev_init</CODE>: register with the input_core; 
  <LI><CODE>evdev_exit</CODE>: unregister with the input_core. </LI></UL></DIV>
<H3>Working through the code</H3>
<DIV>First, we start with examples of input devices. These are taken from Hard's 
article, with minor changes to make them run on 2.4 kernels. 
<OL>
  <LI><A 
  href="http://www.geocities.com/marco_corvi/games/lkpe/input/example1.c">example1.c</A>, 
  basic register/unregister 
  <LI><A 
  href="http://www.geocities.com/marco_corvi/games/lkpe/input/example2.c">example2.c</A>, 
  key event device 
  <LI><A 
  href="http://www.geocities.com/marco_corvi/games/lkpe/input/example3.c">example3.c</A>, 
  motion event device </LI></OL>Try these examples out. Here is the <A 
href="http://www.geocities.com/marco_corvi/games/lkpe/input/makefile">makefile</A>. 
</DIV>
<DIV>Now the first exercise. Write a driver that generates led input events. You 
can begin with examples 2 or 3 above, and replace the driver event type with 
EV_LED, and set some <CODE>ledbit</CODE>. Give it a try before looking at a 
solution, <BR><A 
href="http://www.geocities.com/marco_corvi/games/lkpe/input/example4.c">example4.c</A>, 
led event device. </DIV>
<DIV>Second exercise. Now write a handler for the led device of the first 
exercise. As a hint you may look at the joydev.c code in drivers/input 
subdirectory of Linux. Here is a solution, <A 
href="http://www.geocities.com/marco_corvi/games/lkpe/input/leddev.c">leddev.c</A>, 
led event handler. And these are two user programs for it, <A 
href="http://www.geocities.com/marco_corvi/games/lkpe/input/ledtest.c">ledtest.c</A>, 
<A 
href="http://www.geocities.com/marco_corvi/games/lkpe/input/ledreset.c">ledreset.c</A>. 
</DIV><BR clear=all><FONT size=-1>Marco Corvi - 2003</FONT> <!-- text below generated by server. PLEASE REMOVE --></OBJECT></LAYER></DIV></SPAN></STYLE></NOSCRIPT></TABLE></SCRIPT></APPLET>
<SCRIPT 
language=JavaScript>var PUpage="76001084"; var PUprop="geocities"; </SCRIPT>

<SCRIPT language=JavaScript src="The Input Subsystem2_file/pu5geo.js"></SCRIPT>

<SCRIPT language=JavaScript 
src="The Input Subsystem2_file/ygIELib9.js"></SCRIPT>

<SCRIPT language=JavaScript>var yviContents='http://us.toto.geo.yahoo.com/toto?s=76001084&l=NE&b=1&t=1057747069';yviR='us';yfiEA(0);</SCRIPT>

<SCRIPT language=JavaScript src="The Input Subsystem2_file/mc.js"></SCRIPT>

<SCRIPT language=JavaScript src="The Input Subsystem2_file/geov2.js"></SCRIPT>

<SCRIPT language=javascript>geovisit();</SCRIPT>
<NOSCRIPT><IMG height=1 alt=setstats src="The Input Subsystem2_file/visit.gif" 
width=1 border=0></NOSCRIPT> <IMG height=1 alt=1 
src="The Input Subsystem2_file/serv.gif" width=1> <!-- w52.geo.scd.yahoo.com compressed/chunked Wed Jul  9 03:37:49 PDT 2003 --></DIV></BODY></HTML>

⌨️ 快捷键说明

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