Linux驱动--基于驱动设备分离的按键中断驱动

一、设备树

1、设备树概述

设备树是搭配驱动使用,记录硬件信息的一种文件形式,常见的设备树文件类型如下

  • .dts文件:设备树源代码
  • .dtsi文件:用于存放可以被多个dts文件共享的公共硬件描述部分,类似于C语言中的头文件
  • DTC:设备树的编译工具
  • .dtb文件:编译成二进制的设备树文件

2、设备树的语法规则

设备树的编写格式如下

节点{

属性1;

属性2 = 整形值;

属性3 = 字符值;

属性4 = 数组;

属性5 = &节点名;

};

下面以led设备树为例,介绍设备树的基本语法结构

puteled {

#address-cells = <1>;

#size-cells = <1>;

compatible = "pute-led";

reg = <0x20E0068 0x4

0x20E02F4 0x4

... ...

>;

status = "okay";

};

puteled:节点名

#address-cells:该节点下的reg属性中的地址占1个字(4个字节)

#size-cells:该节点下的reg属性中的地址大小占1个字(4个字节)

compatible:将来用于总线驱动中设备与驱动的匹配

reg:寄存器地址和寄存器地址的大小

status:使能该节点 okay disable关闭该节点

3、设备树子系统

pinctrl子系统

主要功能:主要用于设置引脚的复用功能

在相应设备树文件iomuxc节点中定义controller引脚配置:

pinctrl_putekey: putekey {

fsl,pins = <MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xf0b0>

};

其中

MX6UL_PAD_UART1_CTS_B__GPIO1_IO18为 IO 复用配置

0xf0b0为引脚电器属性

在对应的 putekey 设备树节点中添加如下语句

pinctrl-names = "default";

定义设备的状态名称,其中default表示设备在正常工作时的默认状态

pinctrl-0 = <&pinctrl_putekey>;

pinctrl-0 属性指定了第0个状态(即default状态)所对应的引脚配置

<&pinctrl_putekey>表示引用 pinctrl 中的 pinctrl_putekey 节点

二、驱动代码实现

实现按键中断的相关代码如下

1.设备、中断相关操作

1.1 在 misc 设备中注册按键设备
cpp 复制代码
static struct file_operations fops = {
    .owner = THIS_MODULE,
    .read = key_read,
};

static struct miscdevice misc_key = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "misc_key",
    .fops = &fops,
};

int ret = 0;
    
init_waitqueue_head(&wq);

ret = misc_register(&misc_key);
if (ret) {
    pr_info("misc_register failed\n");
    return -1;
}
1.2 查找设备树节点、获取GPIO编号
cpp 复制代码
    pkeynode = of_find_node_by_path("/putekey");
    if (NULL == pkeynode) {
        pr_info("of_find_node_by_path failed\n");
        return -1;
    }
    //从设备树节点属性中获取GPIO编号
    gpiokey = of_get_named_gpio(pkeynode, "gpio-key", 0);
    if (gpiokey < 0) {
        pr_info("of_get_named_gpio failed\n");
        return -1;
    }
1.3申请、配置GPIO
cpp 复制代码
    //申请使用GPIO引脚
    ret = gpio_request(gpiokey, "pute-key-gpio");
    if (ret) {
        pr_info("gpio_request failed\n");
        return -1;
    }

    //配置GPIO输入/输出方向
    ret = gpio_direction_input(gpiokey);
    if (ret) {
        pr_info("gpio_direction_input failed\n");
        return -1;
    }
1.4 获取、注册中断号
cpp 复制代码
    //将GPIO软件编号映射为中断号
#if 0
    irqno = gpio_to_irq(gpiokey);
    if (irqno < 0) {
        pr_info("gpio_to_irq failed\n");
        return -1;
    }
#endif

    //从设备树节点解析获取软件逻辑中断号
    irqno = of_irq_get(pkeynode, 0);
    if (irqno < 0) {
        pr_info("of_irq_get failed\n");
        return -1;
    }

    //注册中断号与中断处理函数
    ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING, "pute-irq-key", NULL);
    if (ret) {
        pr_info("request_irq failed\n");
        return -1;
    }

2、驱动端功能代码

cpp 复制代码
static ssize_t key_read(struct file *fp, char __user *puser, size_t n, loff_t *off)
{
    unsigned long nret = 0;

    condition = 0;
    status = 0;
    wait_event_interruptible(wq, condition);    //阻塞等待

    nret = copy_to_user(puser, &status, sizeof(status));//驱动与应用层交互,传递按键状态信息
    if (nret) {
        pr_info("copy_to_user failed\n");        
        return -1;
    }

    return nret;
}

static irqreturn_t key_irq_handler(int irqno, void *pdev)
{
    condition = 1;
    status = 1;
    wake_up_interruptible(&wq);                 //检测到按键信号唤醒

    return IRQ_HANDLED;
}

3、应用层代码

cpp 复制代码
int main(void)
{
    int fd = 0;
    int stat = 0;

    fd = open("/dev/misc_key", O_RDWR);
    if (-1 == fd)
    {
        perror("fail to open");
        return -1;
    }

    while (1)
    {
        //当按键被按下时,获取到stat信息
        read(fd, &stat, sizeof(stat));        
        printf("stat = %d\n", stat);
    }

    close(fd);

    return 0;
}
相关推荐
SuperArc1999几秒前
Grafana相关数据可视化平台基础教程-序言
运维·信息可视化·数据分析·grafana
半部论语5 分钟前
openEuler 安装 LibreOffice 技术指南
linux
r-t-H5 分钟前
Docker进阶与容器编排实践-第二章
运维·docker·容器·dockerfile·docker compose·docker网络
爱装代码的小瓶子10 分钟前
muduo库 --socket的封装
服务器·开发语言·php
凡人叶枫10 分钟前
Effective C++ 条款13:以对象管理资源(RAII)
java·linux·开发语言·c++·嵌入式开发
爱喝水的鱼丶14 分钟前
SAP-ABAP:SAP多表连接视图实战:内连接/外连接配置逻辑与性能优化技巧
运维·开发语言·学习·性能优化·sap·abap
cgsthtm16 分钟前
Jenkins添加用户和角色并分配相应Job权限
运维·jenkins·jenkins用户·jenkins角色·jenkins权限·jenkins job
mnasd19 分钟前
Gitlab + Jenkins 实现 CICD
运维·gitlab·jenkins
m0_7373025821 分钟前
OpenClaw:不止于对话,能真正动手的开源 AI 智能体
服务器
難釋懷25 分钟前
Nginx测试工具charles
运维·nginx·php