linux 觸控式螢幕驅動中斷下半部實現-工作佇列
工作佇列(work queue)是Linux kernel中將工作推後執行的一種機制。這種機制和BH或Tasklets不同之處在於工作佇列是把推後的工作交由一個核心執行緒去執行,因此工作佇列的優勢就在於它允許重新排程甚至睡眠。工作佇列可以把工作推後,交由一個核心執行緒去執行,也就是說,這個下半部分可以在程序上下文中執行。 這樣,通過工作佇列執行的程式碼能佔盡程序上下文的所有優勢。
工作佇列:可使用核心提供的預設的共享的預設佇列,優點是簡單易用,缺點是如果預設工作佇列的負載太多,則執行效率會很低。(工作者執行緒本質上是一個普通的核心執行緒,預設情況下,每個CPU均有一個型別為“events”的工作者執行緒
也可建立使用自己的工作者執行緒和工作佇列(使用create_workqueue建立)。(ps:使用新建工作執行緒和預設執行緒,呼叫的API部分不同)
Bcmtch15***.c 和ft5306.c觸控驅動均使用的是工作佇列實現中斷的底半部。
下面以敦泰觸控式螢幕驅動ft5306.c為例,介紹其實現過程:
1、宣告工作佇列結構體指標:static struct workqueue_struct *synaptics_wq;
2、初始化工作佇列:驅動init函式focaltech_ft5306_init中:
synaptics_wq = create_singlethread_workqueue
//create_workqueue和create_singlethread_workqueue都是建立一個工作佇列,但是差別在create_singlethread_workqueue可以指定為此工作佇列只建立一個核心執行緒(前一個函式會為每一個處理器分別建立一個核心執行緒),這樣可以節省資源,無需發揮SMP的並行處理優勢。
if (!synaptics_wq) {
printk(KERN_ERR "Could not create work queue synaptics_wq: no memory");
return -ENOMEM;}
3、 初始化一個work,並繫結其處理函式:
INIT_WORK(&ts->work, focaltech_ft5306_work_func);
// focaltech_ft5306_work_func為處理函式,ts->work(ts為觸控式螢幕結構體synaptics_rmi4)
//動態地初始化一個由work指向的工作,處理函式為func(無論是動態還是靜態建立,預設定時器初始化為0,即不進行延時排程)
//focaltech_ft5306_work_func為使用container_of實現data指標的傳遞(container_of那就是根據一個結構體變數中的一個域成員變數的指標來獲取指向整個結構體變數的指標)。
struct synaptics_rmi4 *ts = container_of(work, struct synaptics_rmi4, work);
4、使用request_irq申請中斷,繫結中斷處理函式focaltech_ft5306_irq_handler
focaltech_ft5306_probe 函式中:
if (request_irq(GPIO_TO_IRQ(ts_gpio_irq_pin), focaltech_ft5306_irq_handler,
IRQF_TRIGGER_FALLING, client->name, ts) >= 0) {
printk("Requested IRQ\n");
ts->use_irq = 1;
printk(KERN_INFO "GPIO_%d INT: %d", ts_gpio_irq_pin,
GPIO_TO_IRQ(ts_gpio_irq_pin));
/*if ((ret = set_irq_wake(client->irq, 1)) < 0) {
printk(KERN_ERR "failed to set IRQ wake: %d\n", ret);
}*/
}
5、中斷處理函式focaltech_ft5306_irq_handler中,使用queue_work(synaptics_wq, &ts->work);將工作新增到當前處理器對應的連結串列中
irqreturn_t focaltech_ft5306_irq_handler(int irq, void *dev_id)
{
struct synaptics_rmi4 *ts = dev_id;
queue_work(synaptics_wq, &ts->work);
return IRQ_HANDLED;
}
6、focaltech_ft5306_work_func函式中實現資料的上報等
使用 struct synaptics_rmi4 *ts = container_of(work,struct synaptics_rmi4, work);實現資料的傳遞
7.驅動exit函式focaltech_ft5306_exit中銷燬工作佇列:
static void __exit focaltech_ft5306_exit(void)
{
i2c_del_driver(&focaltech_ft5306_driver);
if (synaptics_wq)
destroy_workqueue(synaptics_wq);
}