除了使用中断方式读取SR501的信号以外,还有一种方式是使用内核线程,循环查询引脚的状态。
使用内核线程的框架和使用中断的框架类似,就是把中断的部分用内核线程替换掉。
(1)probe函数中,去掉中断注册代码,加入内核线程注册代码
static int sr501_probe(struct platform_device *pdev)
{
int err;
struct device_node *node = pdev->dev.of_node;
int count;
int i;
//
sr501_gpio=gpiod_get(&pdev->dev,NULL,0);
if(IS_ERR(sr501_gpio))
{
dev_err(&pdev->dev,"Fail to get GPIO for sr501\n");
return PTR_ERR(sr501_gpio);
}
gpiod_direction_input(sr501_gpio);
-irq=gpiod_to_irq(sr501_gpio);
-request_irq(irq,sr501_irq,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING,"sr501_irq",NULL);
+sr501_thread=kthread_run(sr501_detect,NULL,"sr501_thread");
+if (IS_ERR(sr501_thread))
+{
+return PTR_ERR(sr501_thread);
+}
/* 注册file_operations */
major = register_chrdev(0, "sr501_chr", &sr501_drv);
sr501_class = class_create(THIS_MODULE, "100ask_sr501_class");
if (IS_ERR(sr501_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "100ask_sr501");
gpiod_put(sr501_gpio);
return PTR_ERR(sr501_class);
}
device_create(sr501_class, NULL, MKDEV(major, 0), NULL, "sr501");
printk("%s %s line %d,major:%d\n", __FILE__, __FUNCTION__, __LINE__,major);
return 0;
}
(2)remove函数中,去掉注销中断代码,加入停止内核线程代码
static int sr501_remove(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
int i;
device_destroy(sr501_class, MKDEV(major, 0));
class_destroy(sr501_class);
unregister_chrdev(major, "sr501_chr");
-free_irq(irq,&(pdev->dev));
+kthread_stop(sr501_thread);
gpiod_put(sr501_gpio);
return 0;
}
(3)编写内核线程函数
static int sr501_detect(void *arg)
{
int val;
int pre=-1;
while(1)
{
val=gpiod_get_value(sr501_gpio);
if(val!=pre)
{
sr501_flag=0x80|val;
printk("%s %s line %d,val=%x\n", __FILE__, __FUNCTION__, __LINE__,sr501_flag);
wake_up(&sr501_wait);
pre=val;
}
//必须要有这一句,否则不可休眠
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ/5);
//没有这一句会导致不能退出线程。
if(kthread_should_stop())
{
set_current_state(TASK_RUNNING);
break;
}
}
return 0;
}
需要特别注意的有两点:
(1)使用schedule_timeout让线程进入休眠之前,一定要使用 set_current_state(TASK_INTERRUPTIBLE);函数配置线程状态,否则线程无法进入休眠。
(2)线程中一定要使用如下代码,通过程序跳出线程函数的方法来停止内核线程。
if(kthread_should_stop())
{
set_current_state(TASK_RUNNING);
break;
}
因为kthread_stop(sr501_thread);只是配置了线程的状态位,并没有真正的停止线程。