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