不属于c2c网站的是重庆奉节网站建设公司哪家专业
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:08
当前位置: 首页 > news >正文
不属于c2c网站的是,重庆奉节网站建设公司哪家专业,公司logo墙,企业推广费用占比多少合适往期内容 本专栏往期内容#xff1a; input子系统的框架和重要数据结构详解-CSDN博客input device和input handler的注册以及匹配过程解析-CSDN博客input device和input handler的注册以及匹配过程解析-CSDN博客编写一个简单的Iinput_dev框架-CSDN博客GPIO按键驱动分析与使用 input子系统的框架和重要数据结构详解-CSDN博客input device和input handler的注册以及匹配过程解析-CSDN博客input device和input handler的注册以及匹配过程解析-CSDN博客编写一个简单的Iinput_dev框架-CSDN博客GPIO按键驱动分析与使用input_dev层-CSDN博客 I2C子系统专栏 专栏地址IIC子系统_憧憬一下的博客-CSDN博客具体芯片的IIC控制器驱动程序分析i2c-imx.c-CSDN博客 – 末篇有往期内容观看顺序 总线和设备树专栏 专栏地址总线和设备树_憧憬一下的博客-CSDN博客设备树与 Linux 内核设备驱动模型的整合-CSDN博客 – 末篇有往期内容观看顺序 目录 往期内容前言1. 驱动程序框架2. 设备树示例3. 驱动程序分析3.1 分配/设置/注册input_dev3.2 注册中断处理函数3.3 中断处理函数分析 4.编写 前言 Linux 4.x内核 Documentation\devicetree\bindings\input\touchscreen\goodix.txtdrivers/input/touchscreen/gt9xx/gt9xx.c gt9xx.c 设备树 IMX6ULLLinux-4.9.88/arch/arm/boot/dts/100ask_imx6ull-14x14.dts
本节主要讲解内核中提供的gt9xx.c来看看是如何通过input子系统来实现一个IIC协议的传输之后在此基础上编写一个简单的input子系统的IIC驱动
- 驱动程序框架 2. 设备树示例 i2c2 {gt9xx5d {compatible goodix,gt9xx;reg 0x5d;status okay;interrupt-parent gpio1;interrupts 5 IRQ_TYPE_EDGE_FALLING;pinctrl-names default;pinctrl-0 pinctrl_tsc_reset pinctrl_touchscreen_int;/pinctrl-1 pinctrl_tsc_irq;//pinctrl-names default, int-output-low, int-output-high, int-input;pinctrl-0 ts_int_default;pinctrl-1 ts_int_output_low;pinctrl-2 ts_int_output_high;pinctrl-3 ts_int_input;/reset-gpios gpio5 2 GPIO_ACTIVE_LOW;irq-gpios gpio1 5 IRQ_TYPE_EDGE_FALLING;irq-flags 2; /1:rising 2: falling/touchscreen-max-id 5;touchscreen-size-x 800;touchscreen-size-y 480;touchscreen-max-w 1024;touchscreen-max-p 1024;/touchscreen-key-map 172, 158;/ /KEY_HOMEPAGE, KEY_BACK/goodix,type-a-report 0;goodix,driver-send-cfg 0;goodix,create-wr-node 1;goodix,wakeup-with-reset 0;goodix,resume-in-workqueue 0;goodix,int-sync 0;goodix,swap-x2y 0;goodix,esd-protect 0;goodix,pen-suppress-finger 0;goodix,auto-update 0;goodix,auto-update-cfg 0;goodix,power-off-sleep 0;/* …… */}; }; 这段设备树Device Tree定义配置了一个基于 I2C 总线的 Goodix GT9xx 系列触摸屏设备设备地址为 0x5d。
- 节点和基础属性 i2c2 {gt9xx5d {compatible goodix,gt9xx;reg 0x5d;i2c2指向 I2C 总线控制器的节点这意味着该设备挂载在 I2C 总线 2 上。gt9xx5d表示该触摸屏设备的 I2C 地址为 0x5d。compatible goodix,gt9xx;指定设备兼容字符串匹配 Goodix 的 GT9xx 系列触摸屏设备驱动程序。reg 0x5d;设备的 I2C 地址定义为 0x5d。
- 中断与引脚控制配置 status okay;interrupt-parent gpio1;interrupts 5 IRQ_TYPE_EDGE_FALLING;pinctrl-names default;pinctrl-0 pinctrl_tsc_reset pinctrl_touchscreen_int;status okay;设备状态标记为启用。interrupt-parent gpio1;指定中断的父节点为 gpio1即 GPIO 控制器 1。interrupts 5 IRQ_TYPE_EDGE_FALLING;中断配置使用 GPIO1 控制器的第 5 个引脚触发模式为下降沿触发IRQ_TYPE_EDGE_FALLING。pinctrl-names 和 pinctrl-0配置引脚控制器pinctrl-names 指定了配置的名字pinctrl-0 则定义了相关引脚配置pinctrl_tsc_reset 和 pinctrl_touchscreen_int用于触摸屏重置和中断引脚初始化。
- GPIO 和中断标志 reset-gpios gpio5 2 GPIO_ACTIVE_LOW;irq-gpios gpio1 5 IRQ_TYPE_EDGE_FALLING;irq-flags 2; reset-gpios gpio5 2 GPIO_ACTIVE_LOW;触摸屏的复位引脚定义在 gpio5 的第 2 引脚信号低电平有效。irq-gpios gpio1 5 IRQ_TYPE_EDGE_FALLING;触摸屏的中断引脚配置为 gpio1 控制器的第 5 引脚设置为下降沿触发。irq-flags 2;中断触发标志2 表示下降沿触发。
- 触摸屏参数 touchscreen-max-id 5;touchscreen-size-x 800;touchscreen-size-y 480;touchscreen-max-w 1024;touchscreen-max-p 1024;touchscreen-max-id 5;最大触摸点数为 5表示最多支持 5 个手指的多点触控。touchscreen-size-x 和 touchscreen-size-y触摸屏 X、Y 轴的分辨率分别为 800 和 480。touchscreen-max-w 和 touchscreen-max-p触控宽度和压力的最大值均为 1024。
- Goodix 驱动特性 goodix,type-a-report 0;goodix,driver-send-cfg 0;goodix,create-wr-node 1;goodix,wakeup-with-reset 0;goodix,resume-in-workqueue 0;goodix,int-sync 0;goodix,swap-x2y 0;goodix,esd-protect 0;goodix,pen-suppress-finger 0;goodix,auto-update 0;goodix,auto-update-cfg 0;goodix,power-off-sleep 0;Goodix 特定属性goodix,xxx 属性定义了一些特性和行为例如 goodix,type-a-report 和 goodix,driver-send-cfg控制是否启用 A 类型报告和驱动是否发送配置信息。goodix,create-wr-node创建 WR写节点的标志。goodix,wakeup-with-reset 和 goodix,power-off-sleep控制唤醒和电源管理的行为。其他 Goodix 触摸屏特性配置按需要启用或禁用。
这些属性通过设备树配置使系统能够正确初始化并管理触摸屏设备。 - 驱动程序分析 gt9xx.c 3.1 分配/设置/注册input_dev gtp_proberet gtp_request_input_dev(ts);ts-input_dev input_allocate_device();……ret input_register_device(ts-input_dev);ret gtp_request_irq(ts); 3.2 注册中断处理函数 ret request_threaded_irq(ts-client-irq, NULL,gtp_irq_handler,ts-pdata-irq_flags | IRQF_ONESHOT,ts-client-name,ts);3.3 中断处理函数分析 通过I2C函数 2c_tansfer读取数据、上报数据。 static irqreturn_t gtp_irq_handler(int irq, void *dev_id) {struct goodix_ts_data *ts dev_id;gtp_work_func(ts);return IRQ_HANDLED; }static void gtp_work_func(struct goodix_ts_data *ts) {u8 point_state 0; // 保存触摸点的状态u8 key_value 0; // 保存按键的状态s32 i 0; // 循环变量用于迭代按键事件s32 ret -1; // 函数调用返回值static u8 pre_key; // 保存上一次的按键值用于识别按键变化struct goodix_point_t points[GTP_MAX_TOUCH_ID]; // 存储触摸点信息// 检查是否正在执行复位操作若是则退出函数if (test_bit(PANEL_RESETTING, ts-flags))return;// 检查工作线程是否启用若未启用则退出函数if (!test_bit(WORK_THREAD_ENABLED, ts-flags))return;// 手势事件处理检测滑动唤醒功能是否启用且设备是否处于休眠模式if (ts-pdata-slide_wakeup test_bit(DOZE_MODE, ts-flags)) {// 调用手势处理函数 gtp_gesture_handlerret gtp_gesture_handler(ts);if (ret) {// 若处理失败记录错误日志dev_err(ts-client-dev,Failed handler gesture event %d\n, ret);}return; // 处理完成后退出函数}// 获取触摸点的状态及按键状态———–1point_state gtp_get_points(ts, points, key_value); if (!point_state) {// 若未检测到有效的触摸点记录调试日志dev_dbg(ts-client-dev, Invalid finger points\n);return; // 没有有效触摸点直接返回}// 处理触摸按键事件if (key_value 0xf0 || pre_key 0xf0) { // 判断是否有按键事件// 处理手写笔的按键switch (key_value) {case 0x40: // 两个按键都按下input_report_key(ts-input_dev, GTP_PEN_BUTTON1, 1);input_report_key(ts-input_dev, GTP_PEN_BUTTON2, 1);break;case 0x10: // 按下第一个按键input_report_key(ts-input_dev, GTP_PEN_BUTTON1, 1);input_report_key(ts-input_dev, GTP_PEN_BUTTON2, 0);dev_dbg(ts-client-dev, pen button1 down\n);break;case 0x20: // 按下第二个按键input_report_key(ts-input_dev, GTP_PEN_BUTTON1, 0);input_report_key(ts-input_dev, GTP_PEN_BUTTON2, 1);break;default: // 没有按键按下恢复初始状态input_report_key(ts-input_dev, GTP_PEN_BUTTON1, 0);input_report_key(ts-input_dev, GTP_PEN_BUTTON2, 0);dev_dbg(ts-client-dev, button1 up\n);break;}input_sync(ts-input_dev); // 同步输入事件pre_key key_value; // 更新上次按键状态} else if (key_value 0x0f || pre_key 0x0f) { // 判断是否有面板按键事件// 遍历所有按键检测是否有按键状态发生变化for (i 0; i ts-pdata-key_nums; i) {if ((pre_key | key_value) (0x01 i))input_report_key(ts-input_dev,ts-pdata-key_map[i], // 具体按键映射key_value (0x01 i)); // 按键状态}input_sync(ts-input_dev); // 同步输入事件pre_key key_value; // 更新上次按键状态}// 选择不同的报告格式进行触摸点的处理if (!ts-pdata-type_a_report)gtp_mt_slot_report(ts, point_state 0x0f, points); // Slot方式———————-(2)elsegtp_type_a_report(ts, point_state 0x0f, points); // Type A方式 }1point_state gtp_get_points(ts, points, key_value); 从 I2C 总线上读取触摸点的数据和触摸状态。提取坐标、压力值、工具类型等信息若需要则交换 X/Y 坐标。 将手写笔和普通触摸点区分按需要调整触摸点数据。完成数据读取后通过发送结束命令结束当前触摸事件。 ret gtp_i2c_read(ts-client, point_data, 12); //这里内部就调用到了i2c_transfer发起传输 static u8 gtp_get_points(struct goodix_ts_data *ts,struct goodix_point_t *points,u8 *key_value) {int ret; // 保存 I2C 传输返回状态int i; // 循环变量u8 *coor_data NULL; // 指向触摸坐标数据的指针u8 finger_state 0; // 保存手指状态信息u8 touch_num 0; // 保存当前触摸点的数量u8 end_cmd[3] { // 用于向触摸屏发送 结束 命令GTP_READ_COOR_ADDR 8,GTP_READ_COOR_ADDR 0xFF,0};u8 point_data[2 1 8 * GTP_MAX_TOUCH_ID 1] { // 存储触摸点的数据GTP_READ_COOR_ADDR 8,GTP_READ_COOR_ADDR 0xFF};// 读取触摸点的坐标数据ret gtp_i2c_read(ts-client, point_data, 12); //这里内部就调用到了i2c_transfer发起传输if (ret 0) {dev_err(ts-client-dev, I2C transfer error. errno:%d\n , ret);return 0; // 读取失败返回0}finger_state point_data[GTP_ADDR_LENGTH]; // 获取触摸屏状态if (finger_state 0x00) // 若无触摸点return 0;// 获取触摸点数量低 4 位表示触摸点数量touch_num finger_state 0x0f;// 检查触摸状态是否合法如超出最大触摸数或没有触摸if ((finger_state MASK_BIT_8) 0 || touch_num ts-pdata-max_touch_id) {dev_err(ts-client-dev, Invalid touch state: 0x%x, finger_state);finger_state 0; // 若非法则重置触摸状态goto exit_get_point; // 跳转到退出点}// 若有多个触摸点则读取后续触摸点数据if (touch_num 1) {u8 buf[8 * GTP_MAX_TOUCH_ID] {(GTP_READ_COOR_ADDR 10) 8,(GTP_READ_COOR_ADDR 10) 0xff};ret gtp_i2c_read(ts-client, buf, 2 8 * (touch_num - 1));if (ret 0) {dev_err(ts-client-dev, I2C error. %d\n, ret);finger_state 0;goto exit_get_point;}memcpy(point_data[12], buf[2], 8 * (touch_num - 1));}// 触摸按键事件低 4 位标识按键事件*key_value point_data[3 8 * touch_num];// 初始化触摸点信息数组memset(points, 0, sizeof(*points) * GTP_MAX_TOUCH_ID);for (i 0; i touch_num; i) {coor_data point_data[i * 8 3]; // 获取触摸点的坐标数据points[i].id coor_data[0]; // 触摸点 IDpoints[i].x coor_data[1] | (coor_data[2] 8); // 触摸点的 X 坐标points[i].y coor_data[3] | (coor_data[4] 8); // 触摸点的 Y 坐标points[i].w coor_data[5] | (coor_data[6] 8); // 触摸点的宽度points[i].p coor_data[5] | (coor_data[6] 8); // 压力值// 判断是否需要交换 X/Y 坐标if (ts-pdata-swap_x2y)GTP_SWAP(points[i].x, points[i].y);dev_dbg(ts-client-dev, [%d][%d %d %d]\n, points[i].id, points[i].x, points[i].y, points[i].p);// 判断是否为手写笔触摸点if (points[i].id 0x80) {points[i].tool_type GTP_TOOL_PEN;points[i].id 10; // 手写笔 ID 固定为 10if (ts-pdata-pen_suppress_finger) {points[0] points[i];memset(points, 0, sizeof(*points) * (GTP_MAX_TOUCH_ID - 1));finger_state 0xf0;finger_state | 0x01; // 设置第一个触摸点为手写笔break;}} else {points[i].tool_type GTP_TOOL_FINGER;}}exit_get_point:// 若未处于 RAW 数据模式写入结束命令以结束当前触摸事件if (!test_bit(RAW_DATA_MODE, ts-flags)) {ret gtp_i2c_write(ts-client, end_cmd, 3);if (ret 0)dev_info(ts-client-dev, I2C write end_cmd error!);}return finger_state; // 返回触摸屏状态 }2gtp_irq_handler中你的gtp_mt_slot_report(ts, point_state 0x0f, points); // Slot方式。 函数主要负责报告多点触控的触摸点状态包括其位置、工具类型和压力等。使用位图cur_touch 和 pre_touch跟踪当前和先前的触摸 ID从而确定哪些触摸点是新触摸、哪些是结束触摸。 static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num, struct goodix_point_t points) {int i; // 循环变量u16 cur_touch 0; // 当前触摸 ID 位图static u16 pre_touch; // 上一帧的触摸 ID 位图static u8 pre_pen_id; // 上一次触摸的笔 ID// 遍历每个可能的触摸点最大触摸 ID 由 ts-pdata-max_touch_id 决定for (i 0; i ts-pdata-max_touch_id; i) {// 检查当前触摸点是否有效if (touch_num i points-id) {// 设置当前触摸点的槽slotinput_mt_slot(ts-input_dev, points-id);// 判断工具类型if (points-tool_type GTP_TOOL_PEN) {// 如果是笔工具报告笔的状态为真input_mt_report_slot_state(ts-input_dev, MT_TOOL_PEN, true);pre_pen_id points-id; // 更新上一次的笔 ID} else {// 否则为手指工具报告状态为真input_mt_report_slot_state(ts-input_dev, MT_TOOL_FINGER, true);}// 报告触摸点的 X 坐标input_report_abs(ts-input_dev, ABS_MT_POSITION_X, points-x);// 报告触摸点的 Y 坐标input_report_abs(ts-input_dev, ABS_MT_POSITION_Y, points-y);// 报告触摸点的宽度input_report_abs(ts-input_dev, ABS_MT_TOUCH_MAJOR, points-w);// 报告触摸点的压力input_report_abs(ts-input_dev, ABS_MT_PRESSURE, points-p);// 更新当前触摸 ID 位图cur_touch | 0x01 points-id;points; // 移动到下一个触摸点} // 如果在上一帧中这个槽是活跃的else if (pre_touch (0x01 i)) {// 设置当前槽为 iinput_mt_slot(ts-input_dev, i);// 检查上次是否是笔 IDif (pre_pen_id i) {// 如果是笔报告笔的状态为假input_mt_report_slot_state(ts-input_dev, MT_TOOL_PEN, false);/ 有效的 ID 应小于 10所以将 ID 设置为 0xff * 来表示无效状态*/pre_pen_id 0xff; // 重置笔 ID} else {// 否则报告手指状态为假input_mt_report_slot_state(ts-input_dev, MT_TOOL_FINGER, false);}}}// 更新上一帧的触摸 ID 位图为当前帧pre_touch cur_touch;// 同步当前的触摸帧input_mt_sync_frame(ts-input_dev);// 同步输入设备状态input_sync(ts-input_dev); } gtp_irq_handlergtp_work_func(ts);point_state gtp_get_points(ts, points, key_value);gtp_i2c_readi2c_transfergtp_mt_slot_report(ts, point_state 0x0f, points);input_mt_slotinput_mt_report_slot_stateinput_report_abs有所疑问可以先看 I2C相关结构体讲解:i2c_adapter、i2c_algorithm、i2c_msg-CSDN博客 编写一个简单的Iinput_dev框架-CSDN博客 4.编写 这里主要是参考gpio_keys.c但思路其实和上面介绍的差不多设置Input_dev并注册、配置事件类型和支持的事件、请求中断注册中断等。 #define TOUCHSCREEN_POLL_TIME_MS 10 // 定义轮询时间单位为毫秒// 定义模拟触摸屏硬件数据结构 struct qemu_ts_con {volatile unsigned int pressure; // 触摸压力0表示未触摸非0表示触摸volatile unsigned int x; // 触摸X坐标volatile unsigned int y; // 触摸Y坐标volatile unsigned int clean; // 清除标志 };// 全局变量定义 static struct input_dev *g_input_dev; // 输入设备 static int g_irq; // 中断号 static struct qemu_ts_con *ts_con; // 指向模拟触摸屏的结构体 struct timer_list ts_timer; // 定时器用于轮询触摸状态// 定时器回调函数用于定期轮询触摸状态 static void ts_irq_timer(unsigned long _data) {// 如果检测到触摸事件if (ts_con-pressure) {// 报告触摸位置input_event(g_input_dev, EV_ABS, ABS_X, ts_con-x);input_event(g_input_dev, EV_ABS, ABS_Y, ts_con-y);input_sync(g_input_dev);// 重新启动定时器mod_timer(ts_timer, jiffies msecs_to_jiffies(TOUCHSCREEN_POLL_TIME_MS));} }// 中断服务函数触发触摸事件处理 static irqreturn_t input_dev_demo_isr(int irq, void *dev_id) {// 如果有触摸事件发生if (ts_con-pressure) {// 报告触摸位置和触摸按键状态input_event(g_input_dev, EV_ABS, ABS_X, ts_con-x);input_event(g_input_dev, EV_ABS, ABS_Y, ts_con-y);input_event(g_input_dev, EV_KEY, BTN_TOUCH, 1);input_sync(g_input_dev);// 启动定时器继续监控触摸状态mod_timer(ts_timer, jiffies msecs_to_jiffies(TOUCHSCREEN_POLL_TIME_MS));} else {// 如果没有触摸报告触摸键松开input_event(g_input_dev, EV_KEY, BTN_TOUCH, 0);input_sync(g_input_dev);}return IRQ_HANDLED; }// 设备初始化函数负责资源分配和设备注册 static int input_dev_demo_probe(struct platform_device *pdev) {struct device *dev pdev-dev;int error;struct resource *io;int gpio;printk(%s %s %d\n, FILE, FUNCTION, LINE);// 获取GPIO编号gpio of_get_gpio(pdev-dev.of_node, 0);// 分配并初始化input_dev结构体g_input_dev devm_input_allocate_device(dev);if (!g_input_dev)return -ENOMEM;// 配置input_dev的基础信息g_input_dev-name input_dev_demo;g_input_dev-phys input_dev_demo;g_input_dev-dev.parent dev;g_input_dev-id.bustype BUS_HOST;g_input_dev-id.vendor 0x0001;g_input_dev-id.product 0x0001;g_input_dev-id.version 0x0100;// 配置事件类型和支持的事件set_bit(EV_KEY, g_input_dev-evbit);set_bit(EV_ABS, g_input_dev-evbit);set_bit(INPUT_PROP_DIRECT, g_input_dev-propbit);set_bit(BTN_TOUCH, g_input_dev-keybit);set_bit(ABS_X, g_input_dev-absbit);set_bit(ABS_Y, g_input_dev-absbit);// 配置触摸屏的绝对坐标范围input_set_abs_params(g_input_dev, ABS_X, 0, 0xffff, 0, 0);input_set_abs_params(g_input_dev, ABS_Y, 0, 0xffff, 0, 0);// 注册input_deverror input_register_device(g_input_dev);if (error)return error;// 获取硬件寄存器的I/O资源并映射io platform_get_resource(pdev, IORESOURCE_MEM, 0);ts_con ioremap(io-start, resource_size(io));// 获取并请求GPIO的中断号g_irq gpio_to_irq(gpio);error request_irq(g_irq, input_dev_demo_isr, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, input_dev_demo_irq, NULL);if (error)return error;// 初始化定时器setup_timer(ts_timer, ts_irq_timer, (unsigned long)NULL);return 0; }// 设备卸载函数释放资源 static int input_dev_demo_remove(struct platform_device *pdev) {del_timer_sync(ts_timer); // 停止定时器iounmap(ts_con); // 取消内存映射free_irq(g_irq, NULL); // 释放中断input_unregister_device(g_input_dev); // 注销设备return 0; }// 设备树匹配表 static const struct of_device_id input_dev_demo_of_match[] {{ .compatible 100ask,input_dev_demo, },{ }, };// 平台驱动结构体定义 static struct platform_driver input_dev_demo_driver {.probe input_dev_demo_probe,.remove input_dev_demo_remove,.driver {.name input_dev_demo,.of_match_table input_dev_demo_of_match,} };// 模块初始化函数 static int __init input_dev_demo_init(void) {printk(%s %s %d\n, FILE, FUNCTION, LINE);return platform_driver_register(input_dev_demo_driver); }// 模块退出函数 static void __exit input_dev_demo_exit(void) {platform_driver_unregister(input_dev_demo_driver); }module_init(input_dev_demo_init); module_exit(input_dev_demo_exit);MODULE_LICENSE(GPL);
- 上一篇: 不能进入建设银行网站h5课件制作软件
- 下一篇: 不属于企业网站建设基本标准的是浏览器网站大全免费
相关文章
-
不能进入建设银行网站h5课件制作软件
不能进入建设银行网站h5课件制作软件
- 技术栈
- 2026年03月21日
-
不记得域名管理网站wordpress 分类目录里
不记得域名管理网站wordpress 分类目录里
- 技术栈
- 2026年03月21日
-
不会代码建设网站wordpress同步到公众号
不会代码建设网站wordpress同步到公众号
- 技术栈
- 2026年03月21日
-
不属于企业网站建设基本标准的是浏览器网站大全免费
不属于企业网站建设基本标准的是浏览器网站大全免费
- 技术栈
- 2026年03月21日
-
不属于网站后期维护wordpress迁移域名修改
不属于网站后期维护wordpress迁移域名修改
- 技术栈
- 2026年03月21日
-
不通过第三方平台做微网站网站建设行业企业发展前景
不通过第三方平台做微网站网站建设行业企业发展前景
- 技术栈
- 2026年03月21日






