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

网路营销网站策划书营销网站建设的重要性

网路营销网站策划书,营销网站建设的重要性,提交网站的入口地址,广州海珠网站开发定制Linux设备驱动之gpio-keys 前两个章节介绍了Linux字符设备和platform设备的注册#xff0c;他们都是比较基础的#xff0c;让大家理解Linux内核的设备驱动是如何注册、使用的。但在工作中#xff0c;个人认为完全手写一个字符设备驱动的机会比较少#xff0c;更多的都是基…Linux设备驱动之gpio-keys 前两个章节介绍了Linux字符设备和platform设备的注册他们都是比较基础的让大家理解Linux内核的设备驱动是如何注册、使用的。但在工作中个人认为完全手写一个字符设备驱动的机会比较少更多的都是基于前人的代码修修补补过三年。在内核驱动中更多的会基于platform设备进行具体设备驱动的注册与使用下面以内核原生的gpio-keys为例向大家介绍一个简单的按键驱动是如何配置、工作的。 dts配置 前面有简单的介绍设备树用于描述板端硬件信息配合驱动进行使用的Linux内核原生的gpio-keys驱动支持的dts如下 gpio-keys {compatible gpio-keys; /* 用于匹配内核gpio-keys驱动 */autorepeat; /* 标记是否自动重复该按键想想常按的情况 */up {label GPIO Key UP; /* 按键的标签 */linux,code 103; /* 按键的键值理解为键盘上的字母类 */gpios gpio1 0 1; /* 使用的是哪个gpio */};down {label GPIO Key DOWN;linux,code 108;interrupts 1 IRQ_TYPE_LEVEL_HIGH 7; /* 中断配置 */};};上面介绍到的dts配置最后在驱动端都会进行解析使用那么驱动又具体是如何使用的呢继续。 gpio-keys的platform驱动 Linux内核基本都可以看到类似以下的代码 [drivers/input/keyboard/gpio_keys.c]/* 设备驱动匹配信息 */ static const struct of_device_id gpio_keys_of_match[] {{ .compatible gpio-keys, },{ }, }; MODULE_DEVICE_TABLE(of, gpio_keys_of_match);static struct platform_driver gpio_keys_device_driver {.probe gpio_keys_probe, /* platform设备驱动匹配了则调用probe函数 */.shutdown gpio_keys_shutdown,.driver {.name gpio-keys,.pm gpio_keys_pm_ops,.of_match_table gpio_keys_of_match,.dev_groups gpio_keys_groups,} };static int __init gpio_keys_init(void) {/* 注册platform driver */return platform_driver_register(gpio_keys_device_driver); }static void __exit gpio_keys_exit(void) {platform_driver_unregister(gpio_keys_device_driver); }/* late_initcall与modeule_init的宏作用一样* 都是将函数添加到驱动段方便开机启动加载驱动* late_initcall与modeule_init的差异是加载* 的优先级不一致*/ late_initcall(gpio_keys_init); module_exit(gpio_keys_exit);在platform和设备树章节已经介绍当设备驱动匹配时将会调用到probe函数。下面看看gpio-keys的probe是怎样获取dts信息的。PSdts是怎么解析的platform device是什么时候注册的后面其他章节我们再进行介绍。 /** Handlers for alternative sources of platform_data*//** Translate properties into platform_data*/ static struct gpio_keys_platform_data * gpio_keys_get_devtree_pdata(struct device *dev) {struct gpio_keys_platform_data *pdata;struct gpio_keys_button *button;struct fwnode_handle *child;int nbuttons;/* 查看当前的gpio-keys节点有多少个子节点每个节点代表一个按键 */nbuttons device_get_child_node_count(dev);if (nbuttons 0)return ERR_PTR(-ENODEV);pdata devm_kzalloc(dev,sizeof(*pdata) nbuttons * sizeof(*button),GFP_KERNEL);if (!pdata)return ERR_PTR(-ENOMEM);button (struct gpio_keys_button *)(pdata 1);pdata-buttons button;pdata-nbuttons nbuttons;/* 是否自动重复 */pdata-rep device_property_read_bool(dev, autorepeat);/* 按键的标签 */device_property_read_string(dev, label, pdata-name);device_for_each_child_node(dev, child) {if (is_of_node(child))button-irq irq_of_parse_and_map(to_of_node(child), 0);/* 按键码值 */if (fwnode_property_read_u32(child, linux,code,button-code)) {dev_err(dev, Button without keycode\n);fwnode_handle_put(child);return ERR_PTR(-EINVAL);}fwnode_property_read_string(child, label, button-desc);/* 输入的类型一般设置为KEY */if (fwnode_property_read_u32(child, linux,input-type,button-type))button-type EV_KEY;/* 该按键是否设置为唤醒源 */button-wakeup fwnode_property_read_bool(child, wakeup-source) ||/* legacy name */fwnode_property_read_bool(child, gpio-key,wakeup);/* 唤醒的状态 */fwnode_property_read_u32(child, wakeup-event-action,button-wakeup_event_action);/* 是否可休眠 */button-can_disable fwnode_property_read_bool(child, linux,can-disable);/* 按键去抖配置 */if (fwnode_property_read_u32(child, debounce-interval,button-debounce_interval))button-debounce_interval 5;button;}return pdata; }在上面的代码可以看到就是一个解析dts的操作gpio_keys_get_devtree_pdata()将会进行以下操作 确认gpio-keys节点存在多少个子节点每个子节点代表一种按键功能获取”autorepeat“字段的信息赋值到pdata-rep这个变量决定着是否允许重复发送事件获取各button的中断号、事件代码code、label、输入的类型、唤醒等信息 之后驱动会依据这些信息进行按键驱动的适配以及操作。下面通过gpio-keys驱动学习Linux input子系统。 input子系统 Linux input子系统是linux内核用于管理各种输入设备的部分内核将给用户导出一套固定的硬件无关的input API供用户空间程序使用。 input系统分为三块input core、input drivers和event handles。数据传输从底层硬件到input driver再经过input core到event handles最后到达用户空间。 input core input子系统的core代码主要是input.c该文件集成模块模块的注册函数实现如下 static int __init input_init(void) {int err;/* 注册input类 */err class_register(input_class);if (err) {pr_err(unable to register input_dev class\n);return err;}/* 在/proc创建 bus/input/devices handlers */err input_proc_init();if (err)goto fail1;/* 注册input字符设备 */err register_chrdev_region(MKDEV(INPUT_MAJOR, 0),INPUT_MAX_CHAR_DEVICES, input);if (err) {pr_err(unable to register char major %d, INPUT_MAJOR);goto fail2;}return 0;fail2: input_proc_exit();fail1: class_unregister(input_class);return err; }在input.c是input core的核心文件input core主要是承上启下为input drivers提供输入设备注册和操作接口如input_register_device()函数通知event handles对事件进行处理在/proc下产生相应的设备信息。input core将会负责将input drivers和event handles联通具体是如何完成这个操作的呢继续看input drivers和event handles。 相关结构体 [linux/input.h] /** The event structure itself*/struct input_event {struct timeval time; /* 输入事件时间 */__u16 type; /* 类型 */__u16 code; /* 事件代码 [linux/input-event-codes.h] */__s32 value; /* 事件值(当type为EV_KEY时value0表示按键抬起1表示按键按下) */ };[linux/input-event-codes.h] /** Event types*/#define EV_SYN 0x00 /* 所有input设备都具备的同步事件主要是与client同步事件队列 */ #define EV_KEY 0x01 /* 按键 */ #define EV_REL 0x02 /* 鼠标事件 相对坐标 */ #define EV_ABS 0x03 /* 手写板事件 绝对坐标 */ #define EV_MSC 0x04 /* 其他类型 */ #define EV_SW 0x05 /* 开关状态事件 */ #define EV_LED 0x11 /* LED事件 */ #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)gpio_keys_probe() 继续回到gpio_keys_probe()函数从dts中获取到button信息之后将会通过调用devm_input_allocate_device()([input.c])函数创建input_dev设备。接着是通过gpio_keys_setup_key()函数为各个button申请相应的GPIO、中断资源等。最后通过input_register_device()函数注册input设备。至此可以看到input drivers注册完成。 input handle input handle的相关操作在evdev.c实现该文件恰好自己构成一个模块先分析模块的注册函数注册函数只是调用了input_register_handler()([input.c])该函数主要是为系统中的输入设备注册一个新的输入处理程序并将其附加到与该处理程序兼容的所有输入设备上。该模块将在input dev注册时将会通过input core完成与input dev完成相应的connect当event发生时又将会处理相应的event事件并上报。 input core、input drivers和event handles三块的简单介绍如上下面我们将带着问题去阅读代码进一步了解Linux input子系统。 FAQ input core是如何知道当前有多少输入设备而这些输入设备又分别是支持什么类型的事件 在介绍上面的input drivers的时候就有提到在driver的probe函数中将会通过input_register_device()函数注册input device下面来分析一下该函数的实现。 int input_register_device(struct input_dev *dev) {/* 检查input dev支持的事件类型注册device等 */...error mutex_lock_interruptible(input_mutex);if (error)goto err_device_del;/* 将该input device添加到input_dev_list链表 */list_add_tail(dev-node, input_dev_list);/* 在linux input子系统中一个input device的输入事件* 将会发送到系统中所有的event handles所以这里从保存* event handles的全局链表input_handler_list中逐个获* 取event handles添加input device */list_for_each_entry(handler, input_handler_list, node)input_attach_handler(dev, handler);/* 当注册input device成功将会通过该函数唤醒profs的poll线程 */input_wakeup_procfs_readers();mutex_unlock(input_mutex);... }然后我们再回到这个问题input core是如何知道有多少的input devices显然是在通过input_register_device()注册input device的时候同时会把input device添加到全局链表input_dev_list[input.c]中这样input core通过枚举input_dev_list链表就可以得到相应的input device。 还剩一个问题这些input device支持的事件类型和事件代码又是从哪里填充的呢 上面在介绍input device的时候我们是以gpio-keys为例同样的在这里我们继续以它为例也即gpio_keys.c。 在input device的probe()函数中如上面介绍将会通过gpio_keys_get_devtree_pdata()函数从dts中获取button的相应信息接着通过gpio_keys_setup_key()将上面获取得到的信息填充到input dev比如通过input_set_capability()函数设置input dev支持的事件类型等。 这样linux内核就知道当前的input dev支持什么事件type以及code。 当发生输入事件时信息又是如何传递到应用层用户空间 继续以gpio-keys作为input dev例子进行这个问题的解答。 回到gpio_keys_setup_key()函数在该函数中获取gpio之后将会申请相应的中断同时设置中断函数中断函数有两个分别是gpio_keys_gpio_isr()和gpio_keys_irq_isr()将会根据gpio的信息相应的选择其中一个以gpio_keys_gpio_isr()中断函数当相应的gpio中断信号到来时系统将会调用该函数而在该函数中又将存在以下代码 static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) {...mod_delayed_work(system_wq,bdata-work,msecs_to_jiffies(bdata-software_debounce));...同时的在gpio_keys_setup_key()函数中是这样初始化bdata-work所以在中断函数中设置延迟一段时间执行gpio_keys_gpio_work_func()函数。 INIT_DELAYED_WORK(bdata-work, gpio_keys_gpio_work_func);而gpio_keys_gpio_work_func()函数也很简单主要是通过gpio_keys_gpio_report_event()函数报告相应的事件信息。 static void gpio_keys_gpio_work_func(struct work_struct *work) {struct gpio_button_data *bdata container_of(work, struct gpio_button_data, work.work);gpio_keys_gpio_report_event(bdata);if (bdata-button-wakeup)pm_relax(bdata-input-dev.parent); }static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) {const struct gpio_keys_button *button bdata-button;struct input_dev *input bdata-input;unsigned int type button-type ?: EV_KEY;int state;/* 获取gpio的状态是高电平还是低电平 */state gpiod_get_value_cansleep(bdata-gpiod);if (state 0) {dev_err(input-dev.parent,failed to get gpio state: %d\n, state);return;}/* 通过input_event()函数报告input事件 */if (type EV_ABS) {if (state)input_event(input, type, button-code, button-value);} else {input_event(input, type, *bdata-code, state);}/* 同步事件 */input_sync(input); }void input_event(struct input_dev *dev,unsigned int type, unsigned int code, int value) {unsigned long flags;/* 先检查input dev是否支持该type这个dev-evbit是在调用input_set_capability()时设置的 */if (is_event_supported(type, dev-evbit, EV_MAX)) {spin_lock_irqsave(dev-event_lock, flags);input_handle_event(dev, type, code, value);spin_unlock_irqrestore(dev-event_lock, flags);} }而在input_handle_event()函数中将会先通过input_get_disposition()函数回去事件的相应信息。 #define INPUT_IGNORE_EVENT 0 /* 忽略该事件 */ #define INPUT_PASS_TO_HANDLERS 1 /* input handles处理该事件 */ #define INPUT_PASS_TO_DEVICE 2 /* input device处理该事件 */ #define INPUT_SLOT 4 #define INPUT_FLUSH 8 #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)gpio-keys中事件是由handles处理所以在input_handle_event()函数中将会将事件的信息填充到input dev的vals数组。至此回到gpio_keys_gpio_report_event()函数将事件信息填充到input dev的相应结构体之后最后将会调用input_sync(input)函数同步事件。 static inline void input_sync(struct input_dev *dev) {input_event(dev, EV_SYN, SYN_REPORT, 0); }通过input_sync()函数的代码我们可以知道最终是发送EV_SYN事件code为SYN_REPORT这样的一个事件代码将会在input_handle_event()函数中调用input_pass_values()函数激发input handles处理事件。 而在input_pass_values()函数中重要的也是以下部分 static void input_pass_values(struct input_dev *dev,struct input_value *vals, unsigned int count) {.../* 一般的handle会为空所以执行else部分代码 */handle rcu_dereference(dev-grab);if (handle) {count input_to_handler(handle, vals, count);} else {/* 从input dev的dev-h_list链表获取event handles* 上面就有提到一个input dev的事件将会发送到所有的handles */list_for_each_entry_rcu(handle, dev-h_list, d_node)if (handle-open) {count input_to_handler(handle, vals, count);if (!count)break;}}... }代码跟踪到这里又多了一个疑问dev-h_list这个链表是什么时候填充的 在input_register_device()函数中通过调用input_attach_handler()函数将event handles添加到dev-h_list函数调用流程如下 input_register_device()input_attach_handler()handler-connect(handler, dev, id)evdev_connect()input_register_handle()list_add_rcu(handle-d_node, dev-h_list)/list_add_tail_rcu(handle-d_node, dev-h_list)了解到dev-h_list链表的填充过程之后继续回到input_pass_values()函数在该函数中将会针对enable的event handle调用input_to_handler()函数而在input_to_handler()函数重要的是调用handler的events函数—evdev_events()。 /** Pass incoming events to all connected clients.*/ static void evdev_events(struct input_handle *handle,const struct input_value *vals, unsigned int count) {...client rcu_dereference(evdev-grab);if (client)evdev_pass_values(client, vals, count, ev_time);else/* 主要是通过client_list链表获取handle client进行事件处理* 可以将client理解为一个用户层的接收者在open event时创建 */list_for_each_entry_rcu(client, evdev-client_list, node)evdev_pass_values(client, vals, count, ev_time);... }在evdev_pass_values()函数中将会通过__pass_event()将event信息填充到client的buffer缓冲区如果code是SYN_REPORT将会调用kill_fasync(client-fasync, SIGIO, POLL_IN)异步通知应用层这样input event传递到应用层接着用户程序就可以通过read函数读取event的详细信息。
http://www.yutouwan.com/news/198888/

