【doc/input】input系统基础

在我的印象中,input系统应该是将输入设备进行了抽象得到的一个统一的接口。常见的键盘,光鼠,轨迹球,传感器我们都可以归到input系统中来。

 

编写一个input的基本的步骤是:

1创建input device和driver

1.0 一个简单的例子

一个简单的例子是一个简单的I/O按键(BUTTON)。当一个按下或者释放的动都都会产生一个BUTTON_IRQ。

 

  1. #include <linux/input.h>  
  2.   
  3. #include <linux/module.h>  
  4.   
  5. #include <linux/init.h>  
  6.   
  7.    
  8.   
  9. #include <asm/irq.h>  
  10.   
  11. #include <asm/io.h>  
  12.   
  13.    
  14.   
  15. static struct input_dev *button_dev;  
  16.   
  17.    
  18.   
  19. static irqreturn_t button_interrupt(int irq, void *dummy)  
  20.   
  21. {  
  22.   
  23. input_report_key(button_dev, BTN_0, inb(BUTTON_PORT)&1);  
  24.   
  25. input_sync(button_dev);  
  26.   
  27. return IRQ_HANDLED;  
  28.   
  29. }  
  30.   
  31.    
  32.   
  33. static int __init button_init(void)  
  34.   
  35. {  
  36.   
  37. int error;  
  38.   
  39.   
  40. if(request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL) {  
  41.   
  42. printk(KERN_ERR "button.c: Can't allocate irq %d/n", button_irq);  
  43.   
  44. return -EBUSY;  
  45.   
  46. }  
  47.   
  48.   
  49. button_dev = input_allocate_device();  
  50.   
  51. if( !button_dev){  
  52.   
  53. printk(KERN_ERR "button.c: Not enough memory/n");  
  54.   
  55. error = -ENOMEM;  
  56.   
  57. goto err_free_irq;  
  58.   
  59. }  
  60.   
  61.   
  62. button_dev->evbit[0] = BIT_MASK(EV_KEY);  
  63.   
  64. button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);  
  65.   
  66.   
  67. error = input_register_device(button_dev);  
  68.   
  69. if(error){  
  70.   
  71. printk(KERN_ERR "button.c: Failed to register device/n");  
  72.   
  73. goto err_free_dev;  
  74.   
  75. }  
  76.   
  77.   
  78. return 0;  
  79.   
  80.   
  81. err_free_dev:  
  82.   
  83. input_free_device(button_dev);  
  84.   
  85. err_free_irq:  
  86.   
  87. free_irq(BUTTON_IRQ,button_interrupt);  
  88.   
  89. return error;  
  90.   
  91. }  
  92.   
  93.    
  94.   
  95. static void __exit button_exit(void)  
  96.   
  97. {  
  98.   
  99. input_unregister_device(button_dev);  
  100.   
  101. free_irq(BUTTON_IRQ, button_interrupt);  
  102.   
  103. }  
  104.   
  105.    
  106.   
  107. module_init(button_init);  
  108.   
  109. module_exit(button_exit);  

  

 

1.1 上面的例子是做什么的?

首先,他包含了<linux/input.h>这个文件,在input.h的文件中包含了input子系统中相关的接口函数。

__init函数在模块加载或者是内核启动的时候被调动,会申请到使用的资源

然后通过input_allocate_device()申请一个新的输入设备结构体并且设置输入的位域(bitfields)。这种方式会告诉其 他的输入系统中的设备当前注册的是什么,会产生什么events或者是被这个输入设备接受什么。当前的例子设备智慧产生EV_KEY类型的事件,并且只有 BTN_0 event编码。因此我们只要设置这两位,采用如下的方式:

  1. set_bit(EV_KEY, button_dev.evbit);  
  2.   
  3. set_bit(BTN_0, button_dev.keybit);  

,but with more than single bits the first approach tends to be shorter

 

注册输入设备结构体通过调用input_register_device(&button_dev);来实现。

这个会把button_dev结构体和input driver来关联起来,并且会调用device handler modules _connect函数来通知说有一个新的input device出现了。input_register_device()可能休眠,所以不能被中断或者是spinlock来调用。

 

当使用的时候,仅仅使用到的driver是button_interrupt().

当有任何一个按键中断检测到的时候,通过input_report_key()来上报给input_system.没有必要来检测按键是否是两个一 样的值,这个检查的过程在input_report_* 函数内部检查了。(这里需要看看kernel中如何对同一个值的处理)

 

当我们发送了一个完整的report的时候,input_sync会通知到底是谁接收了这个event。(需要看代码看看如何接收的)

 

1.2 dev->open() & dev->close()

