等待队列和内核线程 在触摸屏代码中的应用
相关的头文件
#include "tpd.h"
#include <linux/interrupt.h>#include <cust_eint.h>
#include <linux/i2c.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/rtpm_prio.h>
#include <linux/wait.h>
#include <linux/time.h>
#include <linux/delay.h>
#include "tpd_custom_ft5206.h"
#include "cust_gpio_usage.h"
extern struct tpd_device *tpd;
struct i2c_client *i2c_client = NULL;
struct task_struct *thread = NULL;
static DECLARE_WAIT_QUEUE_HEAD(waiter); //定义等待队列头
static int touch_event_handler(void *unused)
{
struct touch_info cinfo, pinfo;
struct sched_param param = { .sched_priority = RTPM_PRIO_TPD };
sched_setscheduler(current, SCHED_RR, ¶m);
do
{
mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
set_current_state(TASK_INTERRUPTIBLE); //设置当前进程状态为 可中断睡眠
wait_event_interruptible(waiter,tpd_flag!=0);// 把进程加入到waiter的等待队列上面睡觉去,然后等待tpd_flag=1 发生
tpd_flag = 0;//如果发生 重置tpd_flag
set_current_state(TASK_RUNNING);//让进程进去运行态
if (tpd_touchinfo(&cinfo, &pinfo)) {
TPD_DEBUG("point_num = %d\n",point_num);
if(point_num >0) {
tpd_down(cinfo.x[0], cinfo.y[0], 1);
if(point_num>1)
{
tpd_down(cinfo.x[1], cinfo.y[1], 1);
if(point_num >2) tpd_down(cinfo.x[2], cinfo.y[2], 1);
}
input_sync(tpd->dev);
TPD_DEBUG("press --->\n");
} else {
TPD_DEBUG("release --->\n");
input_mt_sync(tpd->dev);
input_sync(tpd->dev);
}
}
}while(!kthread_should_stop());
return 0;
}
static void tpd_eint_interrupt_handler(void)// 中断处理函数 { TPD_DEBUG("TPD interrupt has been triggered\n"); tpd_flag = 1;//设置上面内核线程等待条件 wake_up_interruptible(&waiter);//唤醒在waiter上面睡觉的进程, } static int __devinit tpd_probe(struct i2c_client *client, const struct i2c_device_id *id) { int retval = TPD_OK; char data; i2c_client = client; #ifdef TPD_CLOSE_POWER_IN_SLEEP hwPowerDown(TPD_POWER_SOURCE,"TP"); hwPowerOn(TPD_POWER_SOURCE,VOL_3300,"TP"); msleep(100); #else mt_set_gpio_mode(GPIO_CTP_EN_PIN, GPIO_CTP_EN_PIN_M_GPIO); mt_set_gpio_dir(GPIO_CTP_EN_PIN, GPIO_DIR_OUT); mt_set_gpio_out(GPIO_CTP_EN_PIN, GPIO_OUT_ONE); msleep(100); mt_set_gpio_mode(GPIO_CTP_RST_PIN, GPIO_CTP_RST_PIN_M_GPIO); mt_set_gpio_dir(GPIO_CTP_RST_PIN, GPIO_DIR_OUT); mt_set_gpio_out(GPIO_CTP_RST_PIN, GPIO_OUT_ONE); #endif mt_set_gpio_mode(GPIO_CTP_EINT_PIN, GPIO_CTP_EINT_PIN_M_EINT); mt_set_gpio_dir(GPIO_CTP_EINT_PIN, GPIO_DIR_IN); mt_set_gpio_pull_enable(GPIO_CTP_EINT_PIN, GPIO_PULL_ENABLE); mt_set_gpio_pull_select(GPIO_CTP_EINT_PIN, GPIO_PULL_UP); mt65xx_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_SENSITIVE); mt65xx_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); mt65xx_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_EN, CUST_EINT_TOUCH_PANEL_POLARITY, tpd_eint_interrupt_handler, 1); // 注册中断号 中断处理程序 mt65xx_eint_unmask(CUST_EINT_TOUCH_PANEL_NUM);
从下面的注释我们可以看出,
wait_event_interruptible_timeout(wq, condition, timeout)检查条件是在执行了
wake_up() 或者变体函数看下面的函数,一旦中断发生,这个中断处理函数就要执行,唤醒等待队列中上的进程,然后才会执行这个函数
wait_event_interruptible(waiter,tpd_flag!=0);,所以有些朋友说,发生中断了,怎么我的进程没有唤醒呢? 答案就是你没执行wake_up()这个操作。
static void tpd_eint_interrupt_handler(void) { TPD_DEBUG("TPD interrupt has been triggered\n"); tpd_flag = 1; wake_up_interruptible(&waiter); }
/** * wait_event_interruptible_timeout - sleep until a condition gets true or a timeout elapses * @wq: the waitqueue to wait on * @condition: a C expression for the event to wait for * @timeout: timeout, in jiffies * * The process is put to sleep (TASK_INTERRUPTIBLE) until the * @condition evaluates to true or a signal is received. * The @condition is checked each time the waitqueue @wq is woken up. * * wake_up() has to be called after changing any variable that could * change the result of the wait condition. * * The function returns 0 if the @timeout elapsed, -ERESTARTSYS if it * was interrupted by a signal, and the remaining jiffies otherwise * if the condition evaluated to true before the timeout elapsed. */ #define wait_event_interruptible_timeout(wq, condition, timeout) \ ({ \ long __ret = timeout; \ if (!(condition)) \ __wait_event_interruptible_timeout(wq, condition, __ret); \ __ret; \ }) #define __wait_event_interruptible_exclusive(wq, condition, ret) \ do { \ DEFINE_WAIT(__wait); \ \ for (;;) { \ prepare_to_wait_exclusive(&wq, &__wait, \ TASK_INTERRUPTIBLE); \ if (condition) { \ finish_wait(&wq, &__wait); \ break; \ } \ if (!signal_pending(current)) { \ schedule(); \ continue; \ } \ ret = -ERESTARTSYS; \ abort_exclusive_wait(&wq, &__wait, \ TASK_INTERRUPTIBLE, NULL); \ break; \ } \ } while (0)