Linux 一个简单的input设备驱动

本文详细解析了一个简单的Linux内核输入设备驱动程序,涉及中断注册、设备注册以及中断处理函数。通过request_irq注册中断处理函数button_interrupt,当按键按下时执行。在设备注册过程中,配置了input_dev结构体,指定了设备响应的事件类型EV_KEY及按键BTN_0。在中断处理函数中,根据读取的端口数据报告按键状态。此代码适用于理解Linux内核驱动开发的基础原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

代码解析

1、中断注册

2、设备注册

3、中断处理函数


一个简单的input设备驱动,先直接上代码

#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>

#include <asm/irq.h>
#include <asm/io.h>

static struct input_dev *button_dev;

static irqreturn_t button_interrupt(int irq, void *dummy)
{
        input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);
        input_sync(button_dev);
        return IRQ_HANDLED;
}

static int __init button_init(void)
{
        int error;

        if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
                printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
                return -EBUSY;
        }

        button_dev = input_allocate_device();
        if (!button_dev) {
                printk(KERN_ERR "button.c: Not enough memory\n");
                error = -ENOMEM;
                goto err_free_irq;
        }

        button_dev->evbit[0] = BIT_MASK(EV_KEY);
        button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);

        error = input_register_device(button_dev);
        if (error) {
                printk(KERN_ERR "button.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(BUTTON_IRQ, button_interrupt);
        return error;
}

static void __exit button_exit(void)
{
        input_unregister_device(button_dev);
        free_irq(BUTTON_IRQ, button_interrupt);
}

module_init(button_init);
module_exit(button_exit);

input子系统是Linux下所有输入设备的一个集合,大多数都放在drivers/input目录下,也有一些放在drivers/platform,drivers/hid 。

代码解析

1、中断注册

request_irq主要负责注册一个中断,当有按键按下时,执行中断处理函数button_interrupt。

2、设备注册

  • 先分配一个input_dev空间button_dev;
  • 设定好响应的事件button_dev->evbit[0]=BIT_MASK(EV_KEY)响应的类型,这里指定的一个key类型,当然可以EV_SYNC(标记不同的事件比如时间和空间都改变的多触控协议)、EV_REL(相对位移改变比如鼠标)、EV_ABS(绝对位移的设备比如触摸屏)、EV_MSC(混杂设备)、EV_SW(二进制的开关设备)、EV_LED(改变LED开关设备)、EV_SND(输出声音设备)、EV_REP(自动重复设备)、EV_FF(强制设备输出反馈信息)、EV_POW(特殊的电源开关)、EV_FF_STATUS(接收强制返回回馈信息的状态);
  • 存储key有哪些状态值,也就是有哪些keycode,方便在中断中对相应的keycode做相应处理;
  • input_register_device至此完成input设备驱动的注册登记。

3、中断处理函数

这里混合了按下和抬起两个操作的写法,也可以将两者分开,当按下的时候input_report_key最后一个参数为1、当抬起来的时候为0.

static irqreturn_t button_interrupt(int irq, void *dummy)
{
        if(inb(BUTTON_PORT)){   // keydown
            input_report_key(button_dev, BTN_0, 1);
        }else{                  // keyup
            input_report_key(button_dev, BTN_0, 0);
        }
        
        input_sync(button_dev);
        return IRQ_HANDLED;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值