转载地址:http://blog.youkuaiyun.com/hejinjing_tom_com/article/details/49252333
------------------------------------------------------------
author: hjjdebugdate: 2015年 10月 19日 星期一 17:21:49 CST
------------------------------------------------------------
tslib 代码分析
序言1:tslib 是开源软件,c 语言写成,架构完美,值得阅读。
序言2:程序是用来处理数据的, 那么,tslib 也不会例外,它处理的数据,就是ts设备
读出的数据,那么我们看它怎么处理。
分析实例: 本篇先分析ts_print_raw, ts_print 应用程序
************************************************************
一: ts_print_raw 例子
************************************************************
程序非常简短,就是
struct tsdev *ts_open(char *devname),
tsconfig(struct tsdev *ts),
ts_read_raw(struct tsdev *ts, struct ts_sample *sample int nr),
后面就要分别解释这三句了。
1. 打开一个ts设备,
分配一个tsdev 结构,打开传递的设备名称就可以了。
************************************************************
2. 配置这个ts设备
************************************************************
----------------------------------------
2.1:打开ts的配置文件,
----------------------------------------
2.1.1: 这个文件的名称是由环境变量TSLIB_CONFILE 提供
如果环境变量为空,就用程序默认的。
2.1.2: 配置文件有特定的格式,有空格和tab 分割为域,
第一个域只能是module,或module_raw 关键字,后面的为名称和参数。
2.1.3:分析配置文件,
然后通过ts_load_module(ts,module_name,param) 或者ts_load_module_raw 来把模块加载到内存,
并配置ts 结构变量
其中module_raw 是必须要有的。
----------------------------------------
2.2: 细看 static int __ts_load_module(struct tsdev *ts, const char *module, const char *params, int raw)
----------------------------------------
2.2.1: 目的,ts_load_module 还是为了构建ts设备结构,
它首先是进行静态构建,若不成功再进行动态构建,
成功后,将module信息与ts设备相关联。
2.2.2: 静态构建module
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.2.1: 什么是module,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
每一个module,是由一个module 名称和module 初始化函数构成的,
静态构建就是预先定义好了modules 变量,现在根据传来的module 名称,搜索这个表,找到对应的初始化函数,
调用这个初始化函数,初始化函数会返回module结构指针。
static const struct {
const char *name;
tslib_module_init mod_init;
} tslib_modules[] = {};
具体的module 是由tslib_modules来定义的, 可惜,我们一个module 都没有定义。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.2.2: module初始化函数是什么?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
现在即没有具体的module, 也没有具体的初始化函数,但它们必须符合一定规范。初始化函数是这样的一个函数原型.
typedef struct tslib_module_info *(*tslib_module_init)(struct tsdev *dev, const char *params);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.2.3: module_info 是什么?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
module_info 被定义为一个链表,有next 指针,保留有ts设备地址,动态加载库handle,还有一项为option 指针
struct tslib_module_info {
struct tsdev *dev;
struct tslib_module_info *next; /* next module in chain */
void *handle; /* dl handle */
const struct tslib_ops *ops;
};
该option 指针指向2个函数指针,一个read, 一个finishi
struct tslib_ops {
int (*read)(struct tslib_module_info *inf, struct ts_sample *samp, int nr);
int (*fini)(struct tslib_module_info *inf);
};
----------------------------------------
2.2.3: 动态构建module.
----------------------------------------
动态构建module 是通过加载动态链接库来完成的,它有很多优点,例如可以只加载所需要的module, 不使用的不加载。
要不怎么叫动态加载呢!
2.2.3.1: 动态加载module 到内存。
是的,传来的模块的名字就是要加载的动态库的名字,通过dlopen来加载。通过dlsym找到module 初始化入口函数,
执行它,返回module 指针。
2.2.3.2: 什么是架构
现在一个具体的module 都没有,怎么就开始写出代码了(ts_load_module.c), 是的,这就叫架构,它要求将来要写的代码
必须符合一定的规范,才能被已经生成的代码所认识。并为先前的代码所管理。
tslib模块的架构要求, 每个模块要有一个初始化函数,动态库的导出函数叫:mod_int
这就叫接口,是代码控制与实现的剥离。
----------------------------------------
2.2.4: 看一个具体的module, input.so.
----------------------------------------
对应的代码plugin下input-raw.c
2.2.4.1: 定义mod_init 符号
typedef struct tslib_module_info *(*tslib_module_init)(struct tsdev *dev, const char *params);
#define TSLIB_MODULE_INIT(f) TSAPI tslib_module_init mod_init = &f
TSLIB_MODULE_INIT(input_mod_init);
2.2.4.2: input_mod_init.
架构在load module 后执行input_mod_init 函数,该函数申请了一块内存
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.4.2.1: 申请tslib_input 内存
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
i = malloc(sizeof(struct tslib_input));
i->module.ops = &__ts_input_ops;
其中tslib_input 是包含 tslib_module_info 的结构, 它还有自己专有的属性,开始均初始化为0
struct tslib_input {
struct tslib_module_info module;
int current_x;
int current_y;
int current_p;
int sane_fd;
int using_syn;
int grab_events;
};
static const struct tslib_ops __ts_input_ops = {
.read = ts_input_read,
.fini = ts_input_fini,
};
module.ops 也已赋值,这样以后可以通过结构指针调用到ts_input_read, ts_input_fini函数
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2.4.2.2: 存储tslib_input 专有属性的数值
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ts_lib 库还提供了一个功能,分析变量函数
库: tslib_parse_vars(&i->module, raw_vars, NR_VARS, params)
它负责
把param赋值语句分割为左部和右部,然后
搜索给定的表,与左部匹配,调用表的对应函数,为该函数传递右部数据
查找的函数可能把配置的数据,存储到模块子类的属性中。
plugin:
static const struct tslib_vars raw_vars[] =
{
{ "grab_events", (void *)1, parse_raw_grab },
};
库:
struct tslib_vars {
const char *name;
void *data;
int (*fn)(struct tslib_module_info *inf, char *str, void *data);
};
plugin:
static int parse_raw_grab(struct tslib_module_info *inf, char *str, void *data)
{
struct tslib_input *i = (struct tslib_input *)inf; //指针强制转化为子类型
根据字符串和数据,将数据存入module 的扩展属性中。
}
2.2.4.3: ts_input_read
就是从设备读取一个完整事件数据,然后根据ev.type,ev.code,ev.value 来保存其数据
2.2.4.4: ts_input_fini
fini 就是释放内存.
----------------------------------------
2.2.5: 具体的module, pthres.so
----------------------------------------
对应的代码plugin下pthres.c
看来代码我才知道,这是压力阈值的意思。
直接看pthres_read 函数, 压力比设定最小值小,或比设定最大值大,忽略之
----------------------------------------
2.2.6: 具体的module, variance.so
----------------------------------------
方差判定上次移动是否为噪声的依据是,两次的移动距离超过了delta,可能是噪声
如果两次都超过,则不是噪声,而是快速移动。
----------------------------------------
2.2.7: 具体的module, degitter.so
----------------------------------------
去抖动是把最多4个取值按照一定的权重重新计算来返回结果
参数delta 的含义:
----------------------------------------
2.2.8: 具体的module, linear.so
----------------------------------------
它吧读到的数据,与屏幕矫正的值进行了缩放
samp->x = samp->x * info->dev->res_x / lin->cal_res_x;
************************************************************
二: ts_print 代码
************************************************************
与 ts_print_raw 是一样的分析
只是一个调用ts_read_raw, 一个调用ts_read.
ts_read_raw 只有一层,不会返回给其他module.
ts_read,则是->linear->degitter->variance->pthres->read_raw 这个链来处理数据