Linux input子系统实例分析(一)
这是一个简单的输入设备驱动实例。这个输入设备只有一个按键,按键被连接到一条中断线上,当按键被按下时,将产生一个中断,内核将检测到这个中断,并对其进行处理。该实例的代码如下:
1: #include <linux/module.h> 2: #include <linux/init.h> 3: #include <linux/fs.h> 4: #include <linux/interrupt.h> 5: #include <linux/irq.h> 6: #include <linux/sched.h> 7: #include <linux/spinlock.h> 8: #include <linux/pm.h> 9: #include <linux/slab.h> 10: #include <linux/sysctl.h> 11: #include <linux/proc_fs.h> 12: #include <linux/delay.h> 13: #include <linux/platform_device.h> 14: #include <linux/input.h> 15: #include <linux/workqueue.h> 16: #include <linux/gpio.h> 17: 18: 19: #define gpio_key 32*4+30 //PD(30) 即将使用的gpio
20: #define DEV_NAME "gpio_key"
21: 22: int g_irq = -1; //中断号
23: static struct input_dev *button_dev; //输入子系统设备结构
24: 25: 26: //中断处理函数
27: static irqreturn_t button_interrupt(int irq, void *p)
28: {29: /*get pin value <down 0, up 1> */
30: 31: int val = gpio_get_value(gpio_key);
32: 33: input_report_key(button_dev, KEY_1, val); 34: 35: input_sync(button_dev); 36: 37: return IRQ_RETVAL(IRQ_HANDLED);
38: } 39: 40: 41: 42: static int __init button_init(void)
43: {44: int irq = -1, err = -1;
45: unsigned long irqflags;
46: //申请gpio
47: err = gpio_request(gpio_key, "test_key");
48: if(err < 0){
49: printk("request gpio[%d] failed...\n", gpio_key);
50: goto end1;
51: } 52: 53: //gpio输入
54: err = gpio_direction_input(gpio_key);55: if (err < 0) {
56: //dev_err(dev, "failed to configure"
57: // " direction for GPIO %d, error %d\n",
58: // gpio_key, error);
59: goto end2;
60: }61: //申请gpio中断号
62: g_irq = (irq = gpio_to_irq(gpio_key));63: if (irq < 0) {
64: err = irq;65: //dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n",
66: // gpio_key, irq);
67: goto end2;
68: }69: //中断类型
70: irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;71: /* 申请中断 */
72: if (request_irq(irq, button_interrupt, irqflags, DEV_NAME, NULL)) {
73: 74: printk(KERN_ERR"cannotallocate irq");
75: err= -EBUSY;76: goto end2;
77: } 78: 79: /*分配input_dev */
80: button_dev = input_allocate_device();81: if (button_dev == NULL) {
82: printk(KERN_ERR "notenough memory\n");
83: err= - ENOMEM;84: goto end3;
85: 86: }87: /*设置输入设备支持的事件类型和事件代码 */
88: button_dev->name = "key_gpio";
89: set_bit(EV_KEY, button_dev->evbit); 90: set_bit(KEY_1, button_dev->keybit); 91: 92: /*把输入设备注册进核心层 */
93: err = input_register_device(button_dev);94: if(err) {
95: printk(KERN_ERR "failedto register device\n");
96: goto end4;
97: } 98: 99: printk("initialized\n");
100: return 0;
101: 102: end4: 103: input_free_device(button_dev); 104: end3: 105: free_irq(irq, NULL); 106: end2: 107: gpio_free(gpio_key); 108: end1:109: return err;
110: 111: } 112: 113: 114: 115: static void __exit button_exit(void)
116: { 117: input_unregister_device(button_dev); 118: input_free_device(button_dev); 119: 120: gpio_free(gpio_key); 121: free_irq(g_irq, NULL); 122: } 123: 124: 125: 126: module_init(button_init); 127: module_exit(button_exit); 128: 129: MODULE_LICENSE("GPL");
130: MODULE_AUTHOR("xuyonghong@duotin.com>");
131: 132: 133: 134: 135: 136: 当编译进内核烧写板子后可以看到相应的设备文件:
root@CarRadio:/sys/devices# ls virtual/input/input2/
capabilities id name power subsystem uniq
event2 modalias phys properties uevent
root@CarRadio:/sys/devices# cat virtual/input/input2/name
key_gpio
root@CarRadio:/sys/devices#
这样就可以监控event2来捕捉按键
root@CarRadio:/# ls dev/input/event2
dev/input/event2
root@CarRadio:/#
驱动分析:
1.申请gpio
gpio_request(gpio_key, "test_key");
2.设置为gpio输入模式
gpio_direction_input(gpio_key);
3.申请gpio中断号,注册中断
//申请gpio中断号 g_irq = (irq = gpio_to_irq(gpio_key));
/* 申请中断 */
request_irq(irq, button_interrupt, irqflags, DEV_NAME, NULL);
4.分配input_dev设备
/*分配input_dev */
button_dev = input_allocate_device();
5.把输入设备注册进核心层
input_register_device(button_dev);

浙公网安备 33010602011771号