Linux驱动-中断-工作队列

设备树内:

 驱动

/*
 * @Author: your topeet
 * @Description: 中断下文之tasklet,实现按键打印0-99
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>

#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
//定义结构体表示我们的节点
struct device_node *test_device_node;
//定义tasklet结构体
struct tasklet_struct key_test;
//要申请的中断号
int irq;
//GPIO 编号
int gpio_nu;

/**
 * @description: tasklet 的处理函数
 * @param {unsignedlong} data:要传递给 func 函数的参数
 * @return {*}无
 */
void test(unsigned long data)
{
	int i = data;
	printk("i is %d \n", i);
	while (i--)
		printk("test_key is %d \n", i);
}

/**
 * @description: 中断处理函数test_key
 * @param {int} irq :要申请的中断号
 * @param {void} *args :
 * @return {*}IRQ_HANDLED
 */
irqreturn_t test_key(int irq, void *args)
{
	printk("start\n");
	tasklet_schedule(&key_test);
	printk("end\n");
	return IRQ_RETVAL(IRQ_HANDLED);
}

/**
 * @brief beep_probe : 与设备信息层(设备树)匹配成功后自动执行此函数,
 * @param inode : 文件索引
 * @param file  : 文件
 * @return 成功返回 0           
*/
int beep_probe(struct platform_device *pdev)
{ //匹配成功以后,进入到probe函数
	int ret = 0;

	printk("beep_probe\n");
	//of_find_node_by_path函数通过路径查找节点,/test_key是设备树下的节点路径
	test_device_node = of_find_node_by_path("/test_key");
	if (test_device_node == NULL)
	{
		printk("of_find_node_by_path is error \n");
		return -1;
	}
	//of_get_named_gpio函数获取 GPIO 编号
		gpio_nu = of_get_named_gpio(test_device_node, "gpios", 0);
	if (gpio_nu < 0)
	{
		printk("of_get_namd_gpio is error \n");
		return -1;
	}
	//设置GPIO为输入模式
	gpio_direction_input(gpio_nu);
	//获取GPIO对应的中断号
	//irq = gpio_to_irq(gpio_nu);
	irq = irq_of_parse_and_map(test_device_node, 0);
	printk("irq is %d \n", irq);
	/*申请中断,irq:中断号名字  
     test_key:中断处理函数
     IRQF_TRIGGER_RISING:中断标志,意为上升沿触发
     "test_key":中断的名字
     */
		ret = request_irq(irq, test_key, IRQF_TRIGGER_RISING, "test_key", NULL);
	if (ret < 0)
	{
		printk("request_irq is error \n");
		return -1;
	}
	/* 初始化 tasklet */
	tasklet_init(&key_test, test, 100);
	return 0;
}

int beep_remove(struct platform_device *pdev)
{
	printk("beep_remove\n");
	return 0;
}
const struct platform_device_id beep_idtable = {
	.name = "keys",
};
const struct of_device_id of_match_table_test[] = {
	{.compatible = "test1234"},
	{},
};
struct platform_driver beep_driver = {
	//3. 在beep_driver结构体中完成了beep_probe和beep_remove
	.probe = beep_probe,
	.remove = beep_remove,
	.driver = {
		.owner = THIS_MODULE,
		.name = "beep_test",
		.of_match_table = of_match_table_test},
	//4 .id_table的优先级要比driver.name的优先级要高,优先与.id_table进行匹配
	.id_table = &beep_idtable};

static int beep_driver_init(void)
{
	//1.我们看驱动文件要从init函数开始看
	int ret = 0;
	//2. 在init函数里面注册了platform_driver
	ret = platform_driver_register(&beep_driver);
	if (ret < 0)
	{
		printk("platform_driver_register error \n");
	}
	printk("platform_driver_register ok \n");

	return 0;
}

static void beep_driver_exit(void)
{

	free_irq(irq, NULL);
	tasklet_kill(&key_test);
	platform_driver_unregister(&beep_driver);
	printk("gooodbye! \n");
}
module_init(beep_driver_init);
module_exit(beep_driver_exit);
MODULE_LICENSE("GPL");

Makefile

obj-m += driver.o  #先写生成的中间文件的名字是什么,-m的意思是把我们的驱动编译成模块
KDIR:=/home/topeet/driver/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga/
PWD?=$(shell pwd)   #获取当前目录的变量
all:
	make -C $(KDIR) M=$(PWD) modules  #make会进入内核源码的路径,然后把当前路径下的代码编译成模块

