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;
}
相关推荐
littlegirll2 小时前
ssh远程调用图形程序
运维·ssh·x11forwarding·远程调用图形界面
星期五不见面2 小时前
虚拟机使用外部WPN网络
linux
OnlyEasyCode2 小时前
Linux下载Navicat、特定版本Mysql
linux·运维·服务器
宇宙帅猴3 小时前
【Ubuntu踩坑及解决方案(一)】
linux·运维·ubuntu·go
济6173 小时前
linux 系统移植(第七期)----U-Boot 图形化配置及其原理-- Ubuntu20.04
linux·运维·服务器
_Xiaosz3 小时前
Photo-SLAM / ORB-SLAM3 编译报错解决:undefined reference to DUtils::Random
linux·ubuntu
kida_yuan3 小时前
【Linux】文件系统与 fsck.ext4 修复 - 我踩过的坑与总结
linux·运维·网络
Star Learning Python3 小时前
MySQL基础知识的总结
运维
何以不说话3 小时前
mysql 的主从复制
运维·数据库·学习·mysql