番外篇-mtk平台logo显示接口

分析 mtk 平台 logo 显示接口, 自己实现一个显示 demo ,并利用 input 子系统在屏上绘图

1、mtk提供了测试 demo

/vendor/mediatek/proprietary/external/libshowlogo/libshowlogoTest //路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ctype.h>


#include <utils/Log.h>

//#include <charging_animation.h>

#define VERION_OLD_ANIMATION 0
#define VERION_NEW_ANIMATION 1
#define VERION_WIRELESS_CHARGING_ANIMATION 2

#define DRAW_ANIM_MODE_FB 1
#define DRAW_ANIM_MODE_SURFACE 0


#define LOG_ANIM(x...) dprintf(0, x)


void test_charging_animation(int charging_item)
{
int time = 0;
while(time <= 10) {
if (charging_item == 2) {
show_fast_charging(25);
} else {
show_battery_capacity(25);
}
time ++;
sleep(1);
}
}

int main(int argc, char *argv[])
{
// DRAW_ANIM_MODE_SURFACE 0
// DRAW_ANIM_MODE_FB 1

printf("[logo_test %s %d]libshowlogo Test ...\n",__FUNCTION__,__LINE__);

printf("*************** libshowlogo Test ********************\n");
printf("******* Testlibshowlogo introduce... *******\n");
printf("It can test boot logo, kernel logo and charging animation using \n framebuffer or surface flinger with different parameters\n");
printf("***************************************************************\n");
printf(" ---> para 1:boot kernel charging ut\n");
printf(" boot: boot logo\n");
printf(" kernel: kernel logo \n");
printf(" charging: charging animation\n");
printf(" ut: test all\n");

printf(" ---> para 2: fb sf \n");
printf(" fb: framebuffer\n");
printf(" sf: surface flinger\n");

printf(" ---> para 3: new fast wireless \n");
printf(" new: new version\n");
printf(" fast: fast Charging\n");
printf(" wireless: wireless Charging\n");

printf("\n ---> Example (Default):libshowlogoTest boot sf\n");
printf("**************************************************************\n");


int draw_mode = DRAW_ANIM_MODE_SURFACE;
int version = VERION_OLD_ANIMATION;

int test_item = 0;
int charging_item = 0;

if(argc > 1){
printf("[logo_test %s %d] argv[1]=%s\n",__FUNCTION__,__LINE__,argv[1]);
if(!strcmp(argv[1],"boot")){
test_item = 0;
}else if(!strcmp(argv[1],"kernel")){
test_item = 1;
}else if(!strcmp(argv[1],"charging")){
test_item = 2;
}else if(!strcmp(argv[1],"ut")){
test_item = 3;
}
}

if(argc > 2){
printf("[logo_test %s %d] argv[2]=%s\n",__FUNCTION__,__LINE__,argv[2]);
if(!strcmp(argv[2],"sf"))
{
draw_mode = DRAW_ANIM_MODE_SURFACE;
}else if(!strcmp(argv[2],"fb")){
draw_mode = DRAW_ANIM_MODE_FB;
}
}

if(argc > 3){
printf("[logo_test %s %d] argv[3]=%s\n",__FUNCTION__,__LINE__,argv[3]);
if(!strcmp(argv[3],"new")){
version = VERION_NEW_ANIMATION;
charging_item = 1;
}else if(!strcmp(argv[3],"fast")){
version = VERION_NEW_ANIMATION;
charging_item = 2;
}else if(!strcmp(argv[3],"wireless")){
version = VERION_WIRELESS_CHARGING_ANIMATION;
charging_item = 3;
}
}

printf("[logo_test %s %d] argc =%d, draw_mode=%d,test_item=%d, version=%d, charging_item=%d\n"
,__FUNCTION__,__LINE__,argc, draw_mode,test_item,version,charging_item);

// set parameter before init
set_draw_mode(draw_mode);
set_anim_version(version);
anim_init();

printf("[logo_test %s %d]libshowlogo Test start...\n",__FUNCTION__,__LINE__);

switch(test_item){
case 0:
show_boot_logo();
break;
case 1:
show_kernel_logo();
break;
case 2:
test_charging_animation(charging_item);
break;
case 3:
show_boot_logo();
sleep(2);
show_kernel_logo();
sleep(2);
show_low_battery();
sleep(2);
show_charger_ov_logo();
sleep(2);
test_charging_animation(charging_item);
break;
default:
show_low_battery();
}
sleep(1);
anim_deinit();
return 0;
}

从代码可以看出来代码一共提供了两个接口来显示图片,分别是fb(framebuff)与sf(surface flinger),此处对于sf不做深究,等以后有时间了在研究。跟踪代码发现,show_boot_logo,show_kernel_logo,test_charging_animation,最终都是调用了函数anim_show_logo于是,简化代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ctype.h>
#include <utils/Log.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/stat.h>
#include <sys/types.h>

int index = 0;

int main(int argc, char* argv[])
{
//logo显示初始化
set_draw_mode(DRAW_ANIM_MODE_FB);
set_anim_version(VERION_NEW_ANIMATION);
anim_init(); // 获取 logo 相关地址以及映射 framebuffer 地址等

//向 fb 写入对应的图片,同时显示该图片
anim_show_logo(index);

//释放init获取的数据结构
sleep(1);
anim_deinit();

return 0;
}

运行上述代码就能显示索引为 index 的图片,图片是怎么索引的呢?后文给出答案

在路径 /vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo 下有很多logo 文件存放不同分辨率的图片

他们之间的区别就是分辨率不同,我们选择使用的文件是和我们lcd屏分辨率相同的,如果logo的分辨率和lcd的分辨率对不上开机就会出现显示不全或者显示位置不对的问题。怎么确定每个文件的分辨率,一般有两个方法,复制其中的文件名直接百度,二就是用画图工具打开,看分辨率如下

