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 48struct 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 58static struct fb_chardev_s *g_fb_dev[FB_DEV_MAXNUM] = {NULL}; 59 60/**************************************************************************** 61 * Private Function Prototypes 62 ****************************************************************************/ 63 64static int fb_open(struct file *filep); 65static int fb_close(struct file *filep); 66static ssize_t fb_read(struct file *filep, char *buffer, size_t buflen); 67static ssize_t fb_write(struct file *filep, const char *buffer, size_t buflen); 68static off_t fb_seek(struct file *filep, off_t offset, int whence); 69static int fb_ioctl(struct file *filep, int cmd, unsigned long arg); 70static ssize_t fb_mmap(struct file* filep, LosVmMapRegion *region); 71 72/**************************************************************************** 73 * Private Data 74 ****************************************************************************/ 75 76static 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 97static 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 133static 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 170static 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 203static 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 248static 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 301static 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 369static 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 727int 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 838errout_with_fb: 839 free(fb); 840 return ret; 841} 842 843int 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