相关文章:

  • 怎样用自己的服务器建设网站网站开发的可行性
  • 桐柏网站营销型网站策划方案
  • 山东省建设厅电工证查询网站乐清女孩
  • WordPress博客整站带数据外贸公司网站有哪些
  • 2015网站备案教程wordpress 转义
  • 网站快照网络运营者义务
  • 网站页面维护wordpress搜索功能
  • 做网站上面图片的软件阿里个人网站
  • 网站系统建设需要什么资质wordpress 文章格式
  • 网页建站实用技术dw学生个人网页制作视频
  • 南宁网站定制.net网站制作综合实训报告
  • 企业站模板大全wordpress cnzz 插件
  • 网站怎么做搜索外贸soho做网站
  • 怎样在淘宝网做网站进一步优化营商环境
  • 怎样分析一个网站做的好坏界面设计案例分析
  • 有个专门做简历的网站叫代码素材网站
  • 免费企业网站系统源码建站平台有哪些
  • 有男女做暖暖的视频网站网页制作素材打包下载
  • 什么是网站建设需求做外贸仿牌网站
  • 网页与网站互联网营销公司有哪些
  • 网站备案 邮寄资料建设银行注册网站名咋设置
  • 昆山专业网站建设公司哪家好手机字体如何下载到wordpress
  • 表情包制作网站游侠相册网页设计作业
  • 广州的一起做网站wordpress阅读更改
  • 建设网站的主要设备 网站开发
  • 盐城z做网站电商类网站建设价格
  • 河北保定建设工程信息网站网站建设整体方案论文
  • 北京通州做网站中南建设网官方网站
  • 家具设计网站大全南昌seo网站推广费用
  • c 做网站怎么连接到别的网页做网站的一般要多少钱