图片的下面一行显示了图片的分辨率为1080x1920,这个也是lcd的分辨率,如果已有的分辨率的图片没有和lcd相符合的怎么办呢,方法很简单,就是复制一份现有的,然后用画图工具,修改分辨率为自己需要的的就好了,当然了别忘了重命名。文件名是很重要的,代码就是通过文件名来找到对应的图片文件对其进行编译。
怎么使用这里面的文件呢,分别在lk和device配置 BOOT_LOGO 这个宏:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/vendor/mediatek/proprietary/bootable/bootloader/lk/project/tb8768tp1_64_bsp.mk //路径

//省略部分内容
......
BOOT_LOGO := wxga //配置为要用到的logo文件夹名称
DEBUG := 2
#DEFINES += WITH_DEBUG_DCC=1
DEFINES += WITH_DEBUG_UART=1
......

配置device

```c
/device/mediateksample/tb8768p1_64_bsp/ProjectConfig.mk //路径

//省略部分内容
......
BOOT_LOGO = wxga //配置为要用到的logo文件夹
BUILD_AGO_GMS = no
BUILD_KERNEL = yes
BUILD_LK = yes
BUILD_MD32 = no
BUILD_MTK_SDK =
......

device和lk要同时配置成一样的,如果没有配成一样的也没关系,编译器会告诉你,编译会报错。这里的配置决定了使用哪个文件夹的图片,上述配置使用的是 wxga

1
2
3
make lk -j8 //安卓9编译方式

make vnd_images //安卓11编译方式

3、新增自己的图片

如果我想显示一张里面没有的图片怎么新增呢,首先将我们要的图片做好,然后分辨率改成lcd相同的分辨率放入文件中

图中 wxga_updata.bmp 为新增的图片,增加了图片还需要编译到它,在rules.mk 进行配置

1
/vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo/rules.mk

直接附上文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
LOCAL_DIR := $(GET_LOCAL_DIR)
BOOT_LOGO_DIR := $(LOCAL_DIR)

#fix no boot_logo config
#LOCAL_CFLAGS += -DBOOT_LOGO=wvga

ifeq ($(strip $(BOOT_LOGO)),)
BOOT_LOGO = fwvga
endif

ifeq ($(strip $(MTK_LK_CAMERA_SUPPORT)), yes)
BOOT_LOGO = fhd
endif

$(info BOOT_LOGO = $(BOOT_LOGO))
$(info lk/logo/dir=$(LOCAL_DIR),builddir=$(BUILDDIR))

ifeq ($(HOST_OS),darwin)
BMP_TO_RAW := $(BOOT_LOGO_DIR)/tool/bmp_to_raw.darwin
ZPIPE := $(BOOT_LOGO_DIR)/tool/zpipe.darwin
MKIMG := $(LOCAL_DIR)/../../scripts/mkimage.darwin
else
BMP_TO_RAW := $(BOOT_LOGO_DIR)/tool/bmp_to_raw
ZPIPE := $(BOOT_LOGO_DIR)/tool/zpipe
MKIMG := $(LOCAL_DIR)/../../scripts/mkimage
endif
IMG_HDR_CFG := $(LOCAL_DIR)/img_hdr_logo.cfg

EMPTY :=
UNDER_LINE := _
TEMP := $(strip $(subst $(UNDER_LINE), $(EMPTY), $(BOOT_LOGO)))
COUNT := $(words $(TEMP))
BASE_LOGO := $(word $(COUNT),$(TEMP))
EXIST := $(shell if [ -e $(BOOT_LOGO_DIR)/$(BASE_LOGO) ]; then echo "exist"; else echo "noexist"; fi;)
ifeq ($(EXIST), "noexist")
BASE_LOGO := $(BOOT_LOGO)
endif

SUPPORT_PUMP_EXPRESS = no
ifeq ($(strip $(MTK_PUMP_EXPRESS_SUPPORT)), yes)
SUPPORT_PUMP_EXPRESS = yes
else
ifeq ($(strip $(MTK_PUMP_EXPRESS_PLUS_SUPPORT)), yes)
SUPPORT_PUMP_EXPRESS = yes
endif
endif

BOOT_LOGO_RESOURCE := $(BUILDDIR)/$(BOOT_LOGO_DIR)/$(BOOT_LOGO).raw
LOGO_IMAGE := $(BUILDDIR)/logo.bin

SUPPORT_PROTOCOL1_RAT_CONFIG = no
SUPPORT_CARRIEREXPRESS_PACK = no
ifdef MTK_CARRIEREXPRESS_PACK
ifneq ($(strip $(MTK_CARRIEREXPRESS_PACK)), no)
SUPPORT_CARRIEREXPRESS_PACK = yes
RAT_CONFIG = $(strip $(MTK_PROTOCOL1_RAT_CONFIG))
ifneq (,$(RAT_CONFIG))
ifneq (,$(findstring L,$(RAT_CONFIG)))
SUPPORT_PROTOCOL1_RAT_CONFIG = yes
endif
endif
endif
endif

ifeq ($(strip $(SUPPORT_CARRIEREXPRESS_PACK)),yes)
RESOLUTION := $(word $(COUNT),$(TEMP))
RESOURCE_OBJ_LIST := \
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_uboot.raw //第1张图片
else
RESOURCE_OBJ_LIST := \
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_uboot.raw //第1张图片
endif

ifneq ($(strip $(MACH_TYPE)), 2701)
ifneq ($(strip $(MTK_ALPS_BOX_SUPPORT)), yes)
RESOURCE_OBJ_LIST += \
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_battery.raw \ // 第2张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_low_battery.raw \ // 第3张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_charger_ov.raw \ // 第4张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_0.raw \ // 第5张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_1.raw \ // 第6张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_2.raw \ // 第7张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_3.raw \ // 第8张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_4.raw \ // 第9张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_5.raw \ // 第10张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_6.raw \ // 第11张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_7.raw \ // 第12张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_8.raw \ // 第13张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_9.raw \ // 第14张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_num_percent.raw \ // 第15张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_01.raw \ // 第16张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_02.raw \ // 第17张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_03.raw \ // 第18张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_04.raw \ // 第19张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_05.raw \ // 第20张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_06.raw \ // 第21张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_07.raw \ // 第22张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_08.raw \ // 第23张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_09.raw \ // 第24张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_animation_10.raw \ // 第25张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_01.raw \ // 第26张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_02.raw \ // 第27张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_03.raw \ // 第28张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_04.raw \ // 第29张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_05.raw \ // 第30张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_06.raw \ // 第31张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_07.raw \ // 第32张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_08.raw \ // 第33张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_09.raw \ // 第34张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_10_10.raw \ // 第35张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_bg.raw \ // 第36张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_img.raw \ // 第37张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_bat_100.raw // 第39张
ifeq ($(strip $(SUPPORT_CARRIEREXPRESS_PACK)),yes)
RESOURCE_OBJ_LIST += \
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_kernel.raw //第39张
else
RESOURCE_OBJ_LIST += \
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_kernel.raw //第39张
endif

RESOURCE_OBJ_LIST += \
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_low_battery01.raw \ //第40张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_low_battery02.raw \ //第41张
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_low_battery_remind.raw //第42张
endif

RESOURCE_OBJ_LIST += \
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_updata.raw \ //第43张,后面省略
$(BOOT_LOGO_DIR)/$(BASE_LOGO)/$(BASE_LOGO)_power_off.raw
endif
......

上面有两个第1张和39张,这两个是二选一,最终只会编译一个,可以看见我将新增的图片放在第43张,图片的顺序就是参数index的值,因此index就为42(index是从0开始的因此第一张图片是index 0)。为什么把图片放在这个位置,因为后面的图片,我这个项目用不着,不会影响前面图片的显示。自己添加的图片尽量加在最后面,这样不会影响前面的图片显示。显示新增的图片代码应该如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ctype.h>
#include <utils/Log.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/stat.h>
#include <sys/types.h>

int main(int argc, char* argv[])
{
//logo显示初始化
set_draw_mode(DRAW_ANIM_MODE_FB);
set_anim_version(VERION_NEW_ANIMATION);
anim_init();

//显示索引index的图片
anim_show_logo(42); //这里的42就是我们新增的图片了

//释放init获取的数据结构
sleep(1);
anim_deinit();

return 0;
}

注:我们如果要替换里面的图片,一定要删除 out 目录下已经生成的图片bin文件,可能不会生效,重新编译才会生效!!!。

4、调用简单分析

对于这个anim_show_logo函数最终是怎么显示图片的呢,我们知道想让lcd显示图片只需将图片写入framebuff,soc的lcd控制器就会帮我们将图片显示出来,对于 anim_show_logo fb调用链如下所示

1
2
3
4
5
6
7
anim_show_logo->
fill_animation_logo->
这里省略中间调用最后会调用内核的
mtkfb_pan_display_proxy->
mtkfb_pan_display_impl->
primary_display_trigger->
primary_display_trigger_nolock //这个函数

对于sf的调用链

1
2
3
4
anim_show_logo->
这里省略中间调用最后会调用内核的
primary_display_frame_cfg->
primary_display_trigger_nolock //这个函数

中间省略是因为水平有限,懒得跟代码,我们发现无论是fb 还是 sf显示最终都调用了primary_display_trigger_nolock 这个函数,这个函数的路径

1
/kernel-4.9/drivers/misc/mediatek/video/mt6765/videox/primary_display.c

关于充电动画的文件路径

1
/vendor/mediatek/proprietary/external/libshowlogo/show_animation_common.c

5、源码阅读

源码阅读不排版当手册用

1) LCM_SCREEN_T

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// dedfine the LCM SCREEM parameters
typedef struct {
int width;
int height;
int bits_per_pixel; // 每个像素多少 bpp ,单位 bit
int rotation; // phical screen rotation:0 , 90, 180, 270
int needAllign; // if need adjust the width or height with 32: no need (0), need (1)
int allignWidth;
int need180Adjust; // if need adjust the drawing logo for 180 roration: no need (0), need (1)
int fb_size;
int fill_dst_bits;
int red_offset; // if red_offset is 0: logo use format BGR565 or ABGR8888, red_offset is 11/16: RGB565, ARGB8888
int blue_offset; // if blue_offset is 11/16: logo use format BGR565 or ABGR8888, blue_offset is 0: RGB565, ARGB8888
} LCM_SCREEN_T;

2) anim_logo_init

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
void anim_logo_init(void)
{
// read and de-compress logo data here
int fd = 0;
int len = 0;
Fstab fstab;

if (!ReadDefaultFstab(&fstab)) {
if (MTK_LOG_ENABLE == 1) {
SLOGE("failed to open fstab\n");
}
error_flag = 1;
return;
}

auto rec = GetEntryForMountPoint(&fstab, LOGO_MNT_POINT);
if (rec == nullptr) {
if (MTK_LOG_ENABLE == 1) {
SLOGE("failed to get entry for %s\n", LOGO_MNT_POINT);
}
error_flag = 1;
return;
}

// "rec->blk_device" is the path
printf("rec->blk_device: %s\n",rec->blk_device.c_str()); // 获取 logo 的设备路径
fd = open(rec->blk_device.c_str(), O_RDONLY); // 打开 logo 文件是一个块设备
// get logo patition from fstab end
if(fd < 0)
{
if (MTK_LOG_ENABLE == 1) {
SLOGE("[libshowlogo: %s %d]open logo partition device file fail, errno = %d \n",__FUNCTION__,__LINE__ , errno);
}
goto error_return;
}

//申请 logo 需要的内存空间
logo_addr = (unsigned int*)malloc(LOGO_BUFFER_SIZE);
if(logo_addr == NULL)
{
if (MTK_LOG_ENABLE == 1) {
SLOGE("[libshowlogo: %s %d]allocate logo buffer fail, size=0x%08x \n",__FUNCTION__,__LINE__ , LOGO_BUFFER_SIZE);
}
goto error_return;
}

// (1) skip the image header 读取头部信息
len = read(fd, logo_addr, 512);
if (len < 0)
{
if (MTK_LOG_ENABLE == 1) {
SLOGE("[libshowlogo: %s %d]read from logo addr for 512B is failed! \n",__FUNCTION__,__LINE__);
}
goto error_return;
}
// get the image //获取照片
len = read(fd, logo_addr, LOGO_BUFFER_SIZE - 512);
if (len < 0)
{
if (MTK_LOG_ENABLE == 1) {
SLOGE("[libshowlogo: %s %d]read from logo addr for buffer is failed! \n",__FUNCTION__,__LINE__);
}
goto error_return;
}
close(fd);

if (show_animationm_ver > 0)
{
unsigned int *pinfo = (unsigned int*)logo_addr;
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]pinfo[0]=%d, pinfo[1]=%d\n", __FUNCTION__,__LINE__, pinfo[0], pinfo[1]);
}

if ((show_animationm_ver == VERION_WIRELESS_CHARGING_ANIMATION) && (pinfo[0] < ANIM_V2_LOGO_NUM))
{
set_anim_version(VERION_NEW_ANIMATION);
}
if (pinfo[0] < ANIM_V1_LOGO_NUM)
{
kernel_logo_position = ANIM_V0_LOGO_NUM - 1;
set_anim_version(VERION_OLD_ANIMATION);
}
}
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]show_animationm_ver = :%d",__FUNCTION__,__LINE__ ,show_animationm_ver);
}
return;

error_return:
if(fd >= 0)
{
close(fd);
}
free_fstab();
sleep(3);
error_flag = 1;
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d] error return !!!\n",__FUNCTION__,__LINE__);
}
// to prevent interlace operation with MD reset
}

3) anim_fb_init

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

int anim_fb_init(void)
{
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]\n",__FUNCTION__,__LINE__);
}

fb_fd = open(FB_NODE_PATH, O_RDWR);
if(fb_fd < 0)
{
if (MTK_LOG_ENABLE == 1) {
SLOGE("[libshowlogo: %s %d]open dev file fail, errno = %d \n",__FUNCTION__,__LINE__ , errno);
}
close(fb_fd);
error_flag = 1;

return -1;
}

// 返回 lcd 可变信息
ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);
// 返回 lcd 固定信息
ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);

// 计算fb 的大小
fb_size = finfo.line_length * vinfo.yres;
//分配内存空间
dec_logo_addr = (unsigned int*) malloc(fb_size);

// 将屏幕缓冲区映射到用户空间
lk_fb_addr =(unsigned int*)mmap(0, fb_size*3, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);

// 第一帧地址用于显示 charging
charging_fb_addr = (unsigned int*)((unsigned int)lk_fb_addr + fb_size);
// 第二帧地址用于显示 kernel_fb_addr
kernel_fb_addr = (unsigned int*)((unsigned int)charging_fb_addr + fb_size);
fb_addr = lk_fb_addr;

if (MTK_LOG_ENABLE == 1) { // debug
SLOGD("[libshowlogo: %s %d]vinfo:xres = %d, yres = %d, xres_virtual =%d, bits_per_pixel = %d,red.offset = %d,blue.offset = %d\n"
,__FUNCTION__, __LINE__, vinfo.xres,vinfo.yres, vinfo.xres_virtual, vinfo.bits_per_pixel,vinfo.red.offset,vinfo.blue.offset);

SLOGD("[libshowlogo: %s %d]fb_size =%d, fb_addr = %d,charging_fb_addr=%d\n"
,__FUNCTION__, __LINE__, fb_size,( int)fb_addr, (int)charging_fb_addr);
}

if(fb_addr == NULL || charging_fb_addr == NULL)
{
if (MTK_LOG_ENABLE == 1) {
SLOGE("ChargingAnimation mmap fail\n");
}
munmap(lk_fb_addr, fb_size*2);
close(fb_fd);
error_flag = 1;

return -1;
}

//获取对应的 lcm 参数
phical_screen.bits_per_pixel = vinfo.bits_per_pixel; // 每个像素多少 bpp ,单位 bit
phical_screen.fill_dst_bits = vinfo.bits_per_pixel; // 每个像素多少 bpp ,单位 bit
phical_screen.red_offset = vinfo.red.offset; // 红色像素偏移位置
phical_screen.blue_offset = vinfo.blue.offset; // 蓝色像素偏移位置

phical_screen.width = vinfo.xres; // 屏幕一行有多少个像素点
phical_screen.height = vinfo.yres; // 屏幕一列有多少个像素点

//每一行的像素个数
phical_screen.allignWidth = finfo.line_length/(vinfo.bits_per_pixel/8);

phical_screen.needAllign = 1;
phical_screen.need180Adjust = 1;

//一帧图片的大小
phical_screen.fb_size = fb_size;
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]MTK_LCM_PHYSICAL_ROTATION = %s\n",__FUNCTION__,__LINE__, MTK_LCM_PHYSICAL_ROTATION);
}

int rotation = getRotation(); //获取屏幕旋转多少度
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]rotation = %d\n",__FUNCTION__,__LINE__, rotation);
}

if(ORIENTATION_270 == rotation){//270
phical_screen.rotation = 270;
} else if(ORIENTATION_90 == rotation){//90
phical_screen.rotation = 90;
} else if((ORIENTATION_180 == rotation) && (phical_screen.need180Adjust == 1)){//180
phical_screen.rotation = 180;
} else {
phical_screen.rotation = 0;
}
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo]phical_screen: width= %d,height= %d,bits_per_pixel =%d,needAllign = %d,allignWidth=%d rotation =%d ,need180Adjust = %d\n",
phical_screen.width, phical_screen.height,
phical_screen.bits_per_pixel, phical_screen.needAllign,
phical_screen.allignWidth, phical_screen.rotation, phical_screen.need180Adjust);
SLOGD("[libshowlogo: %s %d]show old animtion= 1, running show_animationm_ver %d\n",__FUNCTION__,__LINE__, show_animationm_ver);
SLOGD("[libshowlogo: %s %d]draw_anim_mode = 1, running mode %d\n",__FUNCTION__,__LINE__, draw_anim_mode);
}

return 0;
}

4) anim_set_buffer_address

1
2
3
4
5
6
7
8
9
10
void anim_set_buffer_address(int index)
{
if (index == BOOT_LOGO_INDEX) {
fb_addr = lk_fb_addr;
} else if (index == kernel_logo_position) {
fb_addr = kernel_fb_addr;
} else {
anim_fb_addr_switch();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void anim_show_logo(int index)
{
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]draw_anim_mode=%d, show index = %d\n",__FUNCTION__,__LINE__,draw_anim_mode,index);
}

if (draw_anim_mode == (DRAW_ANIM_MODE_FB)) {
anim_set_buffer_address(index); // 获取显存地址
fill_animation_logo(index, fb_addr, dec_logo_addr, logo_addr,phical_screen);
anim_fb_disp_update();
} else {
ARect tmpRect;
tmpRect.left = 0;
tmpRect.top = 0;
tmpRect.right = phical_screen.width;
tmpRect.bottom = phical_screen.height;

status_t lockResult = surface->lock(&outBuffer, &tmpRect);
if (MTK_LOG_ENABLE == 1) {
SLOGD("[libshowlogo: %s %d]outBuffer.bits = %d\n",__FUNCTION__,__LINE__, (int)outBuffer.bits);
SLOGD("[libshowlogo: %s %d]surface->lock return = 0x%08x, %d\n",__FUNCTION__,__LINE__,lockResult,lockResult);
}
if (0 == lockResult)
{
fill_animation_logo(index, (void *)outBuffer.bits, dec_logo_addr, logo_addr,phical_screen);
surface->unlockAndPost();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// index 图片索引
// fill_addr 显存地址
// dec_logo_addr
// logo_addr logo.bin 的数据首地址
// phical_screen 内核 获取的 lcd 的信息
void fill_animation_logo(int index, void *fill_addr, void * dec_logo_addr, void * logo_addr, LCM_SCREEN_T phical_screen)
{
LOGO_PARA_T logo_info;
int logo_width;
int logo_height;
int raw_data_size;
int logo_index = index;
int logo_offset = -1;
g_dec_logo_addr = dec_logo_addr;

logo_offset = calculate_logo_offset(index, dec_logo_addr, logo_addr, phical_screen);
if(logo_offset == -1){
SLOGD("[calculate_logo_offset: %s %d]Resolution not supported\n",__FUNCTION__,__LINE__);
return;
}
// 计算要显示的图片索引
logo_index = logo_index + logo_offset;
if(check_logo_index_valid(logo_index, logo_addr, &logo_info) != CHECK_LOGO_BIN_OK)
return;

// 将图片解压缩
// logo_info.inaddr 解压缩前图片地址
// dec_logo_addr 解压缩后图片地址
// logo_info.logolen 解压缩前图片长度
// phical_screen.fb_size 解压缩后图片长度
raw_data_size = decompress_logo((void*)logo_info.inaddr, dec_logo_addr, logo_info.logolen, phical_screen.fb_size);
if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_animation_common: %s %d]raw_data_size = %d\n",__FUNCTION__,__LINE__, raw_data_size);
}
//RECT_REGION_T rect = {0, 0, phical_screen.width, phical_screen.height};
logo_width =phical_screen.width;
logo_height = phical_screen.height;

// 如果旋转图片则交换长宽位置
if (phical_screen.rotation == 270 || phical_screen.rotation == 90) {
logo_width = phical_screen.height;
logo_height = phical_screen.width;
}

// 计算每一个像素需要的 bit
if (0 == bits) {
if (raw_data_size == logo_width*logo_height*4) {
bits = 32;
} else if (raw_data_size == logo_width*logo_height*2) {
bits = 16;
} else {
if (MTK_LOG_ENABLE == 1) {
SLOGE("[show_animation_common: %s %d]Logo data error\n",__FUNCTION__,__LINE__);
}
return;
}
if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_animation_common: %s %d]bits = %d\n",__FUNCTION__,__LINE__, bits);
}
}

//设置显示区域大小
RECT_REGION_T rect = {0, 0, logo_width, logo_height};

// 将数据填充到 fb 显示图片
fill_rect_with_content(fill_addr, rect, dec_logo_addr, phical_screen, bits);
}

7) fill_rect_with_content

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void fill_rect_with_content(void *fill_addr, RECT_REGION_T rect, void *src_addr, LCM_SCREEN_T phical_screen, unsigned int bits)
{
if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_logo_common: %s %d]\n",__FUNCTION__,__LINE__);
}
if (check_rect_valid(rect) != CHECK_RECT_OK)
return;
if (bits == 32) { //32 位
if (phical_screen.fill_dst_bits == 16) { // fb 每个像素需要16bit
fill_rect_with_content_by_16bit_argb8888((unsigned short *)fill_addr, rect, (unsigned int *)src_addr, phical_screen);
} else if (phical_screen.fill_dst_bits == 32){ //// fb 每个像素需要16bit
fill_rect_with_content_by_32bit_argb8888((unsigned int *)fill_addr, rect, (unsigned int *)src_addr, phical_screen, bits);
} else {
if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_logo_common %s %d]unsupported phical_screen.fill_dst_bits =%d\n",__FUNCTION__,__LINE__, phical_screen.fill_dst_bits );
}
}
} else {
if (phical_screen.fill_dst_bits == 16) {
fill_rect_with_content_by_16bit_rgb565((unsigned short *)fill_addr, rect, (unsigned short *)src_addr, phical_screen);
} else if (phical_screen.fill_dst_bits == 32){
fill_rect_with_content_by_32bit_rgb565((unsigned int *)fill_addr, rect, (unsigned short *)src_addr, phical_screen, bits);
} else {
if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_logo_common %s %d]unsupported phical_screen.fill_dst_bits =%d\n",__FUNCTION__,__LINE__, phical_screen.fill_dst_bits );
}
}
}
}

8) fill_rect_with_content_by_32bit_argb8888

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void fill_rect_with_content_by_32bit_argb8888(unsigned int *fill_addr, RECT_REGION_T rect, unsigned int *src_addr, LCM_SCREEN_T phical_screen, unsigned int bits)
{
if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_logo_common: %s %d]\n",__FUNCTION__,__LINE__);
}

int virtual_width = phical_screen.needAllign == 0? phical_screen.width:phical_screen.allignWidth;
int virtual_height = phical_screen.height;

int i = 0;
int j = 0;

unsigned int * dst_addr = fill_addr; // 要填充的显存地址
unsigned int * color_addr = src_addr; // 要显示的图片地址

// left, top, right, bottom
// RECT_REGION_T rect = {0, 0, logo_width, logo_height};

// 0 - logo_height
for(i = rect.top; i < rect.bottom; i++)
{
// 0 - logo_width
for(j = rect.left; j < rect.right; j++) // 逐行显示
{
color_addr = (unsigned int *)src_addr; // 获取要显示的地址
src_addr++;
switch (phical_screen.rotation)
{
case 90:
dst_addr = fill_addr + (virtual_width * j + phical_screen.width - i - 1);
break;
case 270:
dst_addr = fill_addr + ((virtual_width * (virtual_height - j - 1)+ i));
break;
case 180:
// adjust fill in address
dst_addr = fill_addr + virtual_width * (virtual_height - i)- j-1-(virtual_width-phical_screen.width);
break;
default:
dst_addr = fill_addr + virtual_width * i + j;
}
fill_point_buffer(dst_addr, *color_addr, phical_screen, bits);
if((i == rect.top && j == rect.left) || (i == rect.bottom - 1 && j == rect.left) ||
(i == rect.top && j == rect.right - 1) || (i == rect.bottom - 1 && j == rect.right - 1)){
if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_logo_common]dst_addr= 0x%08x, color_addr= 0x%08x, i= %d, j=%d\n", *dst_addr, *color_addr, i , j);
}
}
}
}
}

9) fill_point_buffer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void fill_point_buffer(unsigned int *fill_addr, unsigned int src_color, LCM_SCREEN_T phical_screen, unsigned int bits)
{
if (32 == phical_screen.bits_per_pixel) {
if (32 == bits) {
if(16 == phical_screen.blue_offset) {
*fill_addr = ARGB8888_TO_ABGR8888(src_color);
} else {
*fill_addr = src_color;
}
} else {
if(16 == phical_screen.blue_offset) {
*fill_addr = RGB565_TO_ARGB8888(src_color);
} else {
*fill_addr = RGB565_TO_ABGR8888(src_color);
}
}
} else {
if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_logo_common %s %d]not support bits_per_pixel = %d \n",__FUNCTION__,__LINE__,(int)phical_screen.bits_per_pixel);
}
}
}

10) calculate_logo_offset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// index 图片索引
// dec_logo_addr 图片解压缩后的图片地址
// logo_addr logo.bin 的数据首地址
// phical_screen 内核获取的屏参数
// 返货图片索引的偏移位置
int calculate_logo_offset(unsigned int index, void * dec_logo_addr, void * logo_addr, LCM_SCREEN_T phical_screen)
{
LOGO_PARA_T logo_info;
int logo_width = phical_screen.width;
int logo_height = phical_screen.height;
int raw_data_size;
unsigned int *pinfo;
int logo_index = index;
int total_logo_entries = 0;
if(logo_offset != -1)
return logo_offset;

// 获取 logo.bin 的数据首地址
pinfo = (unsigned int*)logo_addr;
logo_offset = 0;
total_logo_entries = get_total_logo_images_entries(); // 获取 logo 的长度
SLOGD("[calculate_logo_offset: %s %d]pinfo[0] = %d\n",__FUNCTION__,__LINE__, pinfo[0]); // 打印所有的图片有多少张

SLOGD("[calculate_logo_offset: %s %d]TOTAL_LOG0_COUNT = %d , initial index = %d\n",__FUNCTION__,__LINE__, total_logo_entries, logo_index);

while(logo_index < pinfo[0]){ //如果显示的索引是否小于图片数量

// logo_info->logonum 获取图片数量
// logo_info->logolen 获取要显示的图片长度
// logo_info->inaddr 获取要显示的图片的地址
if(check_logo_index_valid(logo_index, logo_addr, &logo_info) != CHECK_LOGO_BIN_OK){
SLOGD("[calculate_logo_offset: %s %d][Error]Resolution not supported",
__FUNCTION__,__LINE__);
logo_offset = -1;
return -1;
}

// 将图片解压缩
// logo_info.inaddr 解压缩前图片地址
// dec_logo_addr 解压缩后图片地址
// logo_info.logolen 解压缩前图片长度
// phical_screen.fb_size 解压缩后图片长度
raw_data_size = decompress_logo((void*)logo_info.inaddr, dec_logo_addr, logo_info.logolen,phical_screen.fb_size);

SLOGD("[calculate_logo_offset: %s %d]Width = %d\n Height = %d\n raw_data_size = %d\n logo_index = %d\n",
__FUNCTION__,__LINE__, logo_width, logo_height, raw_data_size, logo_index);

//获取每个像素的像素点
if (raw_data_size == logo_width*logo_height*4) {
bits = 32;
break;
} else if (raw_data_size == logo_width*logo_height*2) {
bits = 16;
break;
} else {
logo_offset += total_logo_entries;// Add number of logos entries
logo_index += total_logo_entries;
}

SLOGD("[calculate_logo_offset: %s %d]bits = %d\n",__FUNCTION__,__LINE__, bits);
SLOGD("[calculate_logo_offset: %s %d]logo_offset = %d logo_index = %d\n",__FUNCTION__,__LINE__, logo_offset,logo_index);
}

SLOGD("[calculate_logo_offset: %s %d] final logo_offset = %d logo_index = %d\n",__FUNCTION__,__LINE__, logo_offset,logo_index);
return logo_offset;
}

11) check_logo_index_valid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
* Check logo.bin address if valid, and get logo related info
* pinfo[0] : the number of all pictures in logo.bin
* pinf0[1] : the whole length of logo.bin
* pinf0[2] : the index = 0 picture's length
* pinfo[3+index] - pinfo[2+index] : means index length
*/
int check_logo_index_valid(int index, void * logo_addr, LOGO_PARA_T *logo_info)
{
unsigned int *pinfo = (unsigned int*)logo_addr;
logo_info->logonum = pinfo[0]; // 获取图片数量

if (MTK_LOG_ENABLE == 1) {
SLOGD("[show_animation_common: %s %d]logonum =%d, index =%d\n", __FUNCTION__,__LINE__,logo_info->logonum, index);
}

if (index >= logo_info->logonum)
{
if (MTK_LOG_ENABLE == 1) {
SLOGE("[show_animation_common: %s %d]unsupported logo, index =%d\n", __FUNCTION__,__LINE__, index);
}
return CHECK_LOGO_BIN_ERROR;
}

if(index < logo_info->logonum - 1) {
logo_info->logolen = pinfo[3+index] - pinfo[2+index]; // 获取要显示的图片长度
if (MTK_LOG_ENABLE == 1) {
SLOGD("show_animation_common, pinfo[1]=%d, pinfo[3+index] - pinfo[2+index]= %d\n",
pinfo[1], pinfo[3+index] - pinfo[2+index]);
}
}
else {
logo_info->logolen = pinfo[1] - pinfo[2+index]; // 获取要显示的图片长度
if (MTK_LOG_ENABLE == 1) {
SLOGD("show_animation_common, pinfo[1]=%d, pinfo[1] - pinfo[2+index] =%d \n",
pinfo[1], pinfo[1] - pinfo[2+index]);
}
}

// 获取要显示的图片的地址
logo_info->inaddr = (unsigned int)logo_addr + pinfo[2+index];
if (MTK_LOG_ENABLE == 1) {
SLOGD("show_animation_common, logo_addr=0x%08x , in_addr=0x%08x, logolen=%d\n",
(unsigned int)logo_addr, logo_info->inaddr, logo_info->logolen);
}
return CHECK_LOGO_BIN_OK;
}

13) get_total_logo_images_entries

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int get_total_logo_images_entries(void)
{
int total_logo_entries = 0;
total_logo_entries = LOGOS_COUNT_NORMAL;
int to_include_fast_charging = getValue("ro.vendor.mtk_pump_express_plus_support" , "0");
/*
#if defined(MTK_PUMP_EXPRESS_SUPPORT) || defined(MTK_PUMP_EXPRESS_PLUS_SUPPORT) || defined(MTK_PUMP_EXPRESS_PLUS_20_SUPPORT)
total_logo_entries += LOGOS_COUNT_FAST_CHARGING;
#endif
*/
if(to_include_fast_charging == 1)
total_logo_entries += LOGOS_COUNT_FAST_CHARGING;
#if defined(MTK_WIRELESS_CHARGER_SUPPORT)
total_logo_entries += LOGOS_COUNT_WIRELESS;
#endif

SLOGD("[get_total_logo_images_entries: %s %d] total_logo_entries = %d to_include_fast_charging = %d\n",__FUNCTION__,__LINE__, total_logo_entries , to_include_fast_charging);
return total_logo_entries;
}

6、在屏上显示任意绘制点

看了这个源码我就想我能不能自己在屏上画出点,于是捯饬了一下,整理得到下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/input.h>


// use for nmap framebuffer
static unsigned int *fb_addr = NULL;

static unsigned int *lk_fb_addr = NULL;
static unsigned int *charging_fb_addr = NULL;
static unsigned int *kernel_fb_addr = NULL;
static unsigned int v_width = 0;

static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;

static unsigned int fb_size = 0;
int fb_fd = -1;

// 清屏函数,将屏幕颜色设置为 color
void clearScreen (unsigned int *pfb, unsigned int width, unsigned int height, unsigned int color)
{
unsigned int x, y;
printf("draw_back, %p , %d, %d\n",pfb , width, height);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
*(pfb + y * width + x) = color;
}
}
}

// 绘制对应的点
void draw_point(int x ,int y, int color)
{
int i = 0;
int j = 0;

printf("x: %d y: %d\n",x,y);

if(y > 2400) // 防止越界
y = 2400;

if(x > 1080) // 防止越界
x = 1080;

*(fb_addr + y * v_width + x) = color;
}

// 以 x , y 为中心绘制10x10的小方块
void drawCube (int x, int y)
{
int i = 0;
int j = 0;
int xmin = x-10;
int xmax = x+10;
int ymin = y-10;
int ymax = y+10;

if(xmin < 0)
xmin = 0;
if(ymin < 0)
ymin = 0;

for(i = ymin; i< ymax; i++)
{
for(j = xmin; j < xmax; j++)
{
draw_point(j,i,0xFF);
}

}
}

// 初始化 fb 相关信息
int myFbInit(void)
{
//unsigned int color = 0;
fb_fd = open("/dev/graphics/fb0", O_RDWR);
if(fb_fd < 0)
{
printf("fb open err\n");
close(fb_fd);
return -1;
}

ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);
ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);

fb_size = finfo.line_length * vinfo.yres;

// 映射对应的显存到用户空间
lk_fb_addr =(unsigned int*)mmap(0, fb_size*3, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);

charging_fb_addr = (unsigned int*)((unsigned int)lk_fb_addr + fb_size);

kernel_fb_addr = (unsigned int*)((unsigned int)charging_fb_addr + fb_size);

fb_addr = charging_fb_addr;

// 计算出显示区域的宽度
v_width = finfo.line_length/(vinfo.bits_per_pixel/8);

return 0;
}

// 告诉内核刷新 fb
void fbShow()
{

if (fb_addr == charging_fb_addr) {
vinfo.yoffset = vinfo.yres;
} else if (fb_addr == kernel_fb_addr) {
vinfo.yoffset = vinfo.yres * 2;
} else {
vinfo.yoffset = 0;
}

vinfo.activate |= (FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW);
if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0)
{
printf("ioctl FBIOPUT_VSCREENINFO flip failed\n");
}

}

int main(int argc, char **argv)
{

myFbInit();

// 清屏
clearScreen(fb_addr, vinfo.xres, vinfo.yres, 0xFF0000);

// 在 300,300 处画个 10x10 小方块
drawCube(300,300,0xFF);

//刷新 fb 显示
fbShow();

munmap(lk_fb_addr, fb_size*2); // 释放映射的内存空间
close(fb_db);

return 0;
}

这个代码验证有问题,原因就是安卓也在刷图会将我的图刷掉,于是为了简单直接如下操作

1
2
3
4
5
6
7
8
9
10
11
int primary_display_frame_cfg(struct disp_frame_cfg_t *cfg)
{

int ret = 0;
return ret; // 啥也不干直接返回

s_info = disp_get_session_sync_info_for_debug(cfg->session_id);
if (s_info) {
input_event = &s_info->event_setinput;

}

于是再次验证就可以了。

7、在屏幕上面绘制

利用 input 子系统就可以在屏幕上面进行绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/input.h>


// use for nmap framebuffer
static unsigned int *fb_addr = NULL;

static unsigned int *lk_fb_addr = NULL;
static unsigned int *charging_fb_addr = NULL;
static unsigned int *kernel_fb_addr = NULL;
static unsigned int v_width = 0;

static struct fb_var_screeninfo vinfo;
static struct fb_fix_screeninfo finfo;

static unsigned int fb_size = 0;
int fb_fd = -1;

// 清屏函数,将屏幕颜色设置为 color
void clearScreen (unsigned int *pfb, unsigned int width, unsigned int height, unsigned int color)
{
unsigned int x, y;
printf("draw_back, %p , %d, %d\n",pfb , width, height);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
*(pfb + y * width + x) = color;
}
}
}

// 绘制对应的点
void draw_point(int x ,int y, int color)
{
int i = 0;
int j = 0;

printf("x: %d y: %d\n",x,y);

if(y > 2400) // 防止越界
y = 2400;

if(x > 1080) // 防止越界
x = 1080;

*(fb_addr + y * v_width + x) = color;
}

// 以 x , y 为中心绘制10x10的小方块
void drawCube (int x, int y)
{
int i = 0;
int j = 0;
int xmin = x-10;
int xmax = x+10;
int ymin = y-10;
int ymax = y+10;

if(xmin < 0)
xmin = 0;
if(ymin < 0)
ymin = 0;

for(i = ymin; i< ymax; i++)
{
for(j = xmin; j < xmax; j++)
{
draw_point(j,i,0xFF);
}

}
}

// 初始化 fb 相关信息
int myFbInit(void)
{
//unsigned int color = 0;
fb_fd = open("/dev/graphics/fb0", O_RDWR);
if(fb_fd < 0)
{
printf("fb open err\n");
close(fb_fd);
return -1;
}

ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);
ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo);

fb_size = finfo.line_length * vinfo.yres;

// 映射对应的显存到用户空间
lk_fb_addr =(unsigned int*)mmap(0, fb_size*3, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);

charging_fb_addr = (unsigned int*)((unsigned int)lk_fb_addr + fb_size);

kernel_fb_addr = (unsigned int*)((unsigned int)charging_fb_addr + fb_size);

fb_addr = charging_fb_addr;

// 计算出显示区域的宽度
v_width = finfo.line_length/(vinfo.bits_per_pixel/8);

return 0;
}

// 告诉内核刷新 fb
void fbShow()
{

if (fb_addr == charging_fb_addr) {
vinfo.yoffset = vinfo.yres;
} else if (fb_addr == kernel_fb_addr) {
vinfo.yoffset = vinfo.yres * 2;
} else {
vinfo.yoffset = 0;
}

vinfo.activate |= (FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW);
if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0)
{
printf("ioctl FBIOPUT_VSCREENINFO flip failed\n");
}

}

int main(int argc, char **argv)
{
int fd;
struct input_event ev;
char name[80];
static int x = 0;
static int y = 0;

myFbInit();
clearScreen(fb_addr, vinfo.xres, vinfo.yres, 0xFF0000);

// 打开设备
fd = open("/dev/input/event5", O_RDWR);
if(fd < 0) {
printf("open err\n");
return 0;
}

ioctl(fd, EVIOCGNAME(sizeof(name) - 1), name);
printf("find device name = %s\n", name);

// 循环读取
while(1) {
// 读取数据
read(fd, &ev, sizeof(struct input_event));
// 打印当前触发类型
// printf("ev == %x \n",ev.type );
switch(ev.type) {
case EV_SYN:
// printf("-------------------------\n");
printf("do x: %d, y: %d\n",x,y);
drawCube(x,y);
fbShow();
break;

// 按键
case EV_KEY:
printf("key down / up: %d \n",ev.code );
break;

// 鼠标
case EV_REL:
// printf("mouse: ");
if (ev.code == REL_X) {
// printf(" x -- %d\n", ev.value);
} else if (ev.code == REL_Y) {
// printf(" y -- %d\n", ev.value);
}
break;

// 触摸屏
case EV_ABS:
//printf("ts: ");
if(ev.code == ABS_MT_POSITION_X) {
//printf(" x -- %d\n", ev.value);
x = ev.value;
} else if (ev.code == ABS_MT_POSITION_Y) {
// printf(" y -- %d\n", ev.value);
y = ev.value;
} else if (ev.code == ABS_PRESSURE) {
printf(" pressure: %d\n", ev.value);
}
break;
}
}

munmap(lk_fb_addr, fb_size*2); // 释放映射的内存空间

close(fd);
close(fb_fd);
return 0;
}

于是就可以在屏上画图了