06day01input_driver
1 /* 2 输入子系统: 3 把按键的驱动,添加到输入子系统中,可以通过按键来输入对应的字符 4 5 内核中 include/linux/input.h 6 驱动中主要填充 input_dev 这个结构体 7 name 名称 phys uniq input_id 设置对应的节点信息 8 9 10 */ 11 #include <linux/module.h> 12 #include <linux/init.h> 13 #include <linux/kernel.h> 14 15 #include <linux/input.h> 16 #include <linux/bitops.h> 17 #include <linux/interrupt.h> //request_irq 18 #include <mach/irqs.h> //IRQ_EINT 19 #include <linux/gpio.h> //gpio_request 20 #include <mach/gpio.h> //EXYNOS4_GPX3 21 /* 22 用四个按键模拟键盘 把案件值 直接输出标准输出 23 24 可以将开发板上的系统当前终端输入重定向为标准输入 25 26 exec 0 < /dev/tty1 27 */ 28 29 30 #define DEVNAME "ldm" 31 32 // 33 struct ldm_info 34 { 35 struct input_dev * pdev; 36 }; 37 38 struct ldm_info ldm; 39 40 struct key_info 41 { 42 char * name; 43 int code; 44 int irqno; 45 int gpio_num; 46 }; 47 48 //l s enter backspace 49 struct key_info keyinfo[] = { 50 {"KEY_L", KEY_L, IRQ_EINT(26), EXYNOS4_GPX3(2)}, 51 {"KEY_S", KEY_S, IRQ_EINT(27), EXYNOS4_GPX3(3)}, 52 {"KEY_ENTER", KEY_ENTER, IRQ_EINT(28), EXYNOS4_GPX3(4)}, 53 {"KEY_BACKSPACE", KEY_BACKSPACE, IRQ_EINT(29), EXYNOS4_GPX3(5)}, 54 }; 55 56 //中断处理函数 57 static irqreturn_t key_handler(int irqno, void * arg) 58 { 59 struct key_info *key = (struct key_info *)arg; 60 //产生了中断,在合适时候,发送input_event事件 61 62 int key_stat = gpio_get_value(key->gpio_num); 63 64 //发送事件 发送按键的按键值 和 按键的状态 65 input_report_key(ldm.pdev, key->code, !key_stat); 66 //发送结束事件 67 input_sync(ldm.pdev); 68 69 return IRQ_HANDLED; 70 } 71 72 static int test_init(void) 73 { 74 int ret = 0; 75 int i = 0; 76 int j = 0; 77 printk("%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); 78 79 //1.创建input_dev 的对象 input_allocate_device(); 80 //如果仅仅申请了空间,没有注册 即调用input_allocate_device 81 //那么需要调用input_free_device 函数来释放空间 82 //一旦注册成功,则不需要调用input_free_device来释放空间 83 ldm.pdev = input_allocate_device(); 84 if(!ldm.pdev) { 85 printk("input_allocate_device failed\n"); 86 ret = -ENOMEM; 87 goto err_input_allocate_device; 88 } 89 90 //2.填充input_dev 这个结构体 91 ////////////相关的信息///////////////////////// 92 ldm.pdev->name = "my test input device"; 93 ldm.pdev->phys = "key"; 94 ldm.pdev->uniq = "candle"; 95 ldm.pdev->id.bustype = 0x1234; 96 ldm.pdev->id.vendor = 0x2222; 97 ldm.pdev->id.product = 0xabcd; 98 ldm.pdev->id.version = 0x3433; 99 /////////////////////////////////////////////////////// 100 101 //这个设备支持哪些事件? 102 //本设备支持的事件的类型,通过set_bit函数来指定位置 103 //所有的位置,都可以通过宏来设置 104 set_bit(EV_KEY, ldm.pdev->evbit); //支持按键类型的事件 105 set_bit(EV_REP, ldm.pdev->evbit);//支持连发 106 107 //针对不同的事件,处理什么样的数据? 108 //eint26~29 GPX3_2 ~5 109 //这个设备支持的按键的键值 110 111 for(i=0; i< ARRAY_SIZE(keyinfo);i++) { 112 set_bit(keyinfo[i].code, ldm.pdev->keybit); 113 } 114 115 //注册设备对象 116 ret = input_register_device(ldm.pdev); 117 if(ret < 0) { 118 printk("input_register_device failed\n"); 119 goto err_input_register_device; 120 } 121 122 //注册中断,按下和抬起的时候都要去触发 123 for(i=0;i < ARRAY_SIZE(keyinfo);i++) { 124 ret = request_irq(keyinfo[i].irqno, key_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, DEVNAME, keyinfo + i ); 125 if(ret < 0) { 126 printk("request_irq failed\n"); 127 goto err_request_irq; 128 } 129 } 130 131 //注册GPIO管脚 132 //int j = 0; 133 for(j=0; j < ARRAY_SIZE(keyinfo);j++) { 134 ret = gpio_request(keyinfo[j].gpio_num, keyinfo[j].name); 135 if(ret < 0) { 136 printk("gpio_request failed\n"); 137 goto err_gpio_request; 138 } 139 } 140 141 142 return 0; 143 144 err_gpio_request: 145 for(j = j - 1;j>=0;j--) { 146 gpio_free(keyinfo[j].gpio_num); 147 } 148 err_request_irq: 149 for(i=i-1;i>=0;i--) { 150 free_irq(keyinfo[i].irqno, keyinfo + i); 151 //把之前注册成功的中断号释放掉 152 } 153 input_unregister_device(ldm.pdev); 154 return ret; 155 err_input_register_device: 156 input_free_device(ldm.pdev); 157 err_input_allocate_device: 158 return ret; 159 } 160 161 static void test_exit(void) 162 { 163 int i = ARRAY_SIZE(keyinfo); 164 printk("%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); 165 166 167 for(i=i-1; i>=0;i--) { 168 gpio_free(keyinfo[i].gpio_num); 169 free_irq(keyinfo[i].irqno, keyinfo + i); 170 } 171 172 input_unregister_device(ldm.pdev); 173 } 174 175 176 module_init(test_init); 177 module_exit(test_exit); 178 MODULE_LICENSE("GPL");