Linux 定時器+延時工作隊列+外部中斷例程

先上代碼:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/ioctl.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/workqueue.h>

#define GPIO_MAX_NUM	256
#define TIMER_TIMEOUT_VALUE	1
#define WORK_DELAY_VALUE	1
#define USE_TIMER		0
#define USE_DELAY_WORK	1

#define DEV_NAME	"data_dect"

int irq_num = 0;
int irq_gpio = 0;
int pad_sai2_rxd = 0;
struct timer_list timer;
static struct delayed_work delay_work1;
int major;
static struct class *mod_class;
struct device *mod_dev;
dev_t devt;

struct completion data_dect_completion;

//設備文件寫函數
static ssize_t data_dect_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
{

	return 0;
}


//調用read返回,就說明出現了空白的現象
static ssize_t data_dect_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    ssize_t status = 0;
    wait_for_completion_interruptible_timeout(&data_dect_completion, HZ);
    return status;
}

static long data_dect_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{

	return 0;
}

static int data_dect_open(struct inode *node, struct file *filp)
{
    nonseekable_open(node, filp);
    return 0;
}

static const struct file_operations data_dect_fops =
{
    .owner = THIS_MODULE,
    .write = data_dect_write,
    .read  = data_dect_read,
    .unlocked_ioctl = data_dect_ioctl,
    .open = data_dect_open,
};

static irqreturn_t irq_handler_func(int irq, void *dev)
{
//    printk ("this  is interrupt !kernel _lqd\n"); /*其他模塊的導出符號*/   
	schedule_delayed_work(&delay_work1, msecs_to_jiffies(WORK_DELAY_VALUE));	//啓動引腳檢測
    return IRQ_HANDLED;
} 

void timer_function(unsigned long arg)
{
//	int value = 0;
	static unsigned int value = 0;
	mod_timer(&timer, jiffies+TIMER_TIMEOUT_VALUE);
	value++;
	gpio_set_value(pad_sai2_rxd, value%2);
	return ;
	
	value = gpio_get_value(irq_gpio);
	if(value)
	{
		gpio_set_value(pad_sai2_rxd, 1);
		printk("irq_gpio status is Hig !\n");
	}
	else
	{
		gpio_set_value(pad_sai2_rxd, 0);
	}
}

//中斷裏面啓動延時工作隊列
//延時時間到時,開始執行下面的函數
static void delay_work_func(struct work_struct *work)
{
	int value = 0;
#if 0	
	static int temp_value = 0;
	temp_value++;
	gpio_set_value(pad_sai2_rxd, temp_value%2);
	schedule_delayed_work(&delay_work1, msecs_to_jiffies(WORK_DELAY_VALUE));
#endif
	value = gpio_get_value(irq_gpio);		//獲取中斷引腳電平狀態
	if(value)								//如果這個時候還是高電平,說明出現了空白
	{
		complete(&data_dect_completion);	//讓應用層的read調用返回
		printk("Data appears blank !\n");	//內核打印提示
	}
	
}

static int __init mod_init(void)
{
	int ret;
	struct device_node *dts_of_node = NULL;
	dts_of_node = of_find_node_by_name(NULL, "test-node");				//獲取設備樹對應的節點

	if(dts_of_node == NULL)
	{
		printk("Don't found test-node node !\n");
		return -1;
	}
	
	irq_gpio = of_get_named_gpio(dts_of_node, "int-gpios", 0);
	if(irq_gpio < 0)
	{
		printk("irq_gpio error !\n");
	}
	
	pad_sai2_rxd = of_get_named_gpio(dts_of_node, "pad_sai2_rxd", 0);
	if(gpio_is_valid(pad_sai2_rxd))
	{
		ret = gpio_request(pad_sai2_rxd, "pad_sai2_rxd");
		if(ret == 0)
		{
			gpio_direction_output(pad_sai2_rxd, 1);
		}
		
	}
	else
	{
		goto error1;
	}
	
	irq_num = irq_of_parse_and_map(dts_of_node, 0);								//獲取中斷號
	if(irq_num < 0)
	{
		printk("irq_of_parse_and_map fail !\n");
		goto error2;
	}
	
	ret = request_irq(irq_num, irq_handler_func, IRQF_TRIGGER_RISING, "gpio_interrupt", NULL);	//申請中斷,上升沿觸發
	if(ret < 0)
	{
		printk("request_irq fail !\n");
		goto error2;
	}
	
#if USE_TIMER
	init_timer(&timer);													//初始化定時器	
	timer.expires = jiffies+TIMER_TIMEOUT_VALUE;
	timer.function = timer_function;
	add_timer(&timer);
#endif

#if USE_DELAY_WORK
	INIT_DELAYED_WORK(&delay_work1, delay_work_func);
	schedule_delayed_work(&delay_work1, msecs_to_jiffies(WORK_DELAY_VALUE));	
#endif	

	init_completion(&data_dect_completion);								//初始化完成量
	
	//創建設備節點
	major = register_chrdev(0, DEV_NAME, &data_dect_fops);				//註冊字符設備	返回主設備號
	if(major < 0)
	{
		printk("register_chrdev fail !\n");
		goto error3;
	}
	
	mod_class = class_create(THIS_MODULE, DEV_NAME);					//創建類
	if (IS_ERR(mod_class)) {
		goto error4;
	}
	
	mod_dev = device_create(mod_class, NULL, MKDEV(major, 0), NULL, DEV_NAME);	//創建設備
	if(IS_ERR(mod_dev))
	{
		goto error5;
	}
	

	return 0; 
error5:
	class_destroy(mod_class);
error4:
	unregister_chrdev(major, DEV_NAME);		
error3:
#if USE_TIMER
	del_timer(&timer);
#endif	
#if USE_DELAY_WORK
	cancel_delayed_work_sync(&delay_work1);
#endif
error2:   
	gpio_free(pad_sai2_rxd);
error1:
	return -1;	
}
module_init(mod_init);

static void __exit mod_exit(void)
{
	unregister_chrdev(major, DEV_NAME);	
	device_destroy(mod_class, MKDEV(major, 0));
	class_destroy(mod_class);
#if USE_TIMER
	del_timer(&timer);
#endif	

#if USE_DELAY_WORK
	cancel_delayed_work_sync(&delay_work1);
#endif

	free_irq(irq_num, NULL);
	gpio_free(pad_sai2_rxd);
	printk("############### %s  %s !kernel\n", __FILE__, __func__);
}
module_exit(mod_exit);



MODULE_AUTHOR("lqd");
MODULE_LICENSE("GPL");

上面的例程,通過設備樹獲取中斷信息。通過中斷,去觸發定時器/延時工作隊列去檢測GPIO的電平

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章