驅動程式 - Linux Device Driver (LDD) - 使用範例 - C/C++ (PocketBeagle) - Workqueue



在延遲中斷處理機制上,workqueue是另一個可以使用的方式,workqueue是執行在低優先級別上,因此,可以讓Context Switch繼續執行,意味著使用者可以在workqueue裡面呼叫sleep()相關的函式,這也是跟softirq、tasklet最大的差別,因此,workqueue是相當適合應用在耗時處理的場合

使用步驟:

1. alloc_workqueue()
2. INIT_WORK()
3. queue_work()
4. destroy_workqueue()

main.c

#include <linux/init.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steward Fu");
MODULE_DESCRIPTION("Linux Driver");
 
#define BUTTON 27

struct work_struct mywork = {0};
struct workqueue_struct *myworkqueue = NULL;

static void workqueue_handler(struct work_struct *work)
{
    printk("%s\n", __func__);
}

static irqreturn_t irq_handler(int irq, void *arg)
{
    queue_work(myworkqueue, &mywork);
    return IRQ_HANDLED;
}

int ldd_init(void)
{
    myworkqueue = alloc_workqueue("myworkqueue", 0, 0);
    INIT_WORK(&mywork, workqueue_handler);
    request_irq(gpio_to_irq(BUTTON), irq_handler, IRQF_TRIGGER_RISING, "gpio_irq", NULL);
    return 0;
}
 
void ldd_exit(void)
{
    free_irq(gpio_to_irq(BUTTON), NULL);
    destroy_workqueue(myworkqueue);
}
 
module_init(ldd_init);
module_exit(ldd_exit);

ldd_init: 設定GPIO中斷以及workqueue延遲處理副程式
irq_handler: 安排一個workqueue延遲處理
workqueue_handler: 列印字串
ldd_exit: 釋放中斷資源以及刪除workqueue

完成

# workqueue_handler