当前位置: 首页 > news >正文

在服务器上部署网站怎么自己刷推广链接

在服务器上部署网站,怎么自己刷推广链接,网络营销工程师培训,重庆腊肠制作文章目录 “休眠-唤醒”机制:APP执行过程内核函数休眠函数唤醒函数 休眠与唤醒方式的按键驱动程序(stm32mp157)驱动程序框架button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “休眠-唤醒”机制: 当应用程序必须等待某个事件发生&#xff0c…

文章目录

  • “休眠-唤醒”机制:
  • APP执行过程
  • 内核函数
    • 休眠函数
    • 唤醒函数
  • 休眠与唤醒方式的按键驱动程序(stm32mp157)
    • 驱动程序框架
    • button_test.c
    • gpio_key_drv.c
    • Makefile
    • 修改设备树文件
    • 编译测试

“休眠-唤醒”机制:

当应用程序必须等待某个事件发生,比如必须等待按键被按下时,可以使用“休眠-唤醒”机制:

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

APP执行过程

在这里插入图片描述

  • 驱动中没有数据时,APP1 在内核态执行到 drv_read 时会休眠
  • 所谓休眠就是把自己的状态改为非 RUNNING,这样内核的调度器就不会让它运行。
  • 当按下按键,驱动程序中的中断服务程序被调用,它会记录数据,并唤醒 APP1。所以唤醒就是把程序的状态改为 RUNNING,这样内核的调度器有合适的时间就会让它运行。
  • 当 APP1 再次运行时,就会继续执行 drv_read 中剩下的代码,把数据复制回用户空间,返回用户空间。
  • 在 APP的read到内核态的drv_read函数中(进程上下文),也就是在 APP1 的执行过程中,它是可以休眠的
  • 在中断处理函数中(属于中断上下文),不能休眠,也就是不能调用会导致休眠的函数。

内核调度器负责维护该链表,链表里面保存的是线程,如果线程的状态为RUNNING,则会找到合适的时间就会让它运行,如果是非RUNNING,内核的调度器就不会让它运行。

内核函数

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

休眠函数

函数说明
wait_event_interruptible(wq, condition)休眠,直到 condition 为真;休眠期间是可被打断的,可以被信号打断
wait_event(wq, condition)休眠,直到 condition 为真;退出的唯一条件是 condition 为真,信号也不好使
wait_event_interruptible_timeout(wq,condition, timeout)休眠,直到 condition 为真或超时;休眠期间是可被打断的,可以被信号打断
wait_event_timeout(wq, condition,timeout)休眠,直到 condition 为真;退出的唯一条件是 condition 为真,信号也不好使

比较重要的参数就是:

  • ① wq:waitqueue,等待队列
    • 休眠时除了把程序状态改为非 RUNNING 之外,还要把进程/进程放入wq 中,以后中断服务程序要从 wq 中把它取出来唤醒。
    • 没有 wq 的话,茫茫人海中,中断服务程序去哪里找到你?
  • ② condition
    • 这可以是一个变量,也可以是任何表达式。表示“一直等待,直到condition 为真”

唤醒函数

函数说明
wake_up_interruptible(x)唤醒 x 队列中状态为“TASK_INTERRUPTIBLE”的线程,只唤醒其中的一个线程
wake_up_interruptible_nr(x, nr)唤醒 x 队列中状态为“TASK_INTERRUPTIBLE”的线程,只唤醒其中的 nr 个线程
wake_up_interruptible_all(x)唤醒 x 队列中状态为“TASK_INTERRUPTIBLE”的线程,唤醒其中的所有线程
wake_up(x)唤 醒 x 队 列 中 状 态 为 “ TASK_INTERRUPTIBLE ” 或“TASK_UNINTERRUPTIBLE”的线程,只唤醒其中的一个线程
wake_up_nr(x, nr)唤 醒 x 队 列 中 状 态 为 “ TASK_INTERRUPTIBLE ” 或“TASK_UNINTERRUPTIBLE”的线程,只唤醒其中 nr 个线程
wake_up_all(x)唤 醒 x 队 列 中 状 态 为 “ TASK_INTERRUPTIBLE ” 或“TASK_UNINTERRUPTIBLE”的线程,唤醒其中的所有线程

休眠与唤醒方式的按键驱动程序(stm32mp157)

驱动程序框架

在这里插入图片描述

要休眠的线程,放在 wq 队列里,中断处理函数从 wq 队列里把它取出来唤醒。

代码编写内容

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

