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;
}
相关推荐
sxstj6 分钟前
Ubuntu 完整安装并启用 Flatpak 教程
linux·运维·ubuntu
国际云,接待9 分钟前
Nginx 后面接负载均衡,502/504 到底该先查哪里?
运维·nginx·负载均衡
Sylvia33.11 分钟前
从轮询到推送:足球数据API架构演进与火星数据技术拆解
java·服务器·网络·python·websocket·架构
天疆说29 分钟前
Ubuntu 26.04 下 Intel Meteor Lake 核显 + NPU 驱动配置与 PyTorch NPU 推理实测
linux·pytorch·ubuntu
mounter6251 小时前
突破单点限制:BPF 多跟踪点高效附加机制与新 ftrace 架构解析
linux·ebpf·linux kernel·kernel·ftrace
刘某的Cloud1 小时前
Galera Cluster部署 mariadb 节点down机,log sequence number恢复
linux·运维·数据库·负载均衡·mariadb·集群·高可用
小此方1 小时前
Re:Linux系统篇(五十四)线程篇 · 七:互斥锁的底层实现原理:从硬件上下文、原子交换指令(Swap)到并发封装实战
linux·运维·驱动开发
郭涤生2 小时前
rootfs 详解与裁剪优化记录
linux·c++·bsp
铁锚2 小时前
解决Ubuntu执行sudo时 unable to resolve host 报错问题
linux·数据库·ubuntu
二宝哥3 小时前
CentOS 7.9 离线安装 Nginx 并配置openssl1.1.1
linux·nginx·centos