• 中断的处理有几个原则:

    ① 不能嵌套;
    ② 越快越好。

    • 在处理当前中断时,即使发生了其他中断,其他中断也不会得到处理,所以中断的处理要越快越好
    • 某些中断要做的事情稍微耗时,这时可以把中断拆分为上半部、下半部

    在上半部处理紧急的事情,在上半部的处理过程中,中断是被禁止的;
    在下半部处理耗时的事情,在下半部的处理过程中,中断是使能的。

    • image.png
    • 上半部和下半部是多对一的关系
      • image.png
    • 如何使用下半部?
      • 定义 tasklet,需要使用时调用 tasklet_schedule,驱动卸载前调用 tasklet_kill
      • tasklet_schedule 只是把 tasklet 放入内核队列,它的 func 函数会在软件中断的执行过程中被调用
    • 内核相关函数
      • 定义 tasklet
        • image.png
        • state 有 2 位:

    ① bit0 表示 TASKLETSTATESCHED
    等于 1 时表示已经执行了 taskletschedule 把该 tasklet 放入队列了;tasklet_schedule 会判断该
    位,如果已经等于 1 那么它就不会再次把 tasklet 放入队列。
    ② bit1 表示 TASKLET_STATE
    RUN
    等于 1 时,表示正在运行 tasklet 中的 func 函数;函数执行完后内核会把该位清 0

    1. - count 表示该 tasklet 是否使能:等于 0 表示使能了,非 0 表示被禁止了。对于 count 0 tasklet,里面的 func 函数不会被执行
    2. - 用这 2 个宏来定义结构体
    3. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1658545/1619177584821-28759f8b-dacd-4ad5-8515-f8b88f5aa19d.png#align=left&display=inline&height=90&margin=%5Bobject%20Object%5D&name=image.png&originHeight=180&originWidth=970&size=34766&status=done&style=none&width=485)
    • 初始化 tasklet 结构体
      • image.png
      • 有多个按键,想为每个按键都定义一个tasklet_struct结构体的话,使用tasklet_init函数
    • 使能/禁止 tasklet
      • image.png
    • 调度 tasklet
      • image.png
    • kill tasklet
      • image.png
        • 修改驱动程序
    • 在中断服务程序里启动中断下半部tasklet ```c struct gpio_key{ int gpio; struct gpio_desc gpiod; int flag; int irq; struct timer_list key_timer; struct tasklet_struct tasklet; / tasklet结构体 */ } ;

    / 中断下半部的处理函数 / static void key_tasklet_func(unsigned long data) { / data ==> gpio / struct gpio_key *gpio_key = data; int val; int key;

    1. val = gpiod_get_value(gpio_key->gpiod);
    2. printk("key_tasklet_func key %d %d\n", gpio_key->gpio, val);

    }

    static irqreturn_t gpio_key_isr(int irq, void dev_id) { struct gpio_key gpio_key = dev_id; //printk(“gpio_key_isr key %d irq happened\n”, gpio_key->gpio);

    1. /* 在中断处理函数中开启中断下半部tasklet */
    2. tasklet_schedule(&gpio_key->tasklet);
    3. mod_timer(&gpio_key->key_timer, jiffies + HZ/50);
    4. return IRQ_HANDLED;

    }

    /* 1. 从platform_device获得GPIO

      1. gpio=>irq
      1. request_irq / static int gpio_key_probe(struct platform_device pdev) { int err; struct device_node *node = pdev->dev.of_node; int count; int i; enum of_gpio_flags flag;

        printk(“%s %s line %d\n”, FILE, FUNCTION, LINE);

        count = ofgpiocount(node); if (!count) { printk(“%s %s line %d, there isn’t any gpio available\n”, FILE, FUNCTION, __LINE); return -1; }

        gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL); for (i = 0; i < count; i++) {
        gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag); if (gpio_keys_100ask[i].gpio < 0) {

        1. printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);
        2. return -1;

        } gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio); gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW; gpio_keys_100ask[i].irq = gpio_to_irq(gpio_keys_100ask[i].gpio);

        setup_timer(&gpio_keys_100ask[i].key_timer, key_timer_expire, &gpio_keys_100ask[i]); gpio_keys_100ask[i].key_timer.expires = ~0; add_timer(&gpio_keys_100ask[i].key_timer);

        / 在probe函数中初始化tasklet结构体 / tasklet_init(&gpio_keys_100ask[i].tasklet, key_tasklet_func, &gpio_keys_100ask[i]); }

        for (i = 0; i < count; i++) { err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, “100ask_gpio_key”, &gpio_keys_100ask[i]); }

        / 注册file_operations / major = register_chrdev(0, “100ask_gpio_key”, &gpio_key_drv); / /dev/gpio_key /

        gpiokeyclass = classcreate(THISMODULE, “100askgpiokey_class”); if (IS_ERR(gpio_key_class)) { printk(“%s %s line %d\n”, __FILE, __FUNCTION, __LINE); unregister_chrdev(major, “100ask_gpio_key”); return PTR_ERR(gpio_key_class); }

        device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, “100ask_gpio_key”); / /dev/100ask_gpio_key /

        return 0;

    }

    static int gpio_key_remove(struct platform_device pdev) { //int err; struct device_node node = pdev->dev.of_node; int count; int i;

    1. device_destroy(gpio_key_class, MKDEV(major, 0));
    2. class_destroy(gpio_key_class);
    3. unregister_chrdev(major, "100ask_gpio_key");
    4. count = of_gpio_count(node);
    5. for (i = 0; i < count; i++)
    6. {
    7. free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);
    8. del_timer(&gpio_keys_100ask[i].key_timer);
    9. /* 在remove函数中kill掉中断下半部tasklet */
    10. tasklet_kill(&gpio_keys_100ask[i].tasklet);
    11. }
    12. kfree(gpio_keys_100ask);
    13. return 0;

    } ```