驱动开发 Linux按键中断点灯

华清远见上海中心22071班

三个按键实现按键中断,

key1->led1

key2->led2

key3->led3

按键按一下灯亮,再按一下灯灭 

#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>

#define CNAME "myled"
int major;
int minor = 0;
int count = 3;
int irqnum_key1;
int irqnum_key2;
int irqnum_key3;
struct cdev *cdev;
struct class *cls;
struct device *dvc;
struct device_node *lednode;
struct device_node *irqnode;
struct gpio_desc *topled1;
struct gpio_desc *topled2;
struct gpio_desc *topled3;
// myleds
// {
//     topled1 = <&gpioe 10 0>;
//     topled2 = <&gpiof 10 0>;
//     topled3 = <&gpioe 8 0>;
// };
// myirq
// {
//     interrupt-parent = <&gpiof>;
//     interrupts = <7 0>, <8 0>, <9 0>; //第一个成员指的是gpio编号,第二个成员表示触发方式,0表示默认属性
// };

struct file_operations fops;

irqreturn_t irq_handler_key1(int irqno, void *dev)
{
    gpiod_set_value(topled3, !gpiod_get_value(topled3));
    return IRQ_HANDLED;
}

irqreturn_t irq_handler_key2(int irqno, void *dev)
{
    gpiod_set_value(topled2, !gpiod_get_value(topled2));
    return IRQ_HANDLED;
}

irqreturn_t irq_handler_key3(int irqno, void *dev)
{
    gpiod_set_value(topled1, !gpiod_get_value(topled1));
    return IRQ_HANDLED;
}

static int __init led_init(void)
{
    int res, i;
    dev_t devt;

    //分配cdev结构
    cdev = cdev_alloc();
    if (NULL == cdev)
    {
        printk("申请空间失败\n");
        res = -EIO;
        goto ERR1;
    }

    //初始化cdev结构体
    cdev_init(cdev, &fops);

    //动态注册字符设备编号
    res = alloc_chrdev_region(&devt, 0, count, CNAME);
    if (res)
    {
        printk("动态注册字符设备编号失败(err %d)\n", -res);
        goto ERR2;
    }
    major = MAJOR(devt);
    minor = MINOR(devt);

    //向系统中添加字符设备
    res = cdev_add(cdev, devt, count);
    if (res)
    {
        printk("系统添加字符设备失败(err %d)\n", -res);
        goto ERR3;
    }

    //上传目录
    cls = class_create(THIS_MODULE, CNAME);
    if (IS_ERR(cls))
    {
        printk("上传目录失败 (err %ld)\n", PTR_ERR(cls));
        res = PTR_ERR(cls);
        goto ERR4;
    }

    //上传节点
    for (i = 0; i < count; i++)
    {
        dvc = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
        if (IS_ERR(dvc))
        {
            printk("节点上传失败 (err %ld)\n", PTR_ERR(dvc));
            res = PTR_ERR(dvc);
            goto ERR5;
        }
    }

    lednode = of_find_node_by_path("/myleds");
    if (NULL == lednode)
    {
        printk("寻找设备树节点失败\n");
        res = -EFAULT;
        goto ERR5;
    }

    //申请GPIO号
    topled1 = gpiod_get_from_of_node(lednode, "topled1", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(topled1))
    {
        printk("topled1 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled1));
        res = PTR_ERR(topled1);
        goto ERR5;
    }

    topled2 = gpiod_get_from_of_node(lednode, "topled2", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(topled2))
    {
        printk("topled2 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled2));
        res = PTR_ERR(topled2);
        goto ERR5;
    }

    topled3 = gpiod_get_from_of_node(lednode, "topled3", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(topled3))
    {
        printk("topled3 GPIO号获取编号失败 (err %ld)\n", PTR_ERR(topled3));
        res = PTR_ERR(topled3);
        goto ERR5;
    }

    //设置相对应的gpio引脚为输出模式
    gpiod_direction_output(topled1, 0);
    gpiod_direction_output(topled2, 0);
    gpiod_direction_output(topled3, 0);

    //获取中断设备树节点
    irqnode = of_find_node_by_path("/myirq");
    if (NULL == lednode)
    {
        printk("寻找设备树节点失败\n");
        res = -EFAULT;
        goto ERR5;
    }

    //从节点信息中获取KEY1软中断号
    irqnum_key1 = irq_of_parse_and_map(irqnode, 2);
    if (irqnum_key1 == 0)
    {
        printk("key1 获取软中断号失败\n");
        res = -EINVAL;
        goto ERR5;
    }

    //从节点信息中获取KEY2软中断号
    irqnum_key2 = irq_of_parse_and_map(irqnode, 0);
    if (irqnum_key2 == 0)
    {
        printk("key2 获取软中断号失败\n");
        res = -EINVAL;
        goto ERR5;
    }

    //从节点信息中获取KEY3软中断号
    irqnum_key3 = irq_of_parse_and_map(irqnode, 1);
    if (irqnum_key3 == 0)
    {
        printk("key3 获取软中断号失败\n");
        res = -EINVAL;
        goto ERR5;
    }

    //将需要使用的软中断号key1注册进内核
    res = request_irq(irqnum_key1, irq_handler_key1, IRQF_TRIGGER_FALLING, "key1_inte", NULL);
    if (res)
    {
        printk("key1 注册失败\n");
        return -EINVAL;
    }
    //将需要使用的软中断号key2注册进内核
    res = request_irq(irqnum_key2, irq_handler_key2, IRQF_TRIGGER_FALLING, "key2_inte", NULL);
    if (res)
    {
        printk("key2 注册失败\n");
        return -EINVAL;
    }
    //将需要使用的软中断号key3注册进内核
    res = request_irq(irqnum_key3, irq_handler_key3, IRQF_TRIGGER_FALLING, "key3_inte", NULL);
    if (res)
    {
        printk("key3 注册失败\n");
        return -EINVAL;
    }

    return 0;
ERR5:
    for (--i; i >= 0; i--)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);

ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(devt, count);
ERR2:
    kfree(cdev);
ERR1:
    return res;
}

static void __exit led_exit(void)
{
    int i;
    gpiod_set_value(topled1, 0);
    gpiod_set_value(topled2, 0);
    gpiod_set_value(topled3, 0);

    gpiod_put(topled1);
    gpiod_put(topled2);
    gpiod_put(topled3);

    for (i = 0; i < count; i++)
    {
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);

    cdev_del(cdev);

    unregister_chrdev_region(MKDEV(major, minor), count);

    kfree(cdev);

    free_irq(irqnum_key1, NULL);
    free_irq(irqnum_key2, NULL);
    free_irq(irqnum_key3, NULL);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值