1 /****************************************************************************
2 * drivers/video/fb.c
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership. The
7 * ASF licenses this file to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance with the
9 * License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 * License for the specific language governing permissions and limitations
17 * under the License.
18 *
19 ****************************************************************************/
20
21 /* Framebuffer character driver */
22
23 /****************************************************************************
24 * Included Files
25 ****************************************************************************/
26
27 #include "stdio.h"
28 #include "stdlib.h"
29 #include "string.h"
30 #include "fb.h"
31 #include "fs/driver.h"
32 #include "assert.h"
33 #include "errno.h"
34 #include "user_copy.h"
35
36 #define gerr PRINT_ERR
37
38 /****************************************************************************
39 * Private Types
40 ****************************************************************************/
41
42 /* This structure defines one framebuffer device. Note that which is
43 * everything in this structure is constant data set up and initialization
44 * time. Therefore, no there is requirement for serialized access to this
45 * structure.
46 */
47
48 struct fb_chardev_s
49 {
50 struct fb_vtable_s *vtable; /* Framebuffer interface */
51 void *fbmem; /* Start of frame buffer memory */
52 size_t fblen; /* Size of the framebuffer */
53 uint8_t plane; /* Video plan number */
54 uint8_t bpp; /* Bits per pixel */
55 };
56
57 #define FB_DEV_MAXNUM 32
58 static struct fb_chardev_s *g_fb_dev[FB_DEV_MAXNUM] = {NULL};
59
60 /****************************************************************************
61 * Private Function Prototypes
62 ****************************************************************************/
63
64 static int fb_open(struct file *filep);
65 static int fb_close(struct file *filep);
66 static ssize_t fb_read(struct file *filep, char *buffer, size_t buflen);
67 static ssize_t fb_write(struct file *filep, const char *buffer, size_t buflen);
68 static off_t fb_seek(struct file *filep, off_t offset, int whence);
69 static int fb_ioctl(struct file *filep, int cmd, unsigned long arg);
70 static ssize_t fb_mmap(struct file* filep, LosVmMapRegion *region);
71
72 /****************************************************************************
73 * Private Data
74 ****************************************************************************/
75
76 static const struct file_operations_vfs fb_fops =
77 {
78 fb_open, /* open */
79 fb_close, /* close */
80 fb_read, /* read */
81 fb_write, /* write */
82 fb_seek, /* seek */
83 fb_ioctl, /* ioctl */
84 fb_mmap, /* mmap */
85 #ifndef CONFIG_DISABLE_POLL
86 NULL, /* poll */
87 #endif
88 #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
89 NULL, /* unlink */
90 #endif
91 };
92
93 /****************************************************************************
94 * Private Functions
95 ****************************************************************************/
96
fb_mmap(struct file * filep,LosVmMapRegion * region)97 static ssize_t fb_mmap(struct file *filep, LosVmMapRegion *region)
98 {
99 int ret = -EINVAL;
100 struct fb_chardev_s *fb;
101 struct fb_vtable_s *vtable;
102 struct drv_data *drvData;
103
104 drvData = (struct drv_data *)filep->f_vnode->data;
105 fb = (struct fb_chardev_s *)drvData->priv;
106 if (fb == NULL)
107 {
108 return -ENODEV;
109 }
110
111 vtable = fb->vtable;
112 if (vtable == NULL)
113 {
114 return -EINVAL;
115 }
116
117 if (vtable->fb_mmap != NULL)
118 {
119 ret = vtable->fb_mmap(vtable, region);
120 }
121
122 return ret;
123 }
124
125 /****************************************************************************
126 * Name: fb_open
127 *
128 * Description:
129 * This function is called whenever the framebuffer device is opened.
130 *
131 ****************************************************************************/
132
fb_open(struct file * filep)133 static int fb_open(struct file *filep)
134 {
135 DEBUGASSERT(filep != NULL && filep->f_vnode != NULL);
136 struct fb_chardev_s *fb;
137 struct fb_vtable_s *vtable;
138 int ret = -EINVAL;
139 struct drv_data *drvData;
140
141 drvData = (struct drv_data *)filep->f_vnode->data;
142 fb = (struct fb_chardev_s *)drvData->priv;
143 if (fb == NULL)
144 {
145 return -ENODEV;
146 }
147
148 vtable = fb->vtable;
149 if (vtable == NULL)
150 {
151 return -EINVAL;
152 }
153
154 if (vtable->fb_open)
155 {
156 ret = vtable->fb_open(vtable);
157 }
158
159 return ret;
160 }
161
162 /****************************************************************************
163 * Name: fb_close
164 *
165 * Description:
166 * This function is called when the framebuffer device is closed.
167 *
168 ****************************************************************************/
169
fb_close(struct file * filep)170 static int fb_close(struct file *filep)
171 {
172 DEBUGASSERT(filep != NULL && filep->f_vnode != NULL);
173 struct fb_chardev_s *fb;
174 struct fb_vtable_s *vtable;
175 int ret = -EINVAL;
176 struct drv_data *drvData;
177
178 drvData = (struct drv_data *)filep->f_vnode->data;
179 fb = (struct fb_chardev_s *)drvData->priv;
180 if (fb == NULL)
181 {
182 return -ENODEV;
183 }
184
185 vtable = fb->vtable;
186 if (vtable == NULL)
187 {
188 return -EINVAL;
189 }
190
191 if (vtable->fb_release)
192 {
193 ret = vtable->fb_release(vtable);
194 }
195
196 return ret;
197 }
198
199 /****************************************************************************
200 * Name: fb_read
201 ****************************************************************************/
202
fb_read(struct file * filep,char * buffer,size_t len)203 static ssize_t fb_read(struct file *filep, char *buffer, size_t len)
204 {
205 struct fb_chardev_s *fb = NULL;
206 size_t start;
207 size_t end;
208 size_t size;
209 int ret;
210 struct drv_data *drvData;
211
212 /* Get the framebuffer instance */
213
214 DEBUGASSERT(filep != NULL && filep->f_vnode != NULL);
215 drvData = (struct drv_data *)filep->f_vnode->data;
216 fb = (struct fb_chardev_s *)drvData->priv;
217 /* Get the start and size of the transfer */
218
219 start = filep->f_pos;
220 if (start >= fb->fblen)
221 {
222 return 0; /* Return end-of-file */
223 }
224
225 end = start + len;
226 if (end >= fb->fblen)
227 {
228 end = fb->fblen;
229 }
230
231 size = end - start;
232
233 /* And transfer the data from the frame buffer */
234
235 ret = LOS_ArchCopyToUser(buffer, fb->fbmem, size);
236 if (ret)
237 {
238 return -EFAULT;
239 }
240 filep->f_pos += size;
241 return size;
242 }
243
244 /****************************************************************************
245 * Name: fb_write
246 ****************************************************************************/
247
fb_write(struct file * filep,const char * buffer,size_t len)248 static ssize_t fb_write(struct file *filep, const char *buffer,
249 size_t len)
250 {
251 struct fb_chardev_s *fb = NULL;
252 size_t start;
253 size_t end;
254 size_t size;
255 int ret;
256 struct drv_data *drvData;
257
258
259 /* Get the framebuffer instance */
260
261 DEBUGASSERT(filep != NULL && filep->f_vnode != NULL);
262 drvData = (struct drv_data *)filep->f_vnode->data;
263 fb = (struct fb_chardev_s *)drvData->priv;
264 /* Get the start and size of the transfer */
265
266 start = filep->f_pos;
267 if (start >= fb->fblen)
268 {
269 return -EFBIG; /* Cannot extend the framebuffer */
270 }
271
272 end = start + len;
273 if (end >= fb->fblen)
274 {
275 end = fb->fblen;
276 }
277
278 size = end - start;
279
280 /* And transfer the data into the frame buffer */
281
282 ret = LOS_ArchCopyFromUser(fb->fbmem, buffer, size);
283 if (ret)
284 {
285 return -EFAULT;
286 }
287 filep->f_pos += size;
288 return size;
289 }
290
291 /****************************************************************************
292 * Name: fb_seek
293 *
294 * Description:
295 * Seek the logical file pointer to the specified position. The offset
296 * is in units of pixels, with offset zero being the beginning of the
297 * framebuffer.
298 *
299 ****************************************************************************/
300
fb_seek(struct file * filep,off_t offset,int whence)301 static off_t fb_seek(struct file *filep, off_t offset, int whence)
302 {
303 struct fb_chardev_s *fb = NULL;
304 off_t newpos;
305 int ret;
306 struct drv_data *drvData;
307
308 /* Get the framebuffer instance */
309
310 DEBUGASSERT(filep != NULL && filep->f_vnode != NULL);
311 drvData = (struct drv_data *)filep->f_vnode->data;
312 fb = (struct fb_chardev_s *)drvData->priv;
313 /* Determine the new, requested file position */
314
315 switch (whence)
316 {
317 case SEEK_CUR:
318 newpos = filep->f_pos + offset;
319 break;
320
321 case SEEK_SET:
322 newpos = offset;
323 break;
324
325 case SEEK_END:
326 newpos = fb->fblen + offset;
327 break;
328
329 default:
330 /* Return EINVAL if the whence argument is invalid */
331
332 return -EINVAL;
333 }
334
335 /* Opengroup.org:
336 *
337 * "The lseek() function shall allow the file offset to be set beyond the end
338 * of the existing data in the file. If data is later written at this point,
339 * subsequent reads of data in the gap shall return bytes with the value 0
340 * until data is actually written into the gap."
341 *
342 * We can conform to the first part, but not the second. But return EINVAL if
343 *
344 * "...the resulting file offset would be negative for a regular file, block
345 * special file, or directory."
346 */
347
348 if (newpos >= 0)
349 {
350 filep->f_pos = newpos;
351 ret = newpos;
352 }
353 else
354 {
355 ret = -EINVAL;
356 }
357
358 return ret;
359 }
360
361 /****************************************************************************
362 * Name: fb_ioctl
363 *
364 * Description:
365 * The standard ioctl method.
366 *
367 ****************************************************************************/
368
fb_ioctl(struct file * filep,int cmd,unsigned long arg)369 static int fb_ioctl(struct file *filep, int cmd, unsigned long arg)
370 {
371 struct fb_chardev_s *fb = NULL;
372 int ret;
373 struct drv_data *drvData;
374
375 /* Get the framebuffer instance */
376
377 DEBUGASSERT(filep != NULL && filep->f_vnode != NULL);
378 drvData = (struct drv_data *)filep->f_vnode->data;
379 fb = (struct fb_chardev_s *)drvData->priv;
380 /* Process the IOCTL command */
381
382 switch (cmd)
383 {
384 case FIOC_MMAP: /* Get color plane info */
385 {
386 void **ppv = (void **)((uintptr_t)arg);
387 uintptr_t fbmem = (uintptr_t)fb->fbmem;
388
389 /* Return the address corresponding to the start of frame buffer. */
390
391 ret = LOS_ArchCopyToUser(ppv, &fbmem, sizeof(uintptr_t));
392 if (ret)
393 {
394 ret = -EFAULT;
395 }
396 }
397 break;
398
399 case FBIOGET_VIDEOINFO: /* Get color plane info */
400 {
401 struct fb_videoinfo_s vinfo = { 0 };
402
403 DEBUGASSERT(fb->vtable != NULL &&
404 fb->vtable->getvideoinfo != NULL);
405 ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
406 if (ret == ENOERR)
407 {
408 ret = LOS_ArchCopyToUser((void *)arg, &vinfo, sizeof(struct fb_videoinfo_s));
409 if (ret)
410 {
411 ret = -EFAULT;
412 }
413 }
414 }
415 break;
416
417 case FBIOGET_PLANEINFO: /* Get video plane info */
418 {
419 struct fb_planeinfo_s pinfo = { 0 };
420
421 DEBUGASSERT(fb->vtable != NULL &&
422 fb->vtable->getplaneinfo != NULL);
423 ret = fb->vtable->getplaneinfo(fb->vtable, fb->plane, &pinfo);
424 if (ret == ENOERR)
425 {
426 ret = LOS_ArchCopyToUser((void *)arg, &pinfo, sizeof(struct fb_planeinfo_s));
427 if (ret)
428 {
429 ret = -EFAULT;
430 }
431 }
432 }
433 break;
434
435 #ifdef CONFIG_FB_CMAP
436 case FBIOGET_CMAP: /* Get RGB color mapping */
437 {
438 struct fb_cmap_s cmap = { 0 };
439
440 DEBUGASSERT(fb->vtable != NULL &&
441 fb->vtable->getcmap != NULL);
442 ret = fb->vtable->getcmap(fb->vtable, &cmap);
443 if (ret == ENOERR)
444 {
445 ret = LOS_ArchCopyToUser((void *)arg, &cmap, sizeof(struct fb_cmap_s));
446 if (ret)
447 {
448 ret = -EFAULT;
449 }
450 }
451 }
452 break;
453
454 case FBIOPUT_CMAP: /* Put RGB color mapping */
455 {
456 struct fb_cmap_s cmap;
457
458 DEBUGASSERT(fb->vtable != NULL &&
459 fb->vtable->putcmap != NULL);
460 ret = LOS_ArchCopyFromUser(&cmap, (const void *)arg, sizeof(struct fb_cmap_s));
461 if (ret)
462 {
463 ret = -EFAULT;
464 break;
465 }
466 ret = fb->vtable->putcmap(fb->vtable, &cmap);
467 }
468 break;
469 #endif
470 #ifdef CONFIG_FB_HWCURSOR
471 case FBIOGET_CURSOR: /* Get cursor attributes */
472 {
473 struct fb_cursorattrib_s attrib = { 0 };
474
475 DEBUGASSERT(fb->vtable != NULL &&
476 fb->vtable->getcursor != NULL);
477 ret = fb->vtable->getcursor(fb->vtable, &attrib);
478 if (ret == ENOERR)
479 {
480 ret = LOS_ArchCopyToUser((void *)arg, &attrib, sizeof(struct fb_cursorattrib_s));
481 if (ret)
482 {
483 ret = -EFAULT;
484 }
485 }
486 }
487 break;
488
489 case FBIOPUT_CURSOR: /* Set cursor attibutes */
490 {
491 struct fb_setcursor_s cursor;
492
493 DEBUGASSERT(fb->vtable != NULL &&
494 fb->vtable->setcursor != NULL);
495 ret = LOS_ArchCopyFromUser(&cursor, (const void *)arg, sizeof(struct fb_setcursor_s));
496 if (ret)
497 {
498 ret = -EFAULT;
499 break;
500 }
501 ret = fb->vtable->setcursor(fb->vtable, &cursor);
502 }
503 break;
504 #endif
505
506 #ifdef CONFIG_LCD_UPDATE
507 case FBIO_UPDATE: /* Update the LCD with the modified framebuffer data */
508 {
509 struct nxgl_rect_s rect;
510 struct fb_planeinfo_s pinfo;
511
512 DEBUGASSERT(fb->vtable != NULL && fb->vtable->getplaneinfo != NULL);
513 ret = LOS_ArchCopyFromUser(&rect, (const void *)arg, sizeof(struct nxgl_rect_s));
514 if (ret)
515 {
516 ret = -EFAULT;
517 break;
518 }
519 ret = fb->vtable->getplaneinfo(fb->vtable, fb->plane, &pinfo);
520 if (ret >= 0)
521 {
522 nx_notify_rectangle((NX_PLANEINFOTYPE *)&pinfo, &rect);
523 }
524 }
525 break;
526 #endif
527
528 #ifdef CONFIG_FB_SYNC
529 case FBIO_WAITFORVSYNC: /* Wait upon vertical sync */
530 {
531 ret = fb->vtable->waitforvsync(fb->vtable);
532 }
533 break;
534 #endif
535
536 #ifdef CONFIG_FB_OVERLAY
537 case FBIO_SELECT_OVERLAY: /* Select video overlay */
538 {
539 struct fb_overlayinfo_s oinfo;
540
541 DEBUGASSERT(fb->vtable != NULL && fb->vtable->getoverlayinfo != NULL);
542 ret = fb->vtable->getoverlayinfo(fb->vtable, arg, &oinfo);
543 if (ret == OK)
544 {
545 fb->fbmem = oinfo.fbmem;
546 fb->fblen = oinfo.fblen;
547 fb->bpp = oinfo.bpp;
548 }
549 }
550 break;
551
552 case FBIOGET_OVERLAYINFO: /* Get video overlay info */
553 {
554 struct fb_overlayinfo_s oinfo;
555
556 DEBUGASSERT(fb->vtable != NULL &&
557 fb->vtable->getoverlayinfo != NULL);
558 ret = LOS_ArchCopyFromUser(&oinfo, (const void *)arg, sizeof(struct fb_overlayinfo_s));
559 if (ret)
560 {
561 ret = -EFAULT;
562 break;
563 }
564 ret = fb->vtable->getoverlayinfo(fb->vtable, oinfo.overlay, &oinfo);
565 if (ret == ENOERR)
566 {
567 ret = LOS_ArchCopyToUser((void *)arg, &oinfo, sizeof(struct fb_overlayinfo_s));
568 if (ret)
569 {
570 ret = -EFAULT;
571 }
572 }
573 }
574 break;
575
576 case FBIOSET_TRANSP: /* Set video overlay transparency */
577 {
578 struct fb_overlayinfo_s oinfo;
579
580 DEBUGASSERT(fb->vtable != NULL &&
581 fb->vtable->settransp != NULL);
582 ret = LOS_ArchCopyFromUser(&oinfo, (const void *)arg, sizeof(struct fb_overlayinfo_s));
583 if (ret)
584 {
585 ret = -EFAULT;
586 break;
587 }
588 ret = fb->vtable->settransp(fb->vtable, &oinfo);
589 }
590 break;
591
592 case FBIOSET_CHROMAKEY: /* Set video overlay chroma key */
593 {
594 struct fb_overlayinfo_s oinfo;
595
596 DEBUGASSERT(fb->vtable != NULL &&
597 fb->vtable->setchromakey != NULL);
598 ret = LOS_ArchCopyFromUser(&oinfo, (const void *)arg, sizeof(struct fb_overlayinfo_s));
599 if (ret)
600 {
601 ret = -EFAULT;
602 break;
603 }
604 ret = fb->vtable->setchromakey(fb->vtable, &oinfo);
605 }
606 break;
607
608 case FBIOSET_COLOR: /* Set video overlay color */
609 {
610 struct fb_overlayinfo_s oinfo;
611
612 DEBUGASSERT(fb->vtable != NULL &&
613 fb->vtable->setcolor != NULL);
614 ret = LOS_ArchCopyFromUser(&oinfo, (const void *)arg, sizeof(struct fb_overlayinfo_s));
615 if (ret)
616 {
617 ret = -EFAULT;
618 break;
619 }
620 ret = fb->vtable->setcolor(fb->vtable, &oinfo);
621 }
622 break;
623
624 case FBIOSET_BLANK: /* Blank or unblank video overlay */
625 {
626 struct fb_overlayinfo_s oinfo;
627
628 DEBUGASSERT(fb->vtable != NULL &&
629 fb->vtable->setblank != NULL);
630 ret = LOS_ArchCopyFromUser(&oinfo, (const void *)arg, sizeof(struct fb_overlayinfo_s));
631 if (ret)
632 {
633 ret = -EFAULT;
634 break;
635 }
636 ret = fb->vtable->setblank(fb->vtable, &oinfo);
637 }
638 break;
639
640 case FBIOSET_AREA: /* Set active video overlay area */
641 {
642 struct fb_overlayinfo_s oinfo;
643
644 DEBUGASSERT(fb->vtable != NULL &&
645 fb->vtable->setarea != NULL);
646 ret = LOS_ArchCopyFromUser(&oinfo, (const void *)arg, sizeof(struct fb_overlayinfo_s));
647 if (ret)
648 {
649 ret = -EFAULT;
650 break;
651 }
652 ret = fb->vtable->setarea(fb->vtable, &oinfo);
653 }
654 break;
655
656 #ifdef CONFIG_FB_OVERLAY_BLIT
657 case FBIOSET_BLIT: /* Blit operation between video overlays */
658 {
659 struct fb_overlayblit_s blit;
660
661 DEBUGASSERT(fb->vtable != NULL &&
662 fb->vtable->blit != NULL);
663 ret = LOS_ArchCopyFromUser(&blit, (const void *)arg, sizeof(struct fb_overlayblit_s));
664 if (ret)
665 {
666 ret = -EFAULT;
667 break;
668 }
669 ret = fb->vtable->blit(fb->vtable, &blit);
670 }
671 break;
672
673 case FBIOSET_BLEND: /* Blend operation between video overlays */
674 {
675 struct fb_overlayblend_s blend;
676
677 DEBUGASSERT(fb->vtable != NULL &&
678 fb->vtable->blend != NULL);
679 ret = LOS_ArchCopyFromUser(&blend, (const void *)arg, sizeof(struct fb_overlayblend_s));
680 if (ret)
681 {
682 ret = -EFAULT;
683 break;
684 }
685 ret = fb->vtable->blend(fb->vtable, &blend);
686 }
687 break;
688 #endif
689 #endif /* CONFIG_FB_OVERLAY */
690
691 default:
692 DEBUGASSERT(fb->vtable != NULL && fb->vtable->fb_ioctl != NULL);
693 ret = fb->vtable->fb_ioctl(fb->vtable, cmd, arg);
694 break;
695 }
696
697 return ret;
698 }
699
700 /****************************************************************************
701 * Public Functions
702 ****************************************************************************/
703
704 /****************************************************************************
705 * Name: fb_register
706 *
707 * Description:
708 * Register the framebuffer character device at /dev/fbN where N is the
709 * display number if the devices supports only a single plane. If the
710 * hardware supports multiple color planes, then the device will be
711 * registered at /dev/fbN.M where N is the again display number but M
712 * is the display plane.
713 *
714 * Input Parameters:
715 * display - The display number for the case of boards supporting multiple
716 * displays or for hardware that supports multiple
717 * layers (each layer is consider a display). Typically zero.
718 * plane - Identifies the color plane on hardware that supports separate
719 * framebuffer "planes" for each color component.
720 *
721 * Returned Value:
722 * Zero (OK) is returned success; a negated errno value is returned on any
723 * failure.
724 *
725 ****************************************************************************/
726
fb_register(int display,int plane)727 int fb_register(int display, int plane)
728 {
729 struct fb_chardev_s *fb = NULL;
730 struct fb_videoinfo_s vinfo;
731 struct fb_planeinfo_s pinfo;
732 #ifdef CONFIG_FB_OVERLAY
733 struct fb_overlayinfo_s oinfo;
734 #endif
735 char devname[16];
736 int nplanes;
737 int ret;
738
739 if (display < 0 || display >= FB_DEV_MAXNUM)
740 return -EINVAL;
741
742 /* Allocate a framebuffer state instance */
743
744 fb = (struct fb_chardev_s *)malloc(sizeof(struct fb_chardev_s));
745 if (fb == NULL)
746 {
747 return -ENOMEM;
748 }
749
750 /* Initialize the frame buffer device. */
751
752 ret = up_fbinitialize(display);
753 if (ret < 0)
754 {
755 gerr("ERROR: up_fbinitialize() failed for display %d: %d\n", display, ret);
756 goto errout_with_fb;
757 }
758
759 DEBUGASSERT((unsigned)plane <= UINT8_MAX);
760 fb->plane = plane;
761
762 fb->vtable = up_fbgetvplane(display, plane);
763 if (fb->vtable == NULL)
764 {
765 gerr("ERROR: up_fbgetvplane() failed, vplane=%d\n", plane);
766 goto errout_with_fb;
767 }
768
769 /* Initialize the frame buffer instance. */
770
771 DEBUGASSERT(fb->vtable->getvideoinfo != NULL);
772 ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
773 if (ret < 0)
774 {
775 gerr("ERROR: getvideoinfo() failed: %d\n", ret);
776 goto errout_with_fb;
777 }
778
779 nplanes = vinfo.nplanes;
780 DEBUGASSERT(vinfo.nplanes > 0 && (unsigned)plane < vinfo.nplanes);
781
782 DEBUGASSERT(fb->vtable->getplaneinfo != NULL);
783 ret = fb->vtable->getplaneinfo(fb->vtable, plane, &pinfo);
784 if (ret < 0)
785 {
786 gerr("ERROR: getplaneinfo() failed: %d\n", ret);
787 goto errout_with_fb;
788 }
789
790 fb->fbmem = pinfo.fbmem;
791 fb->fblen = pinfo.fblen;
792 fb->bpp = pinfo.bpp;
793
794 /* Clear the framebuffer memory */
795
796 memset(pinfo.fbmem, 0, pinfo.fblen);
797
798 #ifdef CONFIG_FB_OVERLAY
799 /* Initialize first overlay but do not select */
800
801 DEBUGASSERT(fb->vtable->getoverlayinfo != NULL);
802 ret = fb->vtable->getoverlayinfo(fb->vtable, 0, &oinfo);
803 if (ret < 0)
804 {
805 gerr("ERROR: getoverlayinfo() failed: %d\n", ret);
806 goto errout_with_fb;
807 }
808
809 /* Clear the overlay memory. Necessary when plane 0 and overlay 0
810 * different.
811 */
812
813 memset(oinfo.fbmem, 0, oinfo.fblen);
814 #endif
815
816 /* Register the framebuffer device */
817
818 if (nplanes < 2)
819 {
820 (void)snprintf(devname, 16, "/dev/fb%d", display);
821 }
822 else
823 {
824 (void)snprintf(devname, 16, "/dev/fb%d.%d", display, plane);
825 }
826
827 ret = register_driver(devname, &fb_fops, 0666, (void *)fb);
828 if (ret < 0)
829 {
830 gerr("ERROR: register_driver() failed: %d\n", ret);
831 goto errout_with_fb;
832 }
833
834 g_fb_dev[display] = fb;
835
836 return OK;
837
838 errout_with_fb:
839 free(fb);
840 return ret;
841 }
842
fb_unregister(int display)843 int fb_unregister(int display)
844 {
845 struct fb_chardev_s *fb = NULL;
846
847 if (display < 0 || display >= FB_DEV_MAXNUM)
848 return -EINVAL;
849
850 fb = g_fb_dev[display];
851
852 up_fbuninitialize(display);
853
854 free(fb);
855 g_fb_dev[display] = NULL;
856
857 return 0;
858 }
859