TP 固件升级方式是采用自动升级方式,自动升级分为两种:
1.request_firmware() 用户空间获取获取固件
2.搜寻BIN 文件方式,包括/data/_goodix_update_.bin
或者/sdcard/_goodix_update_.bin。
1. 驱动初始化会调用kthread_run()在内核创建并启动一个线程,
并执行gt1x_auto_update_proc()方法,这里data==NULL
static int gt1x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id){
GTP_INFO("GTP Driver Version: %s,slave addr:%02xh",GTP_DRIVER_VERSION,
client->addr);
#ifdef CONFIG_GTP_AUTO_UPDATE
do {
struct task_struct *thread = NULL;
thread = kthread_run(gt1x_auto_update_proc,
(void *)NULL,
"gt1x_auto_update");
if(IS_ERR(thread))
GTP_ERROR("Failed to create auto-update thread: %d.", ret);
} while(0);
#endif
}
2. 执行gt1x_auto_update_proc() 方法时,由于data==null 执行 完 gt1x_update_firmware(NULL); 就会返回0;停止执行下去
int gt1x_auto_update_proc(void *data)
{
int ret;
char *filename;
u8 config[GTP_CONFIG_ORG_LENGTH + GTP_CONFIG_EXT_LENGTH] = { 0 };
if(data == NULL) {
GTP_INFO("Start auto update thread from request...");
gt1x_update_firmware(NULL);
return 0;
}
//下面是不会执行
GTP_INFO("Start auto update thread from file...");
ret = gt1x_search_update_files();
if(ret & (FOUND_FW_PATH_1 | FOUND_FW_PATH_2)) {
if(ret & FOUND_FW_PATH_1) {
filename = UPDATE_FILE_PATH_1;
}
gt1x_update_firmware(filename);
3.//执行gt1x_update_firmware(filename) 时,会执行下面方法
gt1x_enter_update_mode(); 进入固件升级模式
gt1x_update_prepare(filename);固件升级准备
gt1x_check_firmware(); 检查固件
gt1x_update_judge(); 下载决定
int gt1x_update_firmware(void *filename)
{
update_info.status = UPDATE_STATUS_RUNNING;
update_info.progress = 0;
gt1x_enter_update_mode();
ret = gt1x_update_prepare(filename);
ret = gt1x_check_firmware();
............
}
调用request_firmware(&update_info.fw,GT1X_FW_NAME, >1x_i2c_client->dev)
从用户空间获取获取固件
int gt1x_update_prepare(char *filename)
{
int ret = 0;
int retry = 5;
if(filename == NULL) {
update_info.fw_name = NULL;
update_info.fw = NULL;
ret = request_firmware(&update_info.fw, GT1X_FW_NAME, >1x_i2c_client->dev);
if(ret < 0) {
GTP_ERROR("Request firmware failed - %s (%d)", GT1X_FW_NAME, ret);
return ERROR_FW;
}
update_info.update_type = UPDATE_TYPE_REQUEST;
update_info.fw_data = (u8*)update_info.fw->data;
update_info.fw_length = update_info.fw->size;
} else {
GTP_INFO("Firmware: %s", filename);
update_info.old_fs = get_fs();
set_fs(KERNEL_DS); //将其能访问的空间限制扩大到KERNEL_DS,这样就能在内核中顺利使用内核调用了
update_info.fw_name = filename;
update_info.update_type = UPDATE_TYPE_FILE;
原理: 在Gesture模式下,IC检测到手指在屏幕滑动足够的长度,双击动作,和自定义字符,中断产生后会上报相应事件。
下面是手势唤醒一些定义和方法
#ifdef CONFIG_GTP_GESTURE_WAKEUP
extern DOZE_T gesture_doze_status; //手势睡眠状态
extern int gesture_enabled;
extern void gt1x_gesture_debug(int on) ;
//手势处理方法
extern s32 gesture_event_handler(struct input_dev *dev);
//手势睡眠方法
extern s32 gesture_enter_doze(void);
extern void gesture_clear_wakeup_data(void);
#endif
#define KEY_GES_REGULAR KEY_F2 // regular gesture-key
#define KEY_GES_CUSTOM KEY_F3 //customize gesture-key
//1.中断申请成功后会执行中断函数gt1x_ts_irq_handler()
线程中断上下文中调用的函数 gt1x_ts_work_thread()
注意: 在 Linux 中,中断具有最高的优先级。不论在任何时刻,只要产生中断事件,内核将立即执行相应的中断处理程序,等到所有挂起的中断和软中断处理完毕后才能执行正常的任务,因此有可能造成实时任务得不到及时的处理。中断线程化之后,中断将作为内核线程运行而且被赋予不同的实时优先级,实时任务可以有比中断线程更高的优先级。这样,具有最高优先级的实时任务就能得到优先处理,即使在严重负载下仍有实时性保证。但是,并不是所有的中断都可以被线程化,比如时钟中断,主要用来维护系统时间以及定时器等,其中定时器是操作系统的脉搏,一旦被线程化,就有可能被挂起,这样后果将不堪设想,所以不应当被线程化。
static s32 gt1x_request_irq(void)
{
s32 ret = -1;
const u8 irq_table[] = GTP_IRQ_TAB;
GTP_DEBUG("INT trigger type:%x", gt1x_int_type);
ret = devm_request_threaded_irq(>1x_i2c_client->dev,
gt1x_i2c_client->irq,
gt1x_ts_irq_handler,
gt1x_ts_work_thread,
irq_table[gt1x_int_type],
gt1x_i2c_client->name,
gt1x_i2c_client);
if(ret) {
GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret);
return -1;
} else {
gt1x_irq_disable();
return 0;
}
}
//2.执行gt1x_ts_work_thread()后 会执行手势执行函数 gesture_event_handler(input_dev);
static irqreturn_t gt1x_ts_work_thread(int irq, void *data)
{
u8 point_data[11] = { 0 };
u8 end_cmd = 0;
u8 finger = 0;
u8 fod_flag = 0; //add by liuyang3.wt
s32 ret = 0;
if(update_info.status) {
GTP_DEBUG("Ignore interrupts during fw update.");
return IRQ_HANDLED;
}
#ifdef CONFIG_GTP_GESTURE_WAKEUP
ret = gesture_event_handler(input_dev);
if(ret >= 0)
goto exit_work_func;
#endif
}
//3.gesture_event_handler(input_dev)函数 :获取手势数据,类型,和上报事件
s32 gesture_event_handler(struct input_dev * dev)
{
u8 doze_buf[4] = { 0 }, ges_type;
static int err_flag1 = 0, err_flag2 = 0;
int len, extra_len, need_chk;
unsigned int key_code = 0;
s32 ret = 0;
if(DOZE_ENABLED != gesture_doze_status) {
return -1;
}
..........
确认在器件测试时所有的信号引脚都与测试系统相应的通道在电性能上完成了连接,并且没有信号引脚与其他信号引脚、
电源或地发生短路。
1.快速发现芯片的各个引脚间的是否有短路
2.检测出DUT是否存在电性物理缺陷,如引脚短路、bond wire缺失、引脚的静电损坏、以及制造缺陷
3.还能发现测试时接触是否良好,探针卡或测试座是否有问题.
//1. gt1x_ts_probe() =>驱动初始化后会执行 gtp_test_sysfs_init();
static int gt1x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
//Add for openshort test;
gtp_test_sysfs_init();
mz_appid_init();
mz_gesture_init();
return 0;
}
//==>2.gtp_test_sysfs_init() 主要操作:
kobject_create_and_add 动态创建一个kobject结构并注册到sysfs
例如: 目录项(/sys/kernel/gt1x_test):通过函数
kobject_create_and_add("gt1x_test", NULL)可以在/sys/kernel下建立一个helloworld目录项。
sysfs_create_file 属性文件(dev_attr_openshort.attr)通过函数sysfs_create_file(gt1x_debug_kobj, &dev_attr_openshort.attr)建立。
这个也同时建立了文件与操作之间的联系和对应。
s32 gtp_test_sysfs_init(void)
{
gt1x_debug_kobj = kobject_create_and_add("gt1x_test", NULL);
if(gt1x_debug_kobj == NULL) {
GTP_ERROR("%s: subsystem_register failed\n", __func__);
return -ENOMEM;
}
ret = sysfs_create_file(gt1x_debug_kobj, &dev_attr_openshort.attr);
if(ret) {
GTP_ERROR("%s: sysfs_create_openshort_file failed\n", __func__);
return ret;}
}
DEBUG("GT1X debug sysfs create successwtfadd\n");
GTP_INFO("GT1X debug sysfs create success!\n");
.....
//3. DEVICE_ATTR()函数 触发条件
使用DEVICE_ATTR,可以实现驱动在sys目录自动创建文件,我们只需要实现show和store函数即可.然后在应用层就能通过cat和echo命令来对sys创建出来的文件进行读写驱动设备,实现交互.
注意:
在使用cat命令时,将会调用函数gtp_sysfs_openshort_show();
使用echo命令时,将会调用gtp_sysfs_openshort_store函数.
static DEVICE_ATTR(openshort, 0664, gtp_sysfs_openshort_show, gtp_sysfs_openshort_store);
//4.在使用cat命令时,将会调用函数gtp_sysfs_openshort_show(); => 会执行init_chip_type() 和 open_short_test(result)操作
static ssize_t gtp_sysfs_openshort_show(struct device *dev, struct device_attribute *attr,
char *buff)
{
unsigned char *result;
ssize_t i, len = 0, ret;
init_chip_type();
// malloc(300) 动态分配一个300个大小的内存,
result = (unsigned char *)malloc(300);
//+Bug436464,liuyang3.wt,ADD,20190402,Coverity Test CID70911
if(!result)
return -ENOMEM;
//-Bug436464,liuyang3.wt,ADD,20190402,Coverity Test CID70911
//开短路测试方法
ret = open_short_test(result);
if(ret < 0) {
len += sprintf((char *)&buff[len], "test error code 0x%X", ret);
}
else
if(ret == 0) {
len += sprintf((char *)&buff[len], "1");
}
…………………….
//5.init_chip_type() 和 open_short_test(result)操作
int init_chip_type(void)
{
//u8是unsigned char,u16是unsigned short,u32是unsigned long。
u8 *largebuf;
//动态分配内存大小2048
largebuf = (unsigned char *)malloc(2 * 1024);
if(largebuf == NULL) {
return MEMORY_ERR;
}
sys.reg_rawdata_base = 0xb53c;// //0xB798;
sys.key_offest = 83;
sys.config_length = 239;
sys.max_sensor_num = 32;
sys.max_driver_num = 32;
sys.short_head = 4;
//函数原型:extern int strcmp(char *str1,char * str2,int n) 比较字符串str1和str2的前n个字符。
//(!strncmp((const char *)gt1x_version.product_id, "1143", 4) 比较//gt1x_version.product_id 前4个字符串,如果不是1143,则sys.chip_type = _GT1143
if(!strncmp((const char *)gt1x_version.product_id, "1143", 4)) {
sys.chip_type = _GT1143;
} else
if(!strncmp((const char *)gt1x_version.product_id, "1133", 4)) {
sys.chip_type = _GT1133;
} else
if(!strncmp((const char *)gt1x_version.product_id, "1151", 4)) {
sys.chip_type = _GT1151;
} else {
sys.chip_type = _GT9P;
}
read_config(largebuf, sys.config_length);
free(largebuf);
DEBUG("sen*drv:%d*%d", sys.sensor_num, sys.driver_num);
return 1;
}
// 6.到这里就开始执行开短路测试操作了open_short_test(result) :
而open_short_test()操作会执行:
_init_test_paramters(ini_path): 获取测试参数
_check_short_circuit(test_types, short_result):
_check_other_options(test_types):包括 DeviceVersion or ModuleType test 结果
_check_rawdata_proc()
_save_test_result_data(save_path, test_types, short_result):存储测试结果
s32 open_short_test(unsigned char *short_result_data)
{
int ret = -1, test_types;
char times = 0, timeouts = 0, check_cfg = 0;
u16 *rawdata;
u8 *largebuf, *short_result;
char *ini_path, *save_path;
//动态分配内存
largebuf = (unsigned char *)malloc(600 + sys.max_sensor_num * sys.max_driver_num * 2);
//largebuf = (unsigned char *)kmalloc(600 + sys.max_sensor_num * sys.max_driver_num * 2,GFP_KERNEL);
if(largebuf == NULL) {
return MEMORY_ERR;
}
TEST_START:
//新申请的内存进行初始化工作
memset(largebuf, 0, 600 + sys.max_sensor_num * sys.max_driver_num * 2);
ini_path = (char *)(&largebuf[0]);
short_result = (u8 *)(&largebuf[250]);
save_path = (char *)(&largebuf[350]);
rawdata = (u16 *)(&largebuf[600]);
DEBUG("sen*drv:%d*%d", sys.sensor_num, sys.driver_num);
#if GTP_TEST_PARAMS_FROM_INI
if(auto_find_ini(ini_find_dir1, ini_format, ini_path) < 0) {
if(auto_find_ini(ini_find_dir2, ini_format, ini_path) < 0) {
WARNING("Not find the ini file.");
free(largebuf);
return INI_FILE_ILLEGAL;
}
}
DEBUG("find ini path:%s len %d", ini_path, strlen(ini_path));
#endif
test_types = _init_test_paramters(ini_path);
if(test_types < 0) {
WARNING("get test params failed.");
free(largebuf);
return test_types;
}
FORMAT_PATH(save_path, save_result_dir, "test_data");
DEBUG("save path is %s", save_path);
memset(save_data_path, 0, sizeof(save_data_path));
memcpy(save_data_path, save_path, (strlen(save_path) + 1));
memset(short_result, 0, 100);
if(test_types & _MODULE_SHORT_CHECK || ((sys.chip_type == _GT1143 || sys.chip_type == _GT1133) && test_types & _ACCORD_CHECK)) {
if(disable_irq_esd() < 0) {
WARNING("disable irq and esd fail.");
goto TEST_END;
}
usleep(20 * 1000);
if(sys.chip_type == _GT1143 || sys.chip_type == _GT1133) {
gt900_drv_gnd_resistor_threshold = gt900_sen_gnd_resistor_threshold;
gt900_drv_drv_resistor_threshold = gt900_sen_sen_resistor_threshold;
gt900_drv_sen_resistor_threshold = gt900_sen_sen_resistor_threshold;
}
ret = _check_short_circuit(test_types, short_result);
if(sys.chip_type != _GT1143 && sys.chip_type != _GT1133) {
reset_guitar();
usleep(2 * 1000);
disable_hopping(module_cfg, sys.config_length, 0);
}
if(ret < 0) {
WARNING("Short Test Fail.");
goto TEST_END;
}
DEBUG("cnt %d", short_result[0]);
if(short_result_data != NULL) {
memcpy(short_result_data, short_result, short_result[0] * 4 + 1);
}
if((sys.chip_type == _GT1143 || sys.chip_type == _GT1133) && test_error_code & _GT_SHORT) {
goto TEST_COMPLETE;
}
}
ret = _check_other_options(test_types);
if(ret < 0) {
WARNING("DeviceVersion or ModuleType test failed.");
goto TEST_END;
}
times = 0;
timeouts = 0;
if(test_types & (_MAX_CHECK | _MIN_CHECK | _ACCORD_CHECK | _OFFSET_CHECK | _JITTER_CHECK | _KEY_MAX_CHECK | _KEY_MIN_CHECK | _UNIFORMITY_CHECK)) {
while(times < 5) {
ret = read_raw_data(rawdata, sys.sensor_num * sys.driver_num);
if(ret < 0) {
DEBUG("read rawdata timeout %d.", timeouts);
if(++timeouts > 5) {
WARNING("read rawdata timeout.");
break;
}
be_normal();
continue;
}
ret = _check_rawdata_proc(test_types, rawdata, sys.sensor_num * sys.driver_num, save_path);
if(ret < 0) {
WARNING("raw data test proc error.");
break;
}
else
if(ret == 1) {
DEBUG("rawdata check finish.");
break;
}
times++;
}
TEST_COMPLETE:
ret = test_error_code;
#if GTP_SAVE_TEST_DATA
// if ((check_types & _TEST_RESULT_SAVE) != 0)
{
_save_test_result_data(save_path, test_types, short_result);
}
#endif
7.在使用echo命令时,将会调用gtp_sysfs_openshort_store函数.
static ssize_t gtp_sysfs_openshort_store(struct device *dev, struct device_attribute
*attr, const char *buff, size_t count)
{
DEBUG("openshort_store");
buf = (unsigned char *)malloc(100);
if(buf == NULL) {
return -1;
}
// a+ 以附加方式打开可读写的文件 /sdcard/test.csv
fp = fopen("/sdcard/test.csv", "a+");
if(fp == NULL) {
DEBUG("open /sdcard/test.csv fail");
free(buf);
return -1;
}
bytes += sprintf(&buf[bytes], "%d,", i);
}
DEBUG("%s", buf);
fwrite(buf, bytes, 1, fp);
本人有写不对地方,欢迎大家指出,
https://mp.csdn.net/postedit