练习
基于platform实现
 
设备树
 myplatform_homework{
        compatible = "hqyj,myplatform_homework";      //用于获取节点
                reg = <0x12345678 14>;
        interrupt-parent = <&gpiof>;  //引用父节点
        interrupts = <9 0>; //这个节点引入的中断管脚
        led1-gpio = <&gpioe 10 0>;
    };
应用程序
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *agrv[])
{
    unsigned int number = 0;
    int fd = open("/dev/myplatform", O_RDWR);
    if (fd < 0)
    {
        printf("打开设备文件失败\n");
        return -1;
    }
    printf("打开设备文件成功\n");
    while (1)
    {
        read(fd, &number, sizeof(number));
        printf("number = %d\n", number);
    }
    close(fd);
    return 0;
}
驱动
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/interrupt.h>
struct resource *res;
unsigned int irqno;
struct gpio_desc *gpiono;
unsigned int condition = 0;
unsigned int status = 0;
// 定义等待队列头
wait_queue_head_t wq_head;
unsigned int major = 0;
struct class *cls;
struct device *dev;
// 定义中断处理函数
irqreturn_t key_handler(int irq, void *dev)
{
    status = gpiod_get_value(gpiono);
    status = !status;
    gpiod_set_value(gpiono, status);
    condition = 1;
    wake_up_interruptible(&wq_head); // 唤醒休眠的进程
    return IRQ_HANDLED;
}
// 封装操作方法
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    if (size > sizeof(status))
        size = sizeof(status);
    wait_event_interruptible(wq_head, condition);
    int ret = copy_to_user(ubuf, (void *)&status, size);
    if (ret)
    {
        printk("copy_to_user failed\n");
        return ret;
    }
    condition = 0; // 表示下次的数据没有准备好
    return 0;
}
// 定义一个操作方法结构体变量并且初始化
struct file_operations fops = {
    .read = mycdev_read,
};
// 1.封装probe函数和remove函数
int pdrv_probe(struct platform_device *pdev) // 在进入probe函数的时候节点已经被放在pdev->dev.of_node中了
{
    int ret;
    // 1.注册字符设备驱动
    major = register_chrdev(0, "myplatform", &fops);
    if (major < 0)
    {
        printk("注册字符设备驱动失败\n");
        ret = major;
        goto ERR1;
    }
    printk("注册字符设备驱动成功major=%d\n", major);
    // 2.创建设备节点
    cls = class_create(THIS_MODULE, "myplatform");
    if (IS_ERR(cls))
    {
        printk("向上提交目录信息失败\n");
        ret = PTR_ERR(cls);
        goto ERR2;
    }
    printk("向上提交目录信息成功\n");
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "myplatform");
    if (IS_ERR(dev))
    {
        printk("向上提交设备节点失败\n");
        ret = PTR_ERR(dev);
        goto ERR3;
    }
    printk("向上提交设备节点成功\n");
    // 3.初始化等待队列头
    init_waitqueue_head(&wq_head);
    gpiono = gpiod_get_from_of_node(pdev->dev.of_node, "led1-gpio", 0, GPIOD_OUT_LOW, NULL);
    if (IS_ERR(gpiono))
    {
        printk("解析gpio信息失败\n");
        ret = PTR_ERR(gpiono);
        goto ERR4;
    }
    printk("解析gpio信息成功\n");
    irqno = platform_get_irq(pdev, 0); // 获取中断的信息
    if (irqno < 0)
    {
        printk("获取中断类型资源失败\n");
        ret = irqno;
        goto ERR5;
    }
    printk("软中断号: %d\n", irqno);
    ret = request_irq(irqno, key_handler, IRQF_TRIGGER_FALLING, "myplatform", NULL);
    if (ret)
    {
        printk("注册中断失败\n");
        goto ERR5;
    }
    printk("注册中断成功\n");
    return 0;
ERR5:
    gpiod_put(gpiono);
ERR4:
    device_destroy(cls, MKDEV(major, 0));
ERR3:
    class_destroy(cls);
ERR2:
    unregister_chrdev(major, "myplatform");
ERR1:
    return ret;
}
int pdrv_remove(struct platform_device *pdev)
{
    // 关灯
    gpiod_set_value(gpiono, 0);
    // 释放gpio信息
    gpiod_put(gpiono);
    unregister_chrdev(major, "myplatform");
    class_destroy(cls);
    device_destroy(cls, MKDEV(major, 0));
    free_irq(irqno, NULL);
    return 0;
}
struct of_device_id oftable[] = {
    {.compatible = "hqyj,myplatform_homework"},
    {.compatible = "hqyj,myplatform_homework1"},
    {.compatible = "hqyj,myplatform_homework2"},
    {}, // 防止数组越界
};
// 2.分配驱动信息对象并初始化
struct platform_driver pdrv = {
    .probe = pdrv_probe,
    .remove = pdrv_remove,
    .driver = {
        .name = "aaaaa",           // 用于名字匹配
        .of_match_table = oftable, // 用于设备树匹配
    },
};
// 一键注册宏
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");```



















