Linux驱动开发基础__休眠与唤醒
创始人
2024-05-19 23:18:53
0

目录

1 适用场景

2 内核函数

2.1 休眠函数

2.2 唤醒函数

3 驱动框架

4 编程

 4.1 gpio_key_drv.c

4.2 button_test.c

 4.3 Makefile


1 适用场景

在前面引入中断时,我们曾经举过一个例子: 

 妈妈怎么知道卧室里小孩醒了? 
休眠-唤醒:进去房间陪小孩一起睡觉,小孩醒了会吵醒她  不累,但是妈妈干不了活了 
当应用程序必须等待某个事件发生,比如必须等待按键被按下时,可以使用“休眠-唤醒”机制: 

  • APP 调用 read 等函数试图读取数据,比如读取按键; 
  • APP 进入内核态,也就是调用驱动中的对应函数,发现有数据则复制到用户空间并马上返回; 
  • 如果 APP 在内核态,也就是在驱动程序中发现没有数据,则 APP 休眠; 
  • 当有数据时,比如当按下按键时,驱动程序的中断服务程序被调用,它会记录数据、唤醒 APP; 
  • APP 继续运行它的内核态代码,也就是驱动程序中的函数,复制数据到用户空间并马上返回。 

 驱动中有数据时,下图中红线就是 APP1 的执行过程,涉及用户态、内核态:

驱动中没有数据时,APP1 在内核态执行到 drv_read 时会休眠。所谓休眠就是把自己的状态改为非 RUNNING,这样内核的调度器就不会让它运行。当按下按键,驱动程序中的中断服务程序被调用,它会记录数据,并唤醒 APP1。所以唤醒就是把程序的状态改为 RUNNING,这样内核的调度器有合适的时间就会让它运行。当 APP1 再次运行时,就会继续执行 drv_read 中剩下的代码,把数据复制回用户空间,返回用户空间。APP1 的执行过程如下图的红色实线所示,它被分成了 2段:

 值得注意的是,上面 2 个图中红线部分都属于 APP1 的“上下文”,或者这样说:红线所涉及的代码,都是 APP1 调用的。但是按键的中断服务程序,不属于APP1 的“上下文”,这是突如其来的,当中断发生时,APP1 正在休眠呢。 
在 APP1 的“上下文”,也就是在 APP1 的执行过程中,它是可以休眠的。 
在中断的处理过程中,也就是 gpio_key_irq 的执行过程中,它不能休眠:“中断”怎么能休眠?“中断”休眠了,谁来调度其他 APP 啊? 
所以,请记住:在中断处理函数中,不能休眠,也就不能调用会导致休眠的函数。 

2 内核函数

2.1 休眠函数

参考内核源码:include\linux\wait.h。 

 比较重要的参数就是: 

 wq:waitqueue,等待队列 休眠时除了把程序状态改为非 RUNNING 之外,还要把进程/进程放入wq 中,以后中断服务程序要从 wq 中把它取出来唤醒。 没有 wq 的话,茫茫人海中,中断服务程序去哪里找到你? 

condition :这可以是一个变量,也可以是任何表达式。表示“一直等待,直到 condition
为真”。 

2.2 唤醒函数

参考内核源码:include\linux\wait.h。 

 3 驱动框架

驱动框架如下:

要休眠的线程,放在 wq 队列里,中断处理函数从 wq 队列里把它取出来唤醒。 
所以,我们要做这几件事: 

  • 初始化 wq 队列 
  • 在驱动的 read 函数中,调用 wait_event_interruptible: 它本身会判断 event 是否为 FALSE,如果为 FASLE 表示无数据,则休眠。 当从 wait_event_interruptible 返回后,把数据复制回用户空间。 
  • 在中断服务程序里: 设置 event 为 TRUE,并调用 wake_up_interruptible 唤醒线程。 

4 编程

 4.1 gpio_key_drv.c

#include #include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include struct gpio_key{int gpio;struct gpio_desc *gpiod;int flag;int irq;
} ;static struct gpio_key *gpio_keys_100ask;/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_key_class;static int g_key = 0;static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);/* 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);int err;wait_event_interruptible(gpio_key_wait, g_key);err = copy_to_user(buf, &g_key, 4);g_key = 0;return 4;
}/* 定义自己的file_operations结构体                                              */
static struct file_operations gpio_key_drv = {.owner	 = THIS_MODULE,.read    = gpio_key_drv_read,
};static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{struct gpio_key *gpio_key = dev_id;int val;val = gpiod_get_value(gpio_key->gpiod);printk("key %d %d\n", gpio_key->gpio, val);g_key = (gpio_key->gpio << 8) | val;wake_up_interruptible(&gpio_key_wait);return IRQ_HANDLED;
}/* 1. 从platform_device获得GPIO* 2. gpio=>irq* 3. request_irq*/
static int gpio_key_probe(struct platform_device *pdev)
{int err;struct device_node *node = pdev->dev.of_node;int count;int i;enum of_gpio_flags flag;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);count = of_gpio_count(node);if (!count){printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);return -1;}gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);for (i = 0; i < count; i++){gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);if (gpio_keys_100ask[i].gpio < 0){printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);return -1;}gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW;gpio_keys_100ask[i].irq  = gpio_to_irq(gpio_keys_100ask[i].gpio);}for (i = 0; i < count; i++){err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask[i]);}/* 注册file_operations 	*/major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/100ask_gpio_key */gpio_key_class = class_create(THIS_MODULE, "100ask_gpio_key_class");if (IS_ERR(gpio_key_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "100ask_gpio_key");return PTR_ERR(gpio_key_class);}device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio_key"); /* /dev/100ask_gpio_key */return 0;}static int gpio_key_remove(struct platform_device *pdev)
{//int err;struct device_node *node = pdev->dev.of_node;int count;int i;device_destroy(gpio_key_class, MKDEV(major, 0));class_destroy(gpio_key_class);unregister_chrdev(major, "100ask_gpio_key");count = of_gpio_count(node);for (i = 0; i < count; i++){free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);}kfree(gpio_keys_100ask);return 0;
}static const struct of_device_id ask100_keys[] = {{ .compatible = "100ask,gpio_key" },{ },
};/* 1. 定义platform_driver */
static struct platform_driver gpio_keys_driver = {.probe      = gpio_key_probe,.remove     = gpio_key_remove,.driver     = {.name   = "100ask_gpio_key",.of_match_table = ask100_keys,},
};/* 2. 在入口函数注册platform_driver */
static int __init gpio_key_init(void)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);err = platform_driver_register(&gpio_keys_driver); return err;
}/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*     卸载platform_driver*/
static void __exit gpio_key_exit(void)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);platform_driver_unregister(&gpio_keys_driver);
}/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(gpio_key_init);
module_exit(gpio_key_exit);MODULE_LICENSE("GPL");