button_test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>/** ./button_test /dev/100ask_button0**/
int main(int argc, char **argv)
{int fd;int val;/* 1. 判断参数 */if (argc != 2) {printf("Usage: %s <dev>\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;
}

gpio_key_drv.c

使用环形缓冲区来保存按键值,相比于全局变量,可以避免被覆盖的问题

#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>struct gpio_key{int gpio;struct gpio_desc *gpiod;int flag;int irq;
} ;static struct gpio_key *gpio_keys_first;/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_key_class;/* 环形缓冲区 */
#define BUF_LEN 128
static int g_keys[BUF_LEN];
static int r, w;//r,w是指针,指向读写的位置#define NEXT_POS(x) ((x+1) % BUF_LEN)static int is_key_buf_empty(void)
{return (r == w);//一开始rw都是0,表示空
}static int is_key_buf_full(void)
{return (r == NEXT_POS(w));//下一个写的位置等于r表示满,容量为128字节的buffer存储到127表示满了
}static void put_key(int key)
{if (!is_key_buf_full()){g_keys[w] = key;//把数据放入w位置w = NEXT_POS(w);//移动w}
}static int get_key(void)
{int key = 0;if (!is_key_buf_empty()){key = g_keys[r];//从r位置读数据r = NEXT_POS(r);//移动r}return key;
}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;int key;wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());key = get_key();err = copy_to_user(buf, &key, 4);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;int key;val = gpiod_get_value(gpio_key->gpiod);printk("key %d %d\n", gpio_key->gpio, val);key = (gpio_key->gpio << 8) | val;put_key(key);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_first = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);for (i = 0; i < count; i++){gpio_keys_first[i].gpio = of_get_gpio_flags(node, i, &flag);if (gpio_keys_first[i].gpio < 0){printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);return -1;}gpio_keys_first[i].gpiod = gpio_to_desc(gpio_keys_first[i].gpio);gpio_keys_first[i].flag = flag & OF_GPIO_ACTIVE_LOW;gpio_keys_first[i].irq  = gpio_to_irq(gpio_keys_first[i].gpio);}for (i = 0; i < count; i++){err = request_irq(gpio_keys_first[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_first[i]);}/* 注册file_operations 	*/major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/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_first[i].irq, &gpio_keys_first[i]);}kfree(gpio_keys_first);return 0;
}static const struct of_device_id my_keys[] = {{ .compatible = "first_key,gpio_key" },{ },
};/* 1. 定义platform_driver */
static struct platform_driver gpio_keys_driver = {.probe      = gpio_key_probe,.remove     = gpio_key_remove,.driver     = {.name   = "my_gpio_key",.of_match_table = my_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");

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 =   /home/book/100ask_stm32mp157_pro-sdk/Linux-5.4all:make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o button_test button_test.c
clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.order  button_test# 参考内核源码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

修改设备树文件

在这里插入图片描述
对于一个引脚要用作中断时,

  • a) 要通过 PinCtrl 把它设置为 GPIO 功能;【ST 公司对于 STM32MP157 系列芯片,GPIO 为默认模式 不需要再进行配置Pinctrl 信息】
  • b) 表明自身:是哪一个 GPIO 模块里的哪一个引脚【修改设备树】

打开内核的设备树文件:arch/arm/boot/dts/stm32mp157c-100ask-512d-lcd-v1.dts

gpio_keys_first {compatible = "first_key,gpio_key";gpios = <&gpiog 3 GPIO_ACTIVE_LOW&gpiog 2 GPIO_ACTIVE_LOW>;
};

与此同时,需要把用到引脚的节点禁用

注意,如果其他设备树文件也用到该节点,需要设置属性为disabled状态,在arch/arm/boot/dts目录下执行如下指令查找哪些设备树用到该节点

grep "&gpiog" * -nr

如果用到该节点,需要添加属性去屏蔽:

status = "disabled"; 

在这里插入图片描述

编译测试

首先要设置 ARCH、CROSS_COMPILE、PATH 这三个环境变量后,进入 ubuntu 上板子内核源码的目录,在Linux内核源码根目录下,执行如下命令即可编译 dtb 文件:

make dtbs V=1

编译好的文件在路径由DTC指定,移植设备树到开发板的共享文件夹中,先保存源文件,然后覆盖源文件,重启后会挂载新的设备树,进入该目录查看是否有新添加的设备节点

cd /sys/firmware/devicetree/base 

编译驱动程序,在Makefile文件目录下执行make指令,此时,目录下有编译好的内核模块gpio_key_drv.ko和可执行文件button_test文件移植到开发板上

确定一下烧录系统:cat /proc/mounts,查看boot分区挂载的位置,将其重新挂载在boot分区:mount /dev/mmcblk2p2 /boot,然后将共享文件夹里面的设备树文件拷贝到boot目录下,这样的话设备树文件就在boot目录下

cp /mnt/stm32mp157c-100ask-512d-lcd-v1.dtb /boot

重启后挂载,运行

insmod -f gpio_key_drv.ko // 强制安装驱动程序
ls /dev/my_gpio_key
./button_test /dev/my_gpio_key & //后台运行,此时prink函数打印的内容看不到

然后按下按键

http://www.khdw.cn/news/2859.html

相关文章:

  • 做调研有哪些网站提高搜索引擎检索效果的方法
  • 做最好的网站需要什么网络推广推广外包服务
  • 网站建设行业 前景百度网络优化
  • 17网站一起做网店睡衣批发代运营是什么意思
  • 网站建设干货图书做网络推广费用
  • wordpress不能上传图片win7系统优化
  • 导航栏网站建站网站建站设计
  • 做淘宝客优惠券网站必须是企业吗网络营销具有什么特点
  • c#web网站开发源码百度快速排名平台
  • 泰州做网站软件产品市场推广计划书
  • wordpress媒体插件长沙网站seo推广
  • 阿里巴巴网站怎么做全屏分类最近发生的热点新闻
  • 笔记本电脑做网站比较畅快常德政府网站市民留言
  • 建设网站开题报告网络营销平台有哪些
  • 罗湖网站公司数据分析师35岁以后怎么办
  • 简述营销型网站开发流程百度搜索引擎竞价排名
  • 华强北电子网站建设怀来网站seo
  • 微信商城网站搭建重庆关键词排名推广
  • 电商系统的哪家好优化课程
  • 郑州市做网站的ai智能搜索引擎
  • 甘肃网站建站系统平台中山口碑seo推广
  • 开源 网站开发框架东莞网络优化哪家好
  • 庆阳西峰北京seo百度推广
  • 网站建设及推广服务的合同范本佛山网站建设方案服务
  • 河北省建设厅网站首页枸橼酸西地那非片的作用及功效
  • 深圳创业板股票代码seo查询系统源码
  • 免费的ppt网站推荐太原网站快速排名优化
  • 网站正能量下载直接进入主页可以吗安全吗谷歌在线浏览器入口
  • 乌克兰网站建设搜索引擎营销sem包括
  • 南昌网站开发公司域名购买平台