Linux 的输入子系统不仅支持鼠标、键盘等常规输入设备,而且还支持蜂鸣器、触摸屏等设备。输入子系统又叫input子系统。其构建非常灵活,只需要调用一些简单的函数,就可以将一个输入设备的功能呈现给应用程序。其结构图如下:
编写一个input子系统驱动程序,用于检测按键的中断,并将按键信息上报给应用。在kernel/drivers/input/keyboard目录下新建x4412_keys.c文件,编辑内容如下: - #include <linux/irq.h>
- #include <linux/interrupt.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <linux/errno.h>
- #include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <asm/uaccess.h>
- #include <linux/slab.h>
- #include <linux/device.h>
- #include <mach/gpio.h>
- #include <linux/input.h>
- /* 定义并初始化等待队列头 */
- static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
- static struct class *cdrv_class;
- static struct device *cdrv_device;
- void x4412_eint_do_tasklet(unsigned long data);
- DECLARE_TASKLET(x4412_eint_tasklet,x4412_eint_do_tasklet,0);
- typedef struct pin_desc
- {
- unsigned int pin;
- unsigned int key_val;
- }pin_desc;
- static struct pin_desc pins_desc[6] =
- {
- {EXYNOS4_GPX1(0),0x01},//LEFT
- {EXYNOS4_GPX1(3),0x02},//RIGHT
- {EXYNOS4_GPX1(2),0x03},//UP
- {EXYNOS4_GPX1(1),0x04},//DOWN
- {EXYNOS4_GPX1(5),0x05},//MENU
- {EXYNOS4_GPX1(4),0x06},//BACK
- };
- static struct input_dev *button_dev; /*输入设备结构体*/
- struct pin_desc *pin_desc_p;
- static int ev_press = 0;
- int major;
- void x4412_eint_do_tasklet(unsigned long data)
- {
- unsigned int pinval,state;
- pinval = gpio_get_value(pin_desc_p->pin);
- if(pinval)
- {
- state = 0;
- }
- else
- {
- state = 1;
- }
- ev_press = 1;
- printk("int:pin_desc_p->key_val=0x%x\r\n",pin_desc_p->key_val);
- input_report_key(button_dev, BTN_0, state); /*向输入子系统报告产生按键事件*/
- input_sync(button_dev); /*通知接收者,一个报告发送完毕*/
- wake_up_interruptible(&button_waitq);
- }
- /* 用户中断处理函数 */
- static irqreturn_t x4412_buttons_irq(int irq, void *dev_id)
- {
- pin_desc_p = (struct pin_desc *)dev_id;
- tasklet_schedule(&x4412_eint_tasklet);
- return IRQ_HANDLED;
- }
- static int x4412_eint_open(struct inode * inode, struct file * filp)
- {
- return 0;
- }
- static int x4412_eint_release(struct inode *inode, struct file *file)
- {
- int irq;
- irq = gpio_to_irq(pins_desc[0].pin);
- free_irq(irq, &pins_desc[0]);
- irq = gpio_to_irq(pins_desc[1].pin);
- free_irq(irq,&pins_desc[1]);
- irq = gpio_to_irq(pins_desc[2].pin);
- free_irq(irq,&pins_desc[2]);
- irq = gpio_to_irq(pins_desc[3].pin);
- free_irq(irq, &pins_desc[3]);
- irq = gpio_to_irq(pins_desc[4].pin);
- free_irq(irq,&pins_desc[4]);
- irq = gpio_to_irq(pins_desc[5].pin);
- free_irq(irq,&pins_desc[5]);
- return 0;
- }
- static const struct file_operations x4412_eint_fops =
- {
- .owner = THIS_MODULE,
- .open = x4412_eint_open,
- .release = x4412_eint_release,
- };
- /* 驱动入口函数 */
- static int x4412_eint_init(void)
- {
- int ret,irq;
- major = register_chrdev(0, "x4412-key", &x4412_eint_fops);
- cdrv_class = class_create(THIS_MODULE, "x4412-eint");
- cdrv_device = device_create(cdrv_class, NULL, MKDEV(major, 0), NULL, "x4412-eint");
- irq = gpio_to_irq(pins_desc[0].pin);
- ret = request_irq(irq, x4412_buttons_irq,IRQ_TYPE_EDGE_BOTH, "LEFT", &pins_desc[0]);
- if(ret)
- printk("request irq_eint8 error!\r\n");
- irq = gpio_to_irq(pins_desc[1].pin);
- ret = request_irq(irq, x4412_buttons_irq,IRQ_TYPE_EDGE_BOTH, "RIGHT",&pins_desc[1]);
- if(ret)
- printk("request irq_eint11 error!\r\n");
- irq = gpio_to_irq(pins_desc[2].pin);
- ret = request_irq(irq, x4412_buttons_irq, IRQ_TYPE_EDGE_BOTH, "UP", &pins_desc[2]);
- if(ret)
- printk("request irq_eint10 error!\r\n");
- irq = gpio_to_irq(pins_desc[3].pin);
- ret = request_irq(irq, x4412_buttons_irq, IRQ_TYPE_EDGE_BOTH, "DOWN", &pins_desc[3]);
- if(ret)
- printk("request irq_eint9 error!\r\n");
- irq = gpio_to_irq(pins_desc[4].pin);
- ret = request_irq(irq, x4412_buttons_irq, IRQ_TYPE_EDGE_BOTH, "MENU", &pins_desc[4]);
- if(ret)
- printk("request irq_eint13 error!\r\n");
- irq = gpio_to_irq(pins_desc[5].pin);
- ret = request_irq(irq, x4412_buttons_irq, IRQ_TYPE_EDGE_BOTH, "BACK", &pins_desc[5]);
- if(ret)
- printk("request irq_eint12 error!\r\n");
- pin_desc_p = kmalloc(sizeof(struct pin_desc), GFP_KERNEL);
- if(!pin_desc_p)
- {
- return -ENOMEM;
- }
- button_dev = input_allocate_device(); /*分配一个设备结构体*/
- if (!button_dev)
- {
- printk(KERN_ERR "x4412-key.c: Not enough memory\n");
- ret = -ENOMEM;
- goto err_free_irq;
- }
- button_dev->name = "x4412-key";
- button_dev->evbit[0] = BIT_MASK(EV_KEY); /*设置按键信息*/
- button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
- ret = input_register_device(button_dev); /*注册一个输入设备*/
- if (ret)
- {
- printk(KERN_ERR "x4412-key.c: Failed to register device\n");
- goto err_free_dev;
- }
- return 0;
- err_free_dev:
- input_free_device(button_dev);
- err_free_irq:
- free_irq(irq, x4412_buttons_irq);
- return ret;
- }
- /* 驱动出口函数 */
- static void x4412_eint_exit(void)
- {
- int irq;
- irq = gpio_to_irq(pins_desc[0].pin);
- free_irq(irq, &pins_desc[0]);
- irq = gpio_to_irq(pins_desc[1].pin);
- free_irq(irq,&pins_desc[1]);
- irq = gpio_to_irq(pins_desc[2].pin);
- free_irq(irq,&pins_desc[2]);
- irq = gpio_to_irq(pins_desc[3].pin);
- free_irq(irq, &pins_desc[3]);
- irq = gpio_to_irq(pins_desc[4].pin);
- free_irq(irq,&pins_desc[4]);
- irq = gpio_to_irq(pins_desc[5].pin);
- free_irq(irq,&pins_desc[5]);
- unregister_chrdev(major, "x4412-key");
- device_unregister(cdrv_device); //卸载类下的设备
- class_destroy(cdrv_class); //卸载类
- }
- module_init(x4412_eint_init); //用于修饰入口函数
- module_exit(x4412_eint_exit); //用于修饰出口函数
- MODULE_AUTHOR("www.9tripod.com");
- MODULE_LICENSE("GPL");
复制代码 结合源码,可以总结出添加一个输入子系统的几大步骤: 第一步:定义一个输入子系统结构体: - static struct input_dev *button_dev;
复制代码 第二步:通过input_allocate_device函数分配一个输入子系统结构体: - button_dev = input_allocate_device();
复制代码 第三步:定义输入子系统名称: - button_dev->name = "x4412-key";
复制代码 第四步:设置产生的事件及键值: - button_dev->evbit[0] = BIT_MASK(EV_KEY); /*设置按键信息*/
- button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
复制代码 第五步:注册一个输入设备: - ret = input_register_device(button_dev);
复制代码 第六步:当有输入事件产生时,向输入子系统报告产生的事件: - input_report_key(button_dev, BTN_0, state);
复制代码 第七步:通知接收者: 修改kernel/drivers/input/keyboard/Makefile文件,找到如下内容: - obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
复制代码 修改为: - obj-$(CONFIG_KEYBOARD_GPIO) += x4412_keys.o
复制代码 在make menuconfig指令中,找到 - Device Drivers --->Input device support --->Keyboards --->GPIO Buttons
复制代码 将驱动设置成模块,编译内核后,将会在kernel/drivers/input/keyboard目录下生成目标文件x4412_keys.ko。 在ubuntu用户目录或samba目录下新建测试程序x4412_keys-app.c,用于读取按键键值。编辑内容如下: - #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/select.h>
- #include <sys/time.h>
- #include <errno.h>
- #include <linux/input.h>
- int main(void)
- {
- int buttons_fd;
- int key_value,i=0,count;
- struct input_event ev_key;
- buttons_fd = open("/dev/input/event3", O_RDWR);
- if (buttons_fd < 0)
- {
- perror("open device buttons");
- exit(1);
- }
- for (;;)
- {
- count = read(buttons_fd,&ev_key,sizeof(struct input_event));
- for(i=0; i<(int)count/sizeof(struct input_event); i++)
- if(ev_key.type==EV_KEY)
- printf("type:%d,code:%d,value:%d\n", ev_key.type,ev_key.code-1,ev_key.value);
- if(ev_key.type==EV_SYN)
- printf("syn event\n\n");
- }
- close(buttons_fd);
- return 0;
- }
复制代码 测试程序通过open函数打开输入子系统的设备节点,通过如下指令查询驱动的设备节点: - cat /proc/bus/input/devices
复制代码 查询结果如下: - [root@x4412 mnt]# cat /proc/bus/input/devices
- I: Bus=0018 Vendor=dead Product=beef Version=28bb
- N: Name="ft5x06-ts"
- P: Phys=input/ts
- S: Sysfs=/devices/virtual/input/input0
- U: Uniq=
- H: Handlers=kbd event0
- B: PROP=0
- B: EV=b
- B: KEY=400 0 4 0 2000000 0 40000800 40 0 0 0
- B: ABS=2650000 1000003
-
- I: Bus=0000 Vendor=0000 Product=0000 Version=0000
- N: Name="gsensor"
- P: Phys=
- S: Sysfs=/devices/virtual/input/input1
- U: Uniq=
- H: Handlers=event1
- B: PROP=0
- B: EV=9
- B: ABS=100 7
-
- I: Bus=0019 Vendor=0000 Product=0000 Version=0000
- N: Name="gpio_ir_recv"
- P: Phys=
- S: Sysfs=/devices/virtual/rc/rc0/input2
- U: Uniq=
- H: Handlers=kbd event2
- B: PROP=0
- B: EV=100013
- B: KEY=60000 2008000 0 40400800 1e16c0 0 0 10004ffc
- B: MSC=10
-
- I: Bus=0000 Vendor=0000 Product=0000 Version=0000
- N: Name="x4412-key"
- P: Phys=
- S: Sysfs=/devices/virtual/input/input3
- U: Uniq=
- H: Handlers=event3
- B: PROP=0
- B: EV=3
- B: KEY=1 0 0 0 0 0 0 0 0
-
- [root@x4412 mnt]#
复制代码 这些都是输入子系统设备,其中x4412-key对应的设备节点为event3。编译测试程序,加载驱动模块后,使用测试程序测试效果如下: - [root@x4412 mnt]# insmod x4412-key.ko
- [ 47.368709] input: x4412-key as /devices/virtual/input/input3
- [root@x4412 mnt]# ./x4412-key-app
- [ 53.388507] int:pin_desc_p->key_val=0x1
- count=16
- type:1,code:255,value:1
- count=16
- syn event
复制代码 |