在当前的例子中驱动不停的重复轮训查看device,因为他没有中断并且轮询方式太浪费时间,或者如果device用了一个valuable resource(例如interrupt), 能够通过使用open和close这样的回调函数来知道什么时候他可以停止轮询或者是释放中断,什么是否必须恢复轮询或者是再次获得中断。如上所述,在驱 动代码中应该变为如下的:

  1. static int button_open( struct input_dev *dev)  
  2.   
  3. {  
  4.   
  5. if(request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)){  
  6.   
  7. printk(KERN_ERR, "button.c: Can't allocate irq %d/n",button_irq);  
  8.   
  9. return -EBUSY;  
  10.   
  11. }  
  12.   
  13.   
  14. return 0;  
  15.   
  16. }  
  17.   
  18.    
  19.   
  20. static void button_close(struct input_dev *dev)  
  21.   
  22. {  
  23.   
  24. free_irq(IRQ_AMIGA_VERTB, button_interrupt);  
  25.   
  26. }  
  27.   
  28.    
  29.   
  30. static int __init button_init( void )  
  31.   
  32. {  
  33.   
  34. ...  
  35.   
  36. button_dev->open = button_open;  
  37.   
  38. button_dev->close = button_close;  
  39.   
  40. ...  
  41.   
  42. }  

  

 

注意:input core会记录device的用户数量并且保证dev->open()仅仅是用户第一次连接设备时被调用,并且dev->close()被最 后一个使用者离开时被调用。双方的回调必须是线性的,即先是open设备,使用完成后close设备。

 

1.3 基本的event类型

最简单的event类型是EV_KEY,被用作keys或者是buttons的event类型。通过input_report_key(struct input_dev *dev, int code, int value)来上报。

在linux/input.h中定义了允许使用的值(0~~KEY_MAX)。value是表示实际发生的是哪一个值,非零值表示有按键按下,零值表示按键松开。

 

除了EV_KEY,还有两个基本的event类型:EV_REL和EV_ABS。被用来上报设备的相对和绝对值。一个相对值比如说鼠标在X轴上的运 动。鼠标会上报相对上个位置的相对值,因为在工作的时候并没有一个绝对的位置。绝对值事件一般是操纵杆和数字转换的设备,通常在系统中有实际的值。

 

上报EV_REL和上报EV_KEY是见是一样的,只要调用input_report_rel(struct input_dev *dev, int code, int value)。时间会产生一个非零值。

 

但是EV_ABS需要一些注意的地方。在调用input_register_device之前,不得不先填充设备所拥有的相关绝对数值。如果你的button device绝对值如下设置:

  1. button_dev.absmin[ABS_X] = 0;  
  2.   
  3. button_dev.absmax[ABS_X] 255;  
  4.   
  5. button_dev.absfuzz[ABS_X] = 4;  
  6.   
  7. button_dev.absflat[ABS_X] = 8;  

或者采用这个方式来声明:input_set_abs_params(button_dev, ABS_X, 0, 255, 4, 8);

 

这个设定一般适用于操纵杆(joystick)的X坐标[0~255],and with a center flat position of size 8.

 

如果你不需要absfuzz和absflat,你可以设置为0,意思是所获得的值时准确的。(the thing is precise and alwasys returns to exactly the center position)

 

1.4 BITS_TO_LONGS(), BIT_WORD(), BIT_MASK()

这是三个在bitops.h中定义的宏。

  1. BITS_TO_LONGS(x)---returns the length of a bitfield array in longs for x bits.  
  2.   
  3. BIT_WORD(x)---returns the index in the array in longs for bit x  
  4.   
  5. BIT_MASK(x) --- returns the index in a long for bit x  

  

 

1.5 id*和fields

在通过input device driver注册input device 的时候要注意dev->name要设定。顶一个自己喜欢的字串就好。

id fields包含BUS ID(PCI,USB,...),vendor ID 和device ID。bus ID在input.h文件中定义。vendor ID和device ID在pci_ids.h,usb_ids.h和类似的头文件中定义了。这些都需要在设备注册之前被设置。

idtype field存放的是input device的特定的信息。

id和名字通过evdev接口可以传递给用户空间。

 

1.6 keycode, keycodemax, keycodesize fields

keycode是一个对input system来说映射scancodes的数组。keycode max是数组的大小。

用户空间可以询问和修改当前的keycode mapping通过EVIOCGKEYCODE和EVIOCSKEYCODE ioctls。

 

1.7 dev->getkeycode() 和 dev->setkeycode()

getkeycode和setkeycode()允许驱动获得不是通过keycode/keycodesize/keycodemax提供的值;

 

1.8 key 自动重复

是input.c模块负责。硬件的自动重复没有使用,因为大多数的设备不存在这种情况,反而出现这种情况应该是出问题了。

 

1.9 其他的event type,处理输出的event

其他的还有类似的 /

EV_LED-来作为键盘灯的

EV_SND-键盘蜂鸣器

这些也同key event类似,但是他们是作为输出的event。如果你的设备上需要这些类型,你就必须设定这些位。例如:

    1.  button_dev->event = button_event;  
    2.   
    3.  int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)  
    4.   
    5.  {  
    6.   
    7. if(type == EV_SND && code == SND_BELL){  
    8.   
    9. outb(value, BUTTON_BELL);  
    10.   
    11. return 0;  
    12.   
    13. }  
    14.   
    15. return -1;  
    16.   
    17.  } 

    18. 转自:http://blog.csdn.net/skywalkzf/article/details/6215413


posted @ 2012-11-17 20:54  云翔世界  阅读(224)  评论(0)    收藏  举报