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

秦皇岛网站设计制作外贸公司代理注册

秦皇岛网站设计制作,外贸公司代理注册,如何在服务器上发布网站,介绍什么是网页设计计算机的输入设备繁多#xff0c;有按键、鼠标、键盘、触摸屏、游戏手柄等等#xff0c;Linux内核为了能够将所有的输入设备进行统一的管理#xff0c; 设计了输入子系统。为上层应用提供了统一的抽象层#xff0c;各个输入设备的驱动程序只需上报产生的输入事件即可。 下…计算机的输入设备繁多有按键、鼠标、键盘、触摸屏、游戏手柄等等Linux内核为了能够将所有的输入设备进行统一的管理 设计了输入子系统。为上层应用提供了统一的抽象层各个输入设备的驱动程序只需上报产生的输入事件即可。 下面以按键中断为例讲解输入子系统的使用。 本章配套源码和设备树插件位于“ ~/linux_driver/input_sub_system ”目录下。 1. 输入子系统简介 linux为了统一各个输入设备将输入子系统分为了Drivers驱动层、Input Core输入子系统核心层、 handlers事件处理层三部分。 Drivers主要实现对硬件设备的读写访问设置中断并将硬件产生的事件转为Input Core定义的规范提交给Handlers; Input Core起到承上启下的作用为Drivers提供了规范及接口并通知Handlers对事件进行处理; Handlers并不涉及硬件方面的具体操作是一个纯软件层包含了不同的解决方案如按键、键盘、鼠标、游戏手柄等。 最终所有输入设备的输入信息将被抽象成以下结构体 struct input_event结构体 (内核源码/include/uapi/linux/input.h) //输入事件 struct input_event{struct timeval time; //事件产生的时间__u16 type; //输入设备的类型鼠标、键盘、触摸屏__u16 code;__s16 value; } time 事件产生的时间。 type 输入设备的类型。 code 根据设备类型的不同而含义不同如果设备类型是按键code表示为按键值(如第几个按键等)。 value根据设备类型的不同而含义不同。如果设备类型是按键value表示的是松开或者按下。 本章目的是编写一个基于输入子系统和中断的按键驱动程序重点在于了解Input Core为我们提供了哪些接口并了解如何将 按键信息以事件上报。 input子系统Input Core实现代码是“ 内核源码/drivers/input/input.c ”以及“ 内核源码/include/linux/input.h ”两个文件 为我们提供了注册输入子系统的API通过操作这些API就可以实现输入事件的注册、初始化、上报、注销等等工作。 下面我们介绍输入子系统常用的API接口及数据结构。 1.1. input_dev结构体 在输入子系统中input_dev代表一个具体的输入设备后面将会根据具体的设备来初始化这个结构体结构体成员介绍如下 (input_dev参数很多有些不需要我们手动配置所以这里只列出和介绍常用的参数完整内容位于input.h文件)。 input_dev结构体 (内核源码/include/linux/input.h) struct input_dev {const char *name; //提供给用户的输入设备的名称const char *phys; //提供给编程者的设备节点的名称const char *uniq; //指定唯一的ID号struct input_id id; //输入设备标识IDunsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; //指定设备支持的事件类型unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; //记录支持的键值unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; //记录支持的相对坐标位图unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; //记录支持的绝对坐标位图/*----------以下结构体成员省略----------------*/ }; 结构体成员中最重要的是 evbit、keybit、relbit 等数组这些数组设置了设备输入事件的类型和键值。 evbit:用于指定支持的事件类型这要根据实际输入设备能够产生的事件来选择可选选项如下所示。 输入子系统事件类型 (内核源码/include/uapi/linux/input-event-codes.h) #define EV_SYN 0x00 //同步事件 #define EV_KEY 0x01 //用于描述键盘、按钮或其他类似按键的设备。 #define EV_REL 0x02 //用于描述相对位置变化例如鼠标移动 #define EV_ABS 0x03 //用于描述绝对位置变化例如触摸屏的触点坐标 #define EV_MSC 0x04 //其他事件类型 #define EV_SW 0x05 //用于描述二进制开关类型的设备例如拨码开关。 #define EV_LED 0x11 #define EV_SND 0x12 #define EV_REP 0x14 #define EV_FF 0x15 #define EV_PWR 0x16 #define EV_FF_STATUS 0x17 #define EV_MAX 0x1f #define EV_CNT (EV_MAX1) 上面代码中前几个宏定义较为常用的输入事件类型介绍如代码后面所示。 完整的介绍可以参考内核源码目录下的“ 内核源码/Documentation/input/event-codes.rst ”内核文档。 很明显我们这章节要使用的按键的事件类型应该使用 EV_KEY 。 keybit记录支持的键值“键值”在程序中用于区分不同的按键可选“键值”如下所示。 输入子系统—按键键值 (内核源码/include/uapi/linux/input-event-codes.h) #define KEY_RESERVED 0 #define KEY_ESC 1 #define KEY_1 2 #define KEY_2 3 #define KEY_3 4 #define KEY_4 5 /*-----------以下内容省略-------------*/ 可以看出“键值”就是一些数字。只要实际设备与按键对应即可。例如本章的按键可以使用KEY_1、也可以使用KEY_4等。 relbit、absbit这两个参数和上面的keybit都和参数evbit有关如果evbit中只选择了EV_KEY 那么我们就不需要设置relbit相对坐标和absbit绝对坐标以及后面省略成员的内容。这些内容使用到时再具体介绍。 使用不同的输入事件类型需要设备不同的 总之input_dev结构体成员很多但是对应到一个具体的输入设备只需要设置自己用到的其中一两个属性。 1.2. input_dev结构体的申请和释放 一个input_dev结构体代表了一个输入设备它实际会占输入子系统的一个次设备号。 input子系统为我们提供了申请和释放input_dev结构体的函数。 由于input_dev结构体的成员很多初始化过程也相对麻烦一般都使用input子系统为我们提供的接口函数来 申请和释放input_dev结构体如下所示。 input_dev申请函数 (内核源码/drivers/input/input.c) struct input_dev *input_allocate_device(void) {static atomic_t input_no ATOMIC_INIT(-1);struct input_dev *dev;dev kzalloc(sizeof(*dev), GFP_KERNEL); //动态内存申请if (dev) {dev-dev.type input_dev_type;dev-dev.class input_class; //dev-dev为struct device类型结构体device_initialize(dev-dev); //初始化dev-dev结构体内部成员mutex_init(dev-mutex); //初始化互斥锁spin_lock_init(dev-event_lock); //初始化自旋锁timer_setup(dev-timer, NULL, 0); //初始化定时器INIT_LIST_HEAD(dev-h_list); //初始化handle链表节点INIT_LIST_HEAD(dev-node); //初始化输入设备链表节点dev_set_name(dev-dev, input%lu,(unsigned long)atomic_inc_return(input_no)); //设置设备名称__module_get(THIS_MODULE);}return dev; } EXPORT_SYMBOL(input_allocate_device); 我们只需要知道如何调用这个函数来申请input_dev即可想要更深入学习的同学们可以尝试去分析整个输入子系统的实现源码 对于输入子系统的源码分析就可以写一篇很长的文章了这里并不展开详细的源码分析。 input_dev释放函数 (内核源码/drivers/input/input.c) void input_free_device(struct input_dev *dev) 申请和释放函数接口比较简单。申请函数input_allocate_device执行成功后会返回申请得到的input_dev结构体的地址 如果失败返回NULL。释放函数input_free_device只有一个参数dev用于指定要释放的input_dev结构体。 1.3. 注册和注销input_dev结构体 input_dev申请成功后我们需要根据自己的实际输入设备配置input_dev结构体具体配置在实验代码编写部分会详细说明 配置完成后还要使用注册和注销函数将input_dev注册到输入子系统。注册和注销函数如下 input_dev注册函数(内核源码/drivers/input/input.c) int input_register_device(struct input_dev *dev) 参数 devstruct input_dev类型指针  返回值 成功 0 失败 返回非0值 input_register_device函数将输入设备input_dev注册到输入子系统的核心层。 该函数使用需要注意以下几点 使用该函数注册的input_dev必须是使用input_allocate_device函数申请得到的。 注册之前需要根据实际输入设备配置好input_dev结构体。 如果注册失败必须调用input_free_device函数释放input_dev结构体。 如果注册成功在函数退出时只需要使用input_unregister_device函数注销input_dev结构体不需要再调用 input_free_device函数释放input_dev结构体。 input_dev注销函数 (内核源码/drivers/input/input.c) void input_unregister_device(struct input_dev *dev) input_unregister_device是注销函数输入子系统的资源是有限的不使用是应当注销。 调用input_unregister_device注销函数之后就不必调用input_free_device函数释放input_dev。 1.4. 上报事件函数和上报结束函数 以按键为例按键按下后需要使用上报函数向输入子系统核心层上报按键事件并且上报后还要发送上报结束信息。函数定义如下所示。 通用的上报事件函数 (内核源码include/linux/input.h) void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); 参数 dev指定输入设备input_dev结构体。 type事件类型。我们在根据实际输入设备配置input_dev结构体时会设置input_dev- evbit参数 用于设置输入设备能够产生的事件类型可能是多个。上报事件时要从“能够产生”的这些事件类型中选择。 code编码。以按键为例按键的编码就是我们设置的按键键值。 value指定事件的值。 返回值 无 上报按键事件及发送上报结束事件 (内核源码include/linux/input.h): static inline void input_sync(struct input_dev *dev) {input_event(dev, EV_SYN, SYN_REPORT, 0); }static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) {input_event(dev, EV_KEY, code, !!value); } input子系统为不同的输入事件函数提供了不同的函数接口这些函数接口只是对input_event函数进行简单的封装 具体的参数参照input_event函数。input_report_key用于上报按键事件input_sync用于发送同步信号表示上报结束。 2. 输入子系统实验 本小节以按键为例介绍输入子系统的具体使用方法。本实验在上一章“中断实验”基础上完成。结合源码介绍如下。 2.1. 设备树插件实现 设备树插件与上一章的“按键中断实验”使用的设备树插件几乎相同我们只需要将中断类型修改为“上升和下降沿触发”。 修改部分如下所示。 /dts-v1/; /plugin/; #include ../imx6ul-pinfunc.h #include dt-bindings/interrupt-controller/irq.h #include dt-bindings/gpio/gpio.h/ {fragment0 {target-path /;__overlay__ {button_interrupt {compatible button_interrupt;pinctrl-names default;pinctrl-0 pinctrl_button;button_gpio gpio5 1 GPIO_ACTIVE_LOW;status okay;interrupt-parent gpio5;interrupts 1 IRQ_TYPE_EDGE_BOTH; //设备树修改内容将上升沿触发修改为双边沿触发};};};fragment1 {target iomuxc;__overlay__ {pinctrl_button: buttongrp {fsl,pins MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10b0;};};}; }; 修改内容很简单只是将原来中断的触发方式修改为双边沿触发其他的设备树内容不变。 2.2. 驱动程序实现 2.2.1. 驱动入口函数 驱动入口函数如下所示。 static int __init button_driver_init(void) {int error;printk(KERN_ERR button_driver_init \n);/*-----------第一部分-------------*//*获取按键 设备树节点*/button_device_node of_find_node_by_path(/button_interrupt);if (NULL button_device_node){printk(KERN_ERR of_find_node_by_path error!);return -1;}/*获取按键使用的GPIO*/button_GPIO_number of_get_named_gpio(button_device_node, button_gpio, 0);if (0 button_GPIO_number){printk(KERN_ERRof_get_named_gpio error);return -1;}/*申请GPIO , 记得释放*/error gpio_request(button_GPIO_number, button_gpio);if (error 0){printk(KERN_ERR gpio_request error);gpio_free(button_GPIO_number);return -1;}error gpio_direction_input(button_GPIO_number); //设置引脚为输入模式/*获取中断号*/interrupt_number irq_of_parse_and_map(button_device_node, 0);printk(KERN_ERR \n interrupt_number %d \n, interrupt_number);/*申请中断, 记得释放*/error request_irq(interrupt_number, button_irq_hander, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, button_interrupt, NULL);if (error ! 0){printk(KERN_ERR request_irq error);gpio_free(button_GPIO_number);free_irq(interrupt_number, NULL);return -1;}/*-----------第二部分-------------*//*申请输入子系统结构体*/button_input_dev input_allocate_device();if (NULL button_input_dev){printk(KERN_ERR input_allocate_device error);return -1;}button_input_dev-name BUTTON_NAME;/*-----------第三部分-------------*//*设置要使用的输入事件类型*/button_input_dev-evbit[0] BIT_MASK(EV_KEY);input_set_capability(button_input_dev, EV_KEY, KEY_1); //标记设备能够触发的事件/*-----------第四部分-------------*//*注册输入设备*/error input_register_device(button_input_dev);if (0 ! error){printk(KERN_ERR input_register_device error);gpio_free(button_GPIO_number);free_irq(interrupt_number, NULL);input_unregister_device(button_input_dev);return -1;}return 0; } 驱动入口函数完成基本的初始化工作结合代码各部分介绍如下 第9-49行这部分和“中断实验”相同依次执行获取设备树节点、获取GPIO、申请GPIO、获取中断号、申请中断 需要注意的是这里中断类型为“上升和下降沿触发”。 第50-58行申请输入子系统结构体申请得到的input_dev结构体代表了一个输入设备 下面要根据实际的输入设备设置这个结构体。 第62行设置输入事件类型。input_dev参数很多其中最主要的是事件类型和事件对应的code。 evbit每一位代表了一种事件类型为1则表示支持0表示不支持。例如我们这里要支持“按键”事件 那么就要将EV_KEY等于0x01位置1。内核提供了帮助宏BIT_MASK帮助我们开启某一“事件”。 第63行设置支持的事件类型之后还要设置与之对应的“事件值”内核文档中称为code。以按键为例就是为按键选择键值 (在程序中通过键值区分不同的按键)input_dev-keybit参数用于选择键值例如在驱动中有6个按键那么就要使能6个键值 同样input_dev-keybit每一位代表一个键值我们可以直接设置某一位使能对应的键值 不过内核提供了很多帮助宏或函数帮助我们设置键值也可用于设置其他类型事件的code 我们在程序中使用的是input_set_capability函数。 第67-75行注册输入设备。注册成功后输入设备被添加到输入子系统内核层系统能够接受来自该设备的输入事件。 需要注意的是如果注册失败需要注销之前申请的资源然后退出 input_set_capability函数原型如下 input_set_capability函数 (内核源码/drivers/input/input.c) void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code) {switch (type) {case EV_KEY:__set_bit(code, dev-keybit);break;case EV_REL:__set_bit(code, dev-relbit);break;case EV_ABS:input_alloc_absinfo(dev);if (!dev-absinfo)return;__set_bit(code, dev-absbit);break;case EV_MSC:__set_bit(code, dev-mscbit);break;case EV_SW:__set_bit(code, dev-swbit);break;case EV_LED:__set_bit(code, dev-ledbit);break;case EV_SND:__set_bit(code, dev-sndbit);break;case EV_FF:__set_bit(code, dev-ffbit);break;case EV_PWR:/* do nothing */break;default:pr_err(input_set_capability: unknown type %u (code %u)\n,type, code);dump_stack();return;}__set_bit(type, dev-evbit); } 参数 dev指定要设置的input_dev结构体也就是要设置的输入设备 type设置输入类型可以看到函数实现中根据type设置不同的input_dev结构体参数。例如type EV_KEY 那么设置的是input_dev-keybit也就是键值。 code不同类型的输入信号含义不同如果是按键则表示的是要设置的按键的键值。 返回值 无 2.2.2. 驱动出口函数 出口函数主要完成驱动退出前的清理工作很简单代码如下 static void __exit button_driver_exit(void) {pr_info(button_driver_exit\n);/*释放申请的引脚,和中断*/gpio_free(button_GPIO_number);free_irq(interrupt_number, NULL);/*释放输入子系统相关内容*/input_unregister_device(button_input_dev); } 第6-7行释放申请的引脚和中断 第10行释放申请的输入子系统 2.2.3. 中断服务函数 中断服务函数中我们读取按键输入引脚的状态判断按键是按下还是松开。代码如下所示。 static irqreturn_t button_irq_hander(int irq, void *dev_id) {int button_satus 0;/*读取按键引脚的电平根据读取得到的结果输入按键状态*/button_satus gpio_get_value(button_GPIO_number);if(0 button_satus){input_report_key(button_input_dev, KEY_1, 0);input_sync(button_input_dev);}else{input_report_key(button_input_dev, KEY_1, 1);input_sync(button_input_dev);}return IRQ_HANDLED; } 第7行读取按键对应引脚的电平。 第8-18行根据按键引脚状态向系统上报按键事件。 2.3. 测试应用程序实现 测试应用程序中读取按键键值打印按键状态。具体代码如下所示。 struct input_event button_input_event;int main(int argc, char *argv[]) {int error -20;/*打开文件*/int fd open(/dev/input/event1, O_RDONLY);if (fd 0){printf(open file : /dev/input/event1 error!\n);return -1;}printf(wait button down... \n);printf(wait button down... \n);do{/*读取按键状态*/error read(fd, button_input_event, sizeof(button_input_event));if (error 0){printf(read file error! \n);}/*判断并打印按键状态*/if((button_input_event.type 1) (button_input_event.code 2)){if(button_input_event.value 0){printf(button up\n);}else if(button_input_event.value 1){printf(button down\n);}}} while (1);printf(button Down !\n);/*关闭文件*/error close(fd);if (error 0){printf(close file error! \n);}return 0; } 第1行申请一个input_event类型的结构体变量如我们在本章开头前所说的所有的输入设备传递的信息都会以事件的形式上报。 第8行这里的打开的文件 /dev/input/event1 是输入子系统为我们生成的输入设备设备即我们使用的按键。 第21行读取按键信息read函数没有读取到上报输入事件则将一直等待。 第27-37行根据获取读取到的信息判断按键的状态。 测试应用程序的内容很简单基本是按照打开文件、读取状态、判断状态并打印状态。 2.4. 实验准备 在板卡上的部分GPIO可能会被系统占用在使用前请根据需要修改 /boot/uEnv.txt 文件 可注释掉某些设备树插件的加载重启系统释放相应的GPIO引脚。 如本节实验中可能在鲁班猫系统中默认使能了 KEY 的设备功能 用在了GPIO子系统。引脚被占用后设备树可能无法再加载或驱动中无法再申请对应的资源。 方法参考如下 取消 KEY 设备树插件以释放系统对应KEY资源操作如下 dtoverlay/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-button-interrupt.dtbo 如若运行代码时出现“Device or resource busy”或者运行代码卡死等等现象 请按上述情况检查并按上述步骤操作。 如出现 Permission denied 或类似字样请注意用户权限大部分操作硬件外设的功能几乎都需要root用户权限简单的解决方案是在执行语句前加入sudo或以root用户运行程序。 2.4.1. 编译设备树插件 将 linux_driver/input_sub_system/imx-fire-button-interrupt-overlay.dts 拷贝到 内核源码/arch/arm/boot/dts/overlays 目录下 并修改同级目录下的Makefile追加 imx-fire-button-interrupt.dtbo 编译选项。然后执行如下命令编译设备树插件 make ARCHarm CROSS_COMPILEarm-linux-gnueabihf- npi_v7_defconfigmake ARCHarm -j4 CROSS_COMPILEarm-linux-gnueabihf- dtbs 编译成功后生成同名的设备树插件文件(imx-fire-button-interrupt.dtbo)位于 内核源码/arch/arm/boot/dts/overlays 目录下。 2.4.2. 编译驱动程序 将 linux_driver/input_sub_system 拷贝到内核源码同级目录执行里面的MakeFile生成input_sub_system.ko。 2.4.3. 编译应用程序 将 linux_driver/input_sub_system/test_app 目录中执行里面的MakeFile生成test_app。 2.5. 下载验证 编译驱动和应用程序并拷贝到开发板这里就不再赘述如何拷贝文件了。 在加载模块之前先查看 /boot/uEnv.txt 文件是否加载了板子上原有的与按键相关设备树插件。 如果之前开启了按键相关的设备树插件记得先屏蔽掉。并添加输入子系统的设备树插件。 在上图所示代码前添加’#’以注销掉与按键相关的设备树插件并 reboot 重启开发板。 使用insmod命令加载驱动如下所示 此时会在“/dev/input”目录下生成设备节点文件。 驱动加载成功后直接运行测试应用程序命令“./test_app”.测试程序运行后等待按键按下此时按下开发板的“KEY”按键 终端会输出按键状态如下所示。
http://www.ho-use.cn/article/10824162.html

