1 /*
2 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3 */
4
5 #include <stdio.h>
6 #include <aos/kernel.h>
7 #include <errno.h>
8 #include <aos/vfs.h>
9 #include <string.h>
10 #include <fb.h>
11 #include <devicevfs/devicevfs.h>
12 #include <k_api.h>
13 // #include <k_shmm.h>
14
15 #define FBPIXMAPSIZE (1024 * 8)
16
17 fb_info_t *registered_fb[FB_MAX];
18 static int num_registered_fb = 0;
19 static aos_mutex_t fb_mutex;
20
21 static int fb_open(inode_t *inode, file_t *file);
22 static int fb_close(file_t *file);
23 static ssize_t fb_read(file_t *file, void *buf, size_t len);
24 static ssize_t fb_write(file_t *file, const void *buf, size_t len);
25 static int fb_ioctl(file_t *file, int cmd, unsigned long arg);
26
27 #ifdef CONFIG_AOS_MMAP_ENABLE
28 static void *fb_mmap(file_t *file, size_t size);
29 #endif
30
31 file_ops_t fb_fops = {
32 .open = fb_open,
33 .close = fb_close, // release
34 .read = fb_read,
35 .write = fb_write,
36 .ioctl = fb_ioctl,
37 #ifdef CONFIG_AOS_MMAP_ENABLE
38 .mmap = fb_mmap,
39 #endif
40 };
41
get_fb_info(char * path)42 static fb_info_t *get_fb_info(char *path)
43 {
44 int i = 0;
45 fb_info_t *fb_info;
46
47 if (path == NULL) {
48 printf("[%s]path is null\n", __func__);
49 return NULL;
50 }
51
52 for (i = 0; i < FB_MAX; i++) {
53 if (strlen(path) != strlen(registered_fb[i]->path))
54 continue;
55
56 if (strncmp(registered_fb[i]->path, path, strlen(path)) == 0)
57 break;
58 }
59
60 if (i >= FB_MAX)
61 return NULL;
62
63 if (aos_mutex_lock(&fb_mutex, AOS_WAIT_FOREVER) != 0) {
64 LOGE(FB_STR, "Failed to lock mutex (%s).", __func__);
65 return NULL;
66 }
67 fb_info = registered_fb[i];
68
69 aos_mutex_unlock(&fb_mutex);
70
71 return fb_info;
72 }
73
fb_open(inode_t * inode,file_t * file)74 static int fb_open(inode_t *inode, file_t *file)
75 {
76 fb_info_t *info;
77 int ret = 0;
78
79 info = get_fb_info(inode->i_name);
80 if (!info)
81 return -ENODEV;
82
83 lock_fb_info(info);
84 if (info->fbops->fb_open)
85 ret = info->fbops->fb_open(info, 1);
86
87 unlock_fb_info(info);
88
89 return ret;
90 }
91
file_fb_info(file_t * file)92 static fb_info_t *file_fb_info(file_t *file)
93 {
94 inode_t *inode = file_inode(file);
95 fb_info_t *info;
96
97 if (!inode)
98 return NULL;
99
100 info = get_fb_info(inode->i_name);
101 if (!info)
102 return NULL;
103
104 return info;
105 }
106
fb_read(file_t * file,void * buf,size_t len)107 static ssize_t fb_read(file_t *file, void *buf, size_t len)
108 {
109 fb_info_t *info = file_fb_info(file);
110 unsigned long total_size;
111
112 if (!info || !info->screen_base)
113 return -ENODEV;
114
115 if (info->state != FBINFO_STATE_RUNNING)
116 return -EPERM;
117
118 if (info->fbops->fb_read)
119 return info->fbops->fb_read(info, buf, len);
120
121 total_size = info->screen_size;
122
123 if (total_size == 0)
124 total_size = info->fix.smem_len;
125
126 if (len >= total_size)
127 len = total_size;
128
129 memcpy(buf, info->screen_base, len);
130
131 return len;
132 }
133
fb_write(file_t * file,const void * buf,size_t len)134 static ssize_t fb_write(file_t *file, const void *buf, size_t len)
135 {
136 fb_info_t *info = file_fb_info(file);
137
138 if (!info || !info->screen_base)
139 return -ENODEV;
140
141 if (info->fbops->fb_write)
142 return info->fbops->fb_write(info, buf, len);
143
144 if (!info->screen_base)
145 return -1;
146
147 memcpy(info->screen_base, buf, len);
148
149 return len;
150 }
151
fb_set_var(fb_info_t * info,fb_var_screeninfo_t * var)152 static int fb_set_var(fb_info_t *info, fb_var_screeninfo_t *var)
153 {
154 int32_t ret = 0;
155 memcpy(&info->var, var, sizeof(fb_var_screeninfo_t));
156
157 if (info->fbops->fb_set_par)
158 ret = info->fbops->fb_set_par(info);
159
160 return ret;
161 }
162
fb_pan_display(fb_info_t * info,fb_var_screeninfo_t * var)163 static int fb_pan_display(fb_info_t *info, fb_var_screeninfo_t *var)
164 {
165 fb_fix_screeninfo_t *fix = &info->fix;
166 uint32_t yres = info->var.yres;
167 int err = 0;
168
169 if (!var)
170 return -EINVAL;
171
172 if (var->xoffset > 0 && (!fix->xpanstep ||
173 (var->xoffset % fix->xpanstep)))
174 err = -EINVAL;
175
176 if (err || !info->fbops->fb_pan_display ||
177 var->yoffset > info->var.yres_virtual - yres ||
178 var->xoffset > info->var.xres_virtual - info->var.xres)
179 return -EINVAL;
180
181 err = info->fbops->fb_pan_display(var, info);
182 if (err != 0)
183 return err;
184 info->var.xoffset = var->xoffset;
185 info->var.yoffset = var->yoffset;
186
187 return 0;
188 }
189
fb_blank(fb_info_t * info,int blank)190 static int fb_blank(fb_info_t *info, int blank)
191 {
192 int ret = -EINVAL;
193
194 if (info->fbops->fb_blank)
195 ret = info->fbops->fb_blank(blank, info);
196
197 return ret;
198 }
199
printf_string(int cmd)200 static void printf_string(int cmd)
201 {
202 switch (cmd) {
203 case FBIOGET_VSCREENINFO:
204 printf("ioctl cmd : FBIOGET_VSCREENINFO\n");
205 break;
206 case FBIOPUT_VSCREENINFO:
207 // printf("ioctl cmd : FBIOPUT_VSCREENINFO\n");
208 break;
209 case FBIOGET_FSCREENINFO:
210 printf("ioctl cmd : FBIOGET_FSCREENINFO\n");
211 break;
212 case FBIOPAN_DISPLAY:
213 printf("ioctl cmd : FBIOPAN_DISPLAY\n");
214 break;
215 case FBIOPUT_PREFB_ADDR:
216 printf("ioctl cmd : FBIOPUT_PREFB_ADDR\n");
217 break;
218 // case FBIOPUT_PREFB_PARAMS:
219 // // printf("ioctl cmd: FBIOPUT_PREFB_PARAMS\n");
220 // break;
221 case FBIO_WAITFORVSYNC:
222 printf("ioctl cmd: FBIO_WAITFORVSYNC\n");
223 break;
224 case FBIOBLANK:
225 printf("ioctl cmd : FBIOBLANK\n");
226 break;
227 case FBIOPUT_BRIGHTNESS:
228 printf("ioctl cmd : FBIOPUT_BRIGHTNESS\n");
229 break;
230 case FBIOGET_BRIGHTNESS:
231 printf("ioctl cmd : FBIOGET_BRIGHTNESS\n");
232 break;
233 #ifdef CONFIG_BACKLIGHT_MODE_ENABLE
234 case FBIOENABLE_BACKLIGHT:
235 printf("ioctl cmd : FBIOENABLE_BACKLIGHT\n");
236 break;
237 case FBIODISABLE_BACKLIGHT:
238 printf("ioctl cmd : FBIODISABLE_BACKLIGHT\n");
239 break;
240 #endif
241 default:
242 // printf("ioctl cmd: unknown command\n");
243 break;
244 }
245 return;
246 }
247
fb_ioctl(file_t * file,int cmd,unsigned long arg)248 static int fb_ioctl(file_t *file, int cmd, unsigned long arg)
249 {
250 int ret = 0;
251 fb_info_t *info = file_fb_info(file);
252 fb_var_screeninfo_t var;
253
254 printf_string(cmd);
255
256 switch (cmd) {
257 case FBIOGET_VSCREENINFO:
258 lock_fb_info(info);
259 memcpy((void *)arg, &info->var, sizeof(fb_var_screeninfo_t));
260 unlock_fb_info(info);
261 break;
262 case FBIOPUT_VSCREENINFO:
263 lock_fb_info(info);
264 ret = fb_set_var(info, (fb_var_screeninfo_t *)arg);
265 unlock_fb_info(info);
266 if (ret < 0)
267 ret = -EFAULT;
268 break;
269 case FBIOGET_FSCREENINFO:
270 lock_fb_info(info);
271 memcpy((void *)arg, &info->fix, sizeof(fb_fix_screeninfo_t));
272 unlock_fb_info(info);
273 break;
274 case FBIOGET_FRRAMEBUFFER:
275 info->screen_buffer = malloc((int32_t)arg);
276 break;
277 case FBIOPAN_DISPLAY:
278 lock_fb_info(info);
279 if (arg)
280 ret = fb_pan_display(info, (fb_var_screeninfo_t *)arg);
281
282 unlock_fb_info(info);
283 break;
284 case FBIOBLANK:
285 lock_fb_info(info);
286 ret = fb_blank(info, arg);
287 unlock_fb_info(info);
288 break;
289 #ifdef CONFIG_BACKLIGHT_MODE_ENABLE
290 case FBIOPUT_BRIGHTNESS:
291 if (info->bl_dev)
292 backlight_device_set_brightness(info->bl_dev, *(int32_t *)arg);
293
294 break;
295 case FBIOGET_BRIGHTNESS:
296 if (info->bl_dev) {
297 int32_t brightness;
298 brightness = backlight_device_get_brightness(info->bl_dev);
299 memcpy((void *)arg, &brightness, sizeof(brightness));
300 }
301 break;
302 case FBIOENABLE_BACKLIGHT:
303 if (info->bl_dev)
304 backlight_enable(info->bl_dev);
305 break;
306 case FBIODISABLE_BACKLIGHT:
307 if (info->bl_dev)
308 backlight_disable(info->bl_dev);
309 break;
310 #endif
311 #ifdef CONFIG_HW_ACCELERATION
312 case FBIO_ACCEL_FILLRECT:
313 lock_fb_info(info);
314 if (info->fbops->fb_fillrect) {
315 info->fbops->fb_fillrect(info, (const fb_fillrect_t *)arg);
316 ret = 0;
317 } else {
318 ret = -EIO;
319 }
320 unlock_fb_info(info);
321 break;
322 case FBIO_ACCEL_IMAGEBLIT:
323 lock_fb_info(info);
324 if (info->fbops->fb_imageblit) {
325 info->fbops->fb_imageblit(info, (const fb_image_t *)arg);
326 ret = 0;
327 } else {
328 ret = -EIO;
329 }
330 unlock_fb_info(info);
331 break;
332 case FBIO_ACCEL_COPYAREA:
333 lock_fb_info(info);
334 if (info->fbops->fb_copyarea) {
335 info->fbops->fb_copyarea(info, (const fb_copyarea_t *)arg);
336 ret = 0;
337 } else {
338 ret = -EIO;
339 }
340 unlock_fb_info(info);
341 break;
342 #endif
343 default:
344 lock_fb_info(info);
345 if (info->fbops->fb_ioctl)
346 ret = info->fbops->fb_ioctl(info, cmd, arg);
347 else
348 ret = -EIO;
349 unlock_fb_info(info);
350 break;
351 }
352
353 return ret;
354 }
355
356 #ifdef CONFIG_AOS_MMAP_ENABLE
fb_mmap(file_t * file,size_t size)357 static void *fb_mmap(file_t *file, size_t size)
358 {
359 fb_info_t *info = file_fb_info(file);
360 void *(*fb_mmap_fn)(fb_info_t *info, size_t size);
361 uint64_t *start;
362 uint32_t len;
363
364 if (!info)
365 return NULL;
366
367 if (aos_mutex_lock(&info->mm_lock, AOS_WAIT_FOREVER) != 0) {
368 LOGE(FB_STR, "Failed to lock mutex (%s).", __func__);
369 return NULL;
370 }
371
372 fb_mmap_fn = info->fbops->fb_mmap;
373 if (fb_mmap_fn) {
374 void *res;
375 // The framebuffer needs to be accessed decrypted, be sure
376 // SME protection is removed ahead of the call
377 res = fb_mmap_fn(info, size);
378 aos_mutex_unlock(&info->mm_lock);
379 return res;
380 }
381
382 start = (uint64_t *)&info->fix.smem_start; // pyshical address
383 len = info->fix.smem_len;
384
385 if (start == NULL || len == 0) {
386 info->fix.smem_start = (uint64_t)k_shmm_map_area(NULL, size);
387 if (info->screen_base == NULL) {
388 aos_mutex_unlock(&info->mm_lock);
389 return NULL;
390 }
391 info->screen_base = (uint8_t *)info->fix.smem_start;
392 info->fix.smem_len = size;
393 }
394
395 aos_mutex_unlock(&info->mm_lock);
396
397 return (void *)info->screen_base;
398 }
399 #endif
400
put_fb_info(fb_info_t * info)401 static void put_fb_info(fb_info_t *info)
402 {
403 if (info->fbops->fb_destroy)
404 info->fbops->fb_destroy(info);
405 }
406
fb_close(file_t * file)407 static int fb_close(file_t *file)
408 {
409 fb_info_t *info = file_fb_info(file);
410
411 if (!info)
412 return -ENODEV;
413
414 lock_fb_info(info);
415 if (info->fbops->fb_release)
416 info->fbops->fb_release(info, 1);
417 unlock_fb_info(info);
418 put_fb_info(info);
419 return 0;
420 }
421
do_register_framebuffer(fb_info_t * fb_info)422 static int do_register_framebuffer(fb_info_t *fb_info)
423 {
424 int i = 0, ret = 0;
425
426 if (num_registered_fb == FB_MAX)
427 return -ENXIO;
428
429 /*set ENDIAN mode, TODO*/
430
431 num_registered_fb++;
432 for (i = 0; i < FB_MAX; i++)
433 if (!registered_fb[i])
434 break;
435 fb_info->node = i;
436
437 aos_mutex_new(&fb_info->lock);
438 aos_mutex_new(&fb_info->mm_lock);
439
440 /*register framebuffer device to vfs*/
441 ret = snprintf(fb_info->path, FB_NAME_LEN, "%s%d", fb_node_path, fb_info->node);
442 if (ret < 0) {
443 LOGE(FB_STR, "copy fb path fail (%s)\n", __func__);
444 return -1;
445 }
446
447 ret = aos_register_driver(fb_info->path, &fb_fops, NULL);
448 if (unlikely(ret))
449 return -1;
450
451 if (i < FB_MAX)
452 registered_fb[i] = fb_info;
453 else
454 LOGE(FB_STR, "out of bounds (%s)\n", __func__);
455
456 return ret;
457 }
458
do_unregister_framebuffer(fb_info_t * fb_info)459 static void do_unregister_framebuffer(fb_info_t *fb_info)
460 {
461 registered_fb[fb_info->node] = NULL;
462 num_registered_fb--;
463
464 /* this may free fb info */
465 put_fb_info(fb_info);
466 }
467
register_framebuffer(fb_info_t * info)468 int register_framebuffer(fb_info_t *info)
469 {
470 int ret;
471
472 if (aos_mutex_lock(&fb_mutex, AOS_WAIT_FOREVER) != 0) {
473 LOGE(FB_STR, "Failed to lock mutex (%s).", __func__);
474 return -1;
475 }
476
477 ret = do_register_framebuffer(info);
478 aos_mutex_unlock(&fb_mutex);
479
480 return ret;
481 }
482
unregister_framebuffer(fb_info_t * info)483 void unregister_framebuffer(fb_info_t *info)
484 {
485 if (aos_mutex_lock(&fb_mutex, AOS_WAIT_FOREVER) != 0) {
486 LOGE(FB_STR, "Failed to lock mutex (%s).", __func__);
487 return;
488 }
489 do_unregister_framebuffer(info);
490 aos_mutex_unlock(&fb_mutex);
491 }
492
fb_init(void)493 int fb_init(void)
494 {
495 int i;
496 int ret = 0;
497
498 ret = aos_mutex_new((aos_mutex_t *)&fb_mutex);
499 if (unlikely(ret)) {
500 printf("create fb mutex failed\n");
501 return -1;
502 }
503
504 ret = aos_register_driver(fb_node_path, &fb_fops, NULL);
505 if (unlikely(ret))
506 return -1;
507
508 for (i = 0; i < FB_MAX; i++)
509 registered_fb[i] = NULL;
510
511 return ret;
512 }
513
framebuffer_alloc(size_t size)514 fb_info_t *framebuffer_alloc(size_t size)
515 {
516 int fb_info_size = sizeof(fb_info_t);
517 fb_info_t *info;
518 char *p;
519
520 if (size)
521 fb_info_size += PADDING;
522
523 p = aos_malloc(fb_info_size + size);
524
525 if (!p)
526 return NULL;
527
528 info = (fb_info_t *) p;
529
530 if (size)
531 info->par = p + fb_info_size;
532
533 return info;
534 }
535
536 /**
537 * framebuffer_release - marks the structure available for freeing
538 *
539 * @info: frame buffer info structure
540 *
541 */
framebuffer_release(fb_info_t * info)542 void framebuffer_release(fb_info_t *info)
543 {
544 if (!info)
545 return;
546
547 aos_free(info);
548 }
549
550 LEVEL0_DRIVER_ENTRY(fb_init)
551