新手上路
- 积分
- 35
- 金钱
- 35
- 注册时间
- 2020-10-27
- 在线时间
- 9 小时
|
基于原子教程的input子系统的学习历程
修改部分为:由一个按键改为两个按键,涉及gpio的操作、定时器的初始化和注册等都有变动
学习所得:通过input子系统的学习,把按键、定时器、设备树又进行了一次复习,又有了不一样的理解,代码中我有加粗的部分,供大家参考。具体代码如下:
设备树部分如下:
- mytest_key {
- compatible = "mykey_gpio";
- pinctrl-names = "default";
- pinctrl-0 = <&myGPIO_key0
- &myGPIO_key1>;
- gpios = <&gpio5 1 GPIO_ACTIVE_LOW
- &gpio4 14 GPIO_ACTIVE_LOW>;
- };
复制代码
驱动部分:
- #include <linux/types.h>
- #include <linux/kernel.h>
- #include <linux/delay.h>
- #include <linux/ide.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/errno.h>
- #include <linux/gpio.h>
- #include <linux/cdev.h>
- #include <linux/device.h>
- #include <linux/of.h>
- #include <linux/of_address.h>
- #include <linux/of_gpio.h>
- #include <linux/input.h>
- #include <linux/semaphore.h>
- #include <linux/timer.h>
- #include <linux/of_irq.h>
- #include <linux/irq.h>
- #include <asm/mach/map.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #define KEYINPUT_NAME "keyinput" /* 名字 */
- #define KEY0VALUE 0X01 /* KEY0按键值 */
- #define INVAKEY 0XFF /* 无效的按键值 */
- #define KEY_NUM 2 /* 按键数量 */
- struct irq_keydesc{
- unsigned char value; /*键值*/
- int gpio;
- int flags;
- struct gpio_desc *gpio_key;
- int irqnum; /* 中断号 */
- irqreturn_t (*handler)(int, void *); /* 中断服务函数 */
- };
- struct input_key_test{
- dev_t devid; /* 设备号 */
- struct cdev cdev; /* cdev */
- struct class *class; /* 类 */
- struct device *device; /* 设备 */
- struct device_node *nd; /* 设备节点 */
- struct irq_keydesc *irqkeydesc; /* 按键描述数组 */
- struct timer_list timer; /* 定义一个定时器*/
- unsigned char curkeynum; /* 当前的按键号 */
- struct input_dev *inputdev; /* input结构体 */
- };
- static struct input_key_test keyinputdev;
- static irqreturn_t key_handle0(int irq, void *dev_id)
- {
- struct input_key_test *dev = (struct input_key_test *)dev_id;
- // printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
- dev->timer.data = (unsigned long)dev_id;
- dev->curkeynum =0;
- mod_timer(&dev->timer , jiffies + HZ/5); /*延时去抖*/
- return IRQ_HANDLED;
- }
- static irqreturn_t key_handle1(int irq, void *dev_id)
- {
- struct input_key_test *dev = (struct input_key_test *)dev_id;
- // printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
- dev->timer.data = (unsigned long)dev_id;
- dev->curkeynum =1;
- mod_timer(&dev->timer , jiffies + HZ/5); /*延时去抖*/
- return IRQ_HANDLED;
- }
- static void timer_handle0(unsigned long arg)
- {
- int num;
- int key;
- struct input_key_test *dev = (struct input_key_test *)arg;
- struct irq_keydesc *keydesc;
- // printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
- // printk("key num = %d\n",dev->curkeynum);
- num = dev->curkeynum;
- keydesc = &dev->irqkeydesc[num];
- key = gpiod_get_value(keydesc->gpio_key );
- // printk("key is %d\n",key);
- if(key == 0){ /* 按下按键 */
- /* 上报按键值 */
- //input_event(dev->inputdev, EV_KEY, keydesc->value, 1);
- input_report_key(dev->inputdev, keydesc->value, 1);/* 最后一个参数表示按下还是松开,1为按下,0为松开 */
- input_sync(dev->inputdev);
- } else { /* 按键松开 */
- //input_event(dev->inputdev, EV_KEY, keydesc->value, 0);
- input_report_key(dev->inputdev, keydesc->value, 0);
- input_sync(dev->inputdev);
- }
- }
- static int keyio_init(void)
- {
- int i;
- int err;
- int count;
- enum of_gpio_flags flag;
- /*获取设备树信息*/
- keyinputdev.nd = of_find_node_by_path("/mytest_key"); /*获取设备节点*/
- if(keyinputdev.nd == NULL)
- {
- printk("key node not find!\r\n");
- return -1;
- }
- printk("keyinputdev.nd name is %s\n",keyinputdev.nd->name);
- <div><b> count = of_gpio_count(keyinputdev.nd);//此处注意点:of_gpio_count在匹配设备树时,是匹配的gpios ,由于前期用的是gpiod_get这个函数,对应的设备树中需要写成“key-gpios”,所以我在这个地方被自己给坑了很久</b></div><div><b>//另外在写驱动的时候,对函数的返回值最好做判断,就比如对count我之前没有做判断(设备树中还是key-gpios),导致count的返回值是 -2,而我又没有对count的返回判断(即,没有下面的if(count<0)这个判断),加载模块就挂掉,内核反馈的错误</b></div><div><b>//代码也看不懂,只能重启,修改代码,测试,挂掉,重启......循环下去</b></div> <b></b><b></b>
- if(count < 0)
- {
- printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
- return -1;
- }
- /*
- 内存分配
- 请求大小:gpio个数 * 一个结构体的大小
- 返回:申请内存的指针,正好给结构体指针
- */
- keyinputdev.irqkeydesc = kmalloc(count * sizeof(struct irq_keydesc), GFP_KERNEL);
-
- keyinputdev.irqkeydesc[0].handler = key_handle0;
- keyinputdev.irqkeydesc[1].handler = key_handle1;
- for(i=0 ;i<count;i++)
- {
- keyinputdev.irqkeydesc[i].gpio = of_get_gpio_flags(keyinputdev.nd, i, &flag); /*获取gpio*/
- keyinputdev.irqkeydesc[i].gpio_key = gpio_to_desc(keyinputdev.irqkeydesc[i].gpio); /*由gpio转换为gpio_desc*/
- keyinputdev.irqkeydesc[i].flags = flag & OF_GPIO_ACTIVE_LOW;
- keyinputdev.irqkeydesc[i].irqnum = gpio_to_irq(keyinputdev.irqkeydesc[i].gpio);
- //keyinputdev.irqkeydesc[i].handler = key_handle0;
- /*注册中断*/
- err = request_irq(keyinputdev.irqkeydesc[i].irqnum, keyinputdev.irqkeydesc[i].handler,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq_test0", &keyinputdev);
- if(err < 0)
- {
- printk("irq %d request failed!\r\n", keyinputdev.irqkeydesc[i].irqnum);
- return -EFAULT;
- }
- }
- keyinputdev.irqkeydesc[0].value =KEY_0;
- keyinputdev.irqkeydesc[1].value =KEY_1;
-
- /*设置定时器*/
-
- setup_timer(&keyinputdev.timer , timer_handle0, (unsigned long)&keyinputdev);
- keyinputdev.timer.expires = ~0 ;
- add_timer(&keyinputdev.timer);
- #if 0
- init_timer(&keyinputdev.timer); //初始化定时器
- keyinputdev.timer.function = timer_handle0; //设置定时器触发时函数
- keyinputdev.timer.expires = ~0 ;
- // add_timer(&keyinputdev.timer);
- #endif
- /* 申请input_dev */
- keyinputdev.inputdev = input_allocate_device();
- keyinputdev.inputdev->name = KEYINPUT_NAME;
- keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY);
- for(i=0 ;i<count;i++)
- {
- input_set_capability(keyinputdev.inputdev, EV_KEY, keyinputdev.irqkeydesc[i].value); /*设置keybit*/
- }
- /*注册input_dev*/
- err = input_register_device(keyinputdev.inputdev);
- return 0;
-
- }
- static int __init keyinput_init(void)
- {
- keyio_init();
- return 0;
- }
- /*
- * @description : 驱动出口函数
- * [url=home.php?mod=space&uid=271674]@param[/url] : 无
- * @return : 无
- */
- static void __exit keyinput_exit(void)
- {
- int count;
- unsigned int i = 0;
- printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
- /*获取设备树信息*/
- keyinputdev.nd = of_find_node_by_path("/mytest_key"); /*获取设备节点*/
- count = of_gpio_count(keyinputdev.nd);
-
- if(count < 0)
- {
- printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);
-
- }
- /* 删除定时器 */
- #if 0
- for(i=0 ;i<count;i++)
- {
- del_timer(&keyinputdev.irqkeydesc[i].timer ); /* 删除定时器 */
- }
- #endif
- del_timer(&keyinputdev.timer ); /* 删除定时器 */
- /* 释放中断 */
- for (i = 0; i < count; i++) {
- free_irq(keyinputdev.irqkeydesc[i].irqnum, &keyinputdev);
- }
- /* 释放input_dev */
- input_unregister_device(keyinputdev.inputdev);
- input_free_device(keyinputdev.inputdev);
- }
- module_init(keyinput_init);
- module_exit(keyinput_exit);
- MODULE_LICENSE("GPL");
复制代码 应用层和原子的一样,就不上传了。
|
|