【linux内核中断】

1.linux内核中断子系统相关的API

解析中断的相关设备树节点信息

of_find_compatible_node

根据解析的中断信息获取软中断号

irq_of_parse_and_map(struct device_node *dev,int index)

参数:dev中断对应的设备树节点指针 index:当前中断 对应值的索引号

返回值:成功返回软中断号,失败返回0

注册中断

request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char *name,void *dev)

参数:irq:当前中断的软中断号

handler:中断处理函数的函数指针

flags:设置中断的触发方式

name:当前中断名字

dev:传递给中断处理程序的参数,也是当前中断对应的irqatction的key值

注销中断

void *free_irq(unsigned int irq,void *dev_id)

参数:

irq:要注销的中断对应的软中断号

dev_id:request_irq最后一个参数的数值,一定要写的和注册时的一样,不然会报错

6.中断底半部

中断顶半部:主要处理一些紧急,不耗时的任务

中断底半部:主要处理一些不紧急,耗时的任务

tasklet

tasklet机制是基于软中断实现的一种底半部的机制,但是相比较于软中断,tasklet没有最大数量的限制

驱动代码

复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
int number = 0;
struct device_node *dnode;
unsigned int key_irqno[3];
struct cdev *cdev;
unsigned int major;
unsigned int minor;
dev_t devno;
unsigned int condition = 0;
struct class *cls;
struct device *dev;
// 定义等待队列头
wait_queue_head_t wq_head;
char kbuf[128] = {0};
struct device_node *dnode;
unsigned int gpiono;
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    // 将准备好的硬件数据拷贝到用户空间
    int ret = copy_to_user(ubuf, (void *)number, size);
    if (ret)
    {
        printk("copy_to_user err\n");
        return ret;
    }
    return 0;
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{

    return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}
// 定义操作方法结构体遍历并且初始化
struct file_operations fops = {
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,
};
irqreturn_t key_handler(int irq, void *dev)
{
    // 根据dev的数值的不同来区分不同的按键
    int which = (int)dev;
    switch (which)
    {
    case 0:
        number = 0;
        if (gpio_get_value(gpiono))
            // 亮灯
            gpio_set_value(gpiono, 1);
        else
            gpio_set_value(gpiono, 0);
        printk("key1 interrupt\n");
        break;
    case 1:
        number = 1;
        if (gpio_get_value(gpiono))
            // 亮灯
            gpio_set_value(gpiono, 1);
        else
            gpio_set_value(gpiono, 0);
        printk("key2 interrupt\n");
        break;
    case 2:
        number = 2;
        if (gpio_get_value(gpiono))
            // 亮灯
            gpio_set_value(gpiono, 1);
        else
            gpio_set_value(gpiono, 0);
        printk("key3 interrupt\n");
        break;

    default:
        break;
    }

    return IRQ_HANDLED;
}
static int __init mycdev_init(void)
{
    // 注册字符设备驱动
    major = register_chrdev(0, "MYchrdev", &fops);
    if (major < 0)
    {
        printk("字符设备驱动注册失败\n");
        return major;
    }
    printk("字符设备驱动注册成功major=%d\n", major);

    // 向上提交目录信息
    cls = class_create(THIS_MODULE, "MYcdev");
    if (IS_ERR(cls))
    {
        printk("向上提交目录信息失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交目录信息成功\n");
    // 向上提交设备信息
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "MYcdev%d", 0);
    if (IS_ERR(dev))
    {
        printk("向上提交设备节点失败\n");
        return -PTR_ERR(cls);
    }
    printk("向上提交设备节点信息成功\n");

    // 通过设备树节点名字解析设备树结点
    dnode = of_find_compatible_node(NULL, NULL, "hqyj,myirq");
    if (dnode == NULL)
    {
        printk("解析设备树节点信息失败\n");
        return -ENXIO;
    }
    printk("解析设备树节点信息成功\n");
    // 获取软中断号
    int i;
    for (i = 0; i < 3; i++)
    {
        key_irqno[i] = irq_of_parse_and_map(dnode, i);
        if (!key_irqno[i])
        {
            printk("解析按键的设备树节点失败\n");
            return -ENXIO;
        }
        printk("解析按键的设备树节点成功\n");
        // 注册中断
        int ret;
        ret = request_irq(key_irqno[i], key_handler, IRQF_TRIGGER_FALLING, "key", (void *)i);
        if (ret < 0)
        {
            printk("注册中断失败\n");
            return -1;
        }
        printk("注册中断成功\n");
    }

    // 解析LED设备树节点
    dnode = of_find_node_by_path("/leds");
    if (dnode == NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析设备树节点成功\n");
    // 获取GPIO编号
    gpiono = of_get_named_gpio(dnode, "led1-gpio", 0);
    if (gpiono < 0)
    {
        printk("gpio编号解析失败\n");
        return -ENXIO;
    }
    printk("解析gpio编号成功%d\n", gpiono);
    // 申请gpio编号
    int ret;
    ret = gpio_request(gpiono, NULL);
    if (ret)
    {
        printk("申请gpio编号失败\n");
        return -1;
    }
    printk("申请gpio编号成功\n");
    // 设置为输出模式
    gpio_direction_output(gpiono, 0);
    return 0;
}
static void __exit mycdev_exit(void)
{
    int i;
    for (i = 0; i < 3; i++)
        free_irq(key_irqno[i], (void *)i);

    gpio_free(gpiono);
    device_destroy(cls, MKDEV(major, i));
    // 销毁目录信息
    class_destroy(cls);
    // 字符设备驱动的注销
    unregister_chrdev(major, "MYchrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
相关推荐
Tipriest_6 分钟前
C++ 的 ranges 和 Python 的 bisect 在二分查找中的应用与实现
c++·python·算法·二分法
晨晖21 小时前
顺序查找:c语言
c语言·开发语言·算法
LYFlied1 小时前
【每日算法】LeetCode 64. 最小路径和(多维动态规划)
数据结构·算法·leetcode·动态规划
Salt_07282 小时前
DAY44 简单 CNN
python·深度学习·神经网络·算法·机器学习·计算机视觉·cnn
货拉拉技术2 小时前
AI拍货选车,开启拉货新体验
算法
MobotStone2 小时前
一夜蒸发1000亿美元后,Google用什么夺回AI王座
算法
Wang201220132 小时前
RNN和LSTM对比
人工智能·算法·架构
xueyongfu2 小时前
从Diffusion到VLA pi0(π0)
人工智能·算法·stable diffusion
永远睡不够的入2 小时前
快排(非递归)和归并的实现
数据结构·算法·深度优先
cheems95273 小时前
二叉树深搜算法练习(一)
数据结构·算法