工作队列

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/workqueue.h>
//定义结构体表示我们的节点
struct device_node *test_device_node;
struct property *test_node_property;
//struct tasklet_struct key_test;
// 定义工作结构体
struct work_struct key_test;
//要申请的中断号
int irq;
//GPIO 编号
int gpio_nu;
/**
 * @description: 工作队列的处理函数
 * @param {unsignedlong} data:要传递给 func 函数的参数
 * @return {*}无
 */
void test(struct work_struct * data)
{
	int i = 100;
	printk("i is %d \n", i);
	while (i--)
		printk("test_key is %d \n", i);
}
/**
 * @description: 中断处理函数test_key
 * @param {int} irq :要申请的中断号
 * @param {void} *args :
 * @return {*}IRQ_HANDLED
 */
irqreturn_t test_key(int irq, void *args)
{
	printk("start\n");
	//tasklet_schedule(&key_test);
	schedule_work(&key_test);
	printk("end\n");
	return IRQ_HANDLED;
}
/**
 * @brief beep_probe : 与设备信息层(设备树)匹配成功后自动执行此函数,
 * @param inode : 文件索引
 * @param file  : 文件
 * @return 成功返回 0           
*/
int beep_probe(struct platform_device *pdev)
{
	int ret = 0;

	//进入probe函数
	printk("beep_probe\n");
	//of_find_node_by_path函数通过路径查找节点,/test_key是设备树下的节点路径
	test_device_node = of_find_node_by_path("/test_key");
	if (test_device_node == NULL)
	{
		printk("of_find_node_by_path is error \n");
		return -1;
	}
	//of_get_named_gpio函数获取 GPIO 编号
	gpio_nu = of_get_named_gpio(test_device_node, "gpios", 0);

	if (gpio_nu < 0)
	{
		printk("of_get_namd_gpio is error \n");
		return -1;
	}
	//获取GPIO对应的中断号
	//irq = gpio_to_irq(gpio_nu);
	gpio_direction_input(gpio_nu);

	//获得中断号
	//irq = gpio_to_irq(gpio_nu);
	irq = irq_of_parse_and_map(test_device_node, 0);
	printk("irq is %d \n", irq);
	/*申请中断,irq:中断号名字  
     test_key:中断处理函数
     IRQF_TRIGGER_RISING:中断标志,意为上升沿触发
     "test_key":中断的名字
     */
	ret = request_irq(irq, test_key, IRQF_TRIGGER_RISING, "test_key", NULL);
	if (ret < 0)
	{
		printk("request_irq is error \n");
		return -1;
	}
	//初始化工作队列
	//tasklet_init(&key_test,test, 100);
	//INIT_WORK 宏来初始化工作
	INIT_WORK(&key_test, test);
	return 0;
}

int beep_remove(struct platform_device *pdev)
{
	printk("beep_remove\n");
	return 0;
}
const struct platform_device_id beep_idtable = {
	.name = "keys",
};
const struct of_device_id of_match_table_test[] = {
	{.compatible = "test1234"},
	{},
};
struct platform_driver beep_driver = {
	//3. 在beep_driver结构体中完成了beep_probe和beep_remove
	.probe = beep_probe,
	.remove = beep_remove,
	.driver = {
		.owner = THIS_MODULE,
		.name = "beep_test",
		.of_match_table = of_match_table_test},
	//4 .id_table的优先级要比driver.name的优先级要高,优先与.id_table进行匹配
	.id_table = &beep_idtable};

static int beep_driver_init(void)
{
	// 1.我们看驱动文件要从init函数开始看
	int ret = 0;
	//2. 在init函数里面注册了platform_driver
	ret = platform_driver_register(&beep_driver);
	if (ret < 0)
	{
		printk("platform_driver_register error \n");
	}
	printk("platform_driver_register ok \n");

	return 0;
}

static void beep_driver_exit(void)
{

	free_irq(irq, NULL);
	//tasklet_kill(&key_test);
	platform_driver_unregister(&beep_driver);
	printk("gooodbye! \n");
}
module_init(beep_driver_init);
module_exit(beep_driver_exit);

MODULE_LICENSE("GPL");

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值