4.2 button_test.c


#include 
#include 
#include 
#include 
#include 
#include /** ./button_test /dev/100ask_button0**/
int main(int argc, char **argv)
{int fd;int val;/* 1. 判断参数 */if (argc != 2) {printf("Usage: %s \n", argv[0]);return -1;}/* 2. 打开文件 */fd = open(argv[1], O_RDWR);if (fd == -1){printf("can not open file %s\n", argv[1]);return -1;}while (1){/* 3. 读文件 */read(fd, &val, 4);printf("get button : 0x%x\n", val);}close(fd);return 0;
}

 4.3 Makefile

 


# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH,          比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
#       请参考各开发板的高级用户使用手册KERN_DIR = # 板子所用内核源码的目录all:make -C $(KERN_DIR) M=`pwd` modules clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.order# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.oobj-m += gpio_key_drv.o

相关内容

热门资讯

安卓系统测试流畅度,安卓系统流... 你有没有发现,现在手机更新换代的速度简直就像坐上了火箭呢!尤其是安卓系统,每次更新都让人眼前一亮。但...
安卓系统50怎么升级,轻松迈向... 亲爱的安卓用户们,你是否也像我一样,对安卓系统的更新充满了期待?没错,就是那个让我们的手机焕然一新的...
安卓5.1.1操作系统,系统特... 你知道吗?在手机世界里,操作系统就像是个大管家,它不仅决定了手机的脸面,还掌管着手机的所有“家务事”...
手机安卓系统如果升级,体验流畅... 亲爱的手机控们,你们有没有发现,你的安卓手机最近是不是总在提醒你更新系统呢?别急,别急,今天就来给你...
安卓系统怎么禁止待机,安卓系统... 手机待机时间短,是不是让你头疼不已?别急,今天就来教你一招,让你的安卓手机告别“短命”模式,延长待机...
亿联安卓苹果系统,跨平台沟通新... 你知道吗?在科技飞速发展的今天,手机操作系统可是咱们日常生活中不可或缺的一部分。说起手机系统,亿联安...
smoothx安卓系统安装ap... 你有没有想过,为什么你的手机里总是乱糟糟的,各种app堆在一起,找起来费劲得很?别急,今天就来教你怎...
安卓系统图库在哪里,图库应用位... 你有没有发现,手机里的照片越来越多,有时候想找一张特定的照片,却像大海捞针一样困难?别急,今天就来告...
安卓7.0系统自带彩蛋,隐藏彩... 你知道吗?安卓7.0系统里竟然藏着不少小秘密,就像一颗颗隐藏的彩蛋,等着我们去发现。今天,就让我带你...
安卓系统好用的电池,好用到飞起... 你有没有发现,用安卓手机的时候,电池续航能力简直让人爱不释手啊!没错,今天咱们就来聊聊这个话题——安...
akg3003安卓系统,安卓系... 你有没有听说过AKG3003这款耳机?它最近在安卓系统用户中可是火得一塌糊涂呢!今天,就让我带你全方...
福州攻略系统和安卓,安卓用户必... 你打算去福州玩儿吗?别急,别急,让我这个福州通给你来点独家攻略,让你在福州的街头巷尾畅游无阻!这次,...
安卓游戏账号转系统,轻松实现账... 你有没有想过,有一天你的安卓游戏账号里堆满了金币、装备和等级,但是突然间,你发现这个账号已经不适合你...
安卓怎么下载原系统,安卓系统下... 你有没有发现,有时候安卓手机的系统更新后,新功能是挺多,但就是有点水土不服,用起来总觉得不如原来的系...
安卓系统和ios系统使用区别,... 你有没有发现,身边的朋友在使用手机时,总是对安卓系统和iOS系统争论不休?有时候,你甚至会被卷入这场...
安卓手机各系统名称,一网打尽各... 你有没有发现,现在安卓手机的世界里,系统名称可是五花八门,让人眼花缭乱呢?今天,就让我带你一起探索一...
如何升级安卓Q系统,系统升级指... 亲爱的手机控们,你是不是也和我一样,对安卓Q系统的新功能充满了期待呢?想要让你的手机焕然一新,体验前...
安卓系统与更新在哪,技术演进与... 你有没有发现,你的安卓手机最近是不是总在提醒你更新系统呢?别急,别急,让我来给你详细说说安卓系统与更...
安卓系统和windows系统同... 你知道吗?在科技飞速发展的今天,很多人都在同时使用安卓系统和Windows系统。这两种操作系统各有千...
安卓系统来源于微软系统,探寻安... 你知道吗?安卓系统这个我们日常生活中无处不在的小家伙,竟然有着一个不为人知的秘密——它的源头竟然是微...