相关文章:

  • 建一个收费网站原平的旅游网站怎么做的
  • 酒店网站开发合同范本效果图设计
  • 如何制作产品网站模板下载python和c++学哪个好
  • 做网站沈阳本地wordpress大家都用什么主题
  • 做网站的回扣免费网站模版建设
  • 建站平台最便宜开发工具选项卡在哪
  • 咸宁做网站的公司那家便宜旅行网站开发
  • 班级网站建设规划书搜狗竞价
  • 做网站大概要花多少钱wordpress手机加载不出来
  • 统一管理网站系统安徽网站建设外贸
  • 深圳官网网站建设珍爱网征婚免费下载
  • 深圳南山住房和建设局网站官网微网站 文章
  • 免费网站站长查询南宁公司网站模板建站
  • 常州做的网站的公司网页系统设计
  • 模板型网站建设免费封面设计在线生成软件
  • wordpress网站是什么意思装修公司哪家产品好
  • php做网站知乎wordpress中文免费
  • 承装承修承试材料在哪个网站做文化事业建设费在哪个网站申报
  • 好看的手机网站模板活动推广朋友圈文案
  • 南宁商城网站推广公司贵阳微网站
  • 五个网站十堰市住房和城乡建设厅官方网站
  • 企业建设网站好处京润珍珠企业网站优化
  • 龙岗网站建设费用广州哪里做公司网站号
  • 水利建设相关网站网络营销策划书实施计划
  • 做网站l价格展厅搭建公司
  • 云南省建设系统网站云主机 小型网站
  • 陕西大型网站建设开发一个游戏的过程
  • 怎么建立一个网站让外国人浏览wordpress2.9
  • 站群软件北京工商注册代理公司
  • 广州seo网站推广平台天河外贸型网站建设