| /**************************************************************************** |
| * drivers/lcd/lcd_framebuffer.c |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <stdint.h> |
| #include <string.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <debug.h> |
| |
| #include <nuttx/board.h> |
| #include <nuttx/kmalloc.h> |
| #include <nuttx/lcd/lcd.h> |
| #include <nuttx/video/fb.h> |
| |
| #ifdef CONFIG_LCD_FRAMEBUFFER |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /* At present, only video plane 0 is supported */ |
| |
| #define VIDEO_PLANE 0 |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| /* This structure describes the LCD framebuffer */ |
| |
| struct lcdfb_dev_s |
| { |
| struct fb_vtable_s vtable; /* Must be cast compatible with lcdfb_dev_s */ |
| FAR struct lcdfb_dev_s *flink; /* Supports a singly linked list */ |
| FAR struct lcd_dev_s *lcd; /* Contained LCD device */ |
| FAR uint8_t *fbmem; /* Allocated framebuffer */ |
| FAR struct lcd_planeinfo_s pinfo; /* LCD plane info */ |
| size_t fblen; /* Size of the framebuffer in bytes */ |
| fb_coord_t xres; /* Horizontal resolution in pixel columns */ |
| fb_coord_t yres; /* Vertical resolution in pixel rows */ |
| fb_coord_t stride; /* Width of a row in bytes */ |
| uint8_t display; /* Display number */ |
| }; |
| |
| /**************************************************************************** |
| * Private Function Prototypes |
| ****************************************************************************/ |
| |
| /* Update the LCD when there is a change to the framebuffer */ |
| |
| static int lcdfb_updateearea(FAR struct fb_vtable_s *vtable, |
| FAR const struct fb_area_s *area); |
| |
| /* Get information about the video controller configuration and the |
| * configuration of each color plane. |
| */ |
| |
| static int lcdfb_getvideoinfo(FAR struct fb_vtable_s *vtable, |
| FAR struct fb_videoinfo_s *vinfo); |
| static int lcdfb_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno, |
| FAR struct fb_planeinfo_s *pinfo); |
| |
| /* The following is provided only if the video hardware supports RGB color |
| * mapping |
| */ |
| |
| #ifdef CONFIG_FB_CMAP |
| static int lcdfb_getcmap(FAR struct fb_vtable_s *vtable, |
| FAR struct fb_cmap_s *cmap); |
| static int lcdfb_putcmap(FAR struct fb_vtable_s *vtable, |
| FAR const struct fb_cmap_s *cmap); |
| #endif |
| |
| /* The following is provided only if the video hardware supports a hardware |
| * cursor |
| */ |
| |
| #ifdef CONFIG_FB_HWCURSOR |
| static int lcdfb_getcursor(FAR struct fb_vtable_s *vtable, |
| FAR struct fb_cursorattrib_s *attrib); |
| static int lcdfb_setcursor(FAR struct fb_vtable_s *vtable, |
| FAR struct fb_setcursor_s *settings); |
| #endif |
| |
| static int lcdfb_setpower(FAR struct fb_vtable_s *vtable, int power); |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| /* This is a singly linked list that supports look-up of framebuffer state |
| * using the display number. |
| */ |
| |
| static FAR struct lcdfb_dev_s *g_lcdfb; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: lcdfb_find |
| * |
| * Description: |
| * Find the LCD framebuffer state associated with the display. |
| * |
| ****************************************************************************/ |
| |
| static FAR struct lcdfb_dev_s *lcdfb_find(int display) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| |
| /* Look up the LCD framebuffer state structure for this display. |
| * |
| * REVISIT: If many LCD framebuffers are used, then this lookup would be |
| * a performance issue. |
| * REVISIT: Semaphore protections is needed if there is concurrent access. |
| */ |
| |
| for (priv = g_lcdfb; priv != NULL; priv = priv->flink) |
| { |
| if (priv->display == display) |
| { |
| return priv; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| /**************************************************************************** |
| * Name: lcdfb_updateearea |
| * |
| * Description: |
| * Update the LCD when there is a change to the framebuffer. |
| * |
| ****************************************************************************/ |
| |
| static int lcdfb_updateearea(FAR struct fb_vtable_s *vtable, |
| FAR const struct fb_area_s *area) |
| { |
| FAR struct lcdfb_dev_s *priv = (FAR struct lcdfb_dev_s *)vtable; |
| FAR struct lcd_planeinfo_s *pinfo = &priv->pinfo; |
| FAR uint8_t *run = priv->fbmem; |
| fb_coord_t row; |
| fb_coord_t startx = 0; |
| fb_coord_t endx = priv->xres - 1; |
| fb_coord_t width = priv->xres; |
| fb_coord_t starty = 0; |
| fb_coord_t endy = priv->yres - 1; |
| int ret; |
| |
| if (area != NULL) |
| { |
| /* Clip to fit in the framebuffer */ |
| |
| startx = area->x; |
| if (startx < 0) |
| { |
| startx = 0; |
| } |
| |
| endx = startx + area->w - 1; |
| if (endx >= priv->xres) |
| { |
| endx = priv->xres - 1; |
| } |
| |
| starty = area->y; |
| if (starty < 0) |
| { |
| starty = 0; |
| } |
| |
| endy = starty + area->h - 1; |
| if (endy >= priv->yres) |
| { |
| endy = priv->yres - 1; |
| } |
| |
| /* If the display uses a value of BPP < 8, then we may have to extend |
| * the rectangle on the left so that it is byte aligned. Works for |
| * BPP={1,2,4} |
| */ |
| |
| if (pinfo->bpp < 8) |
| { |
| unsigned int pixperbyte = 8 / pinfo->bpp; |
| startx &= ~(pixperbyte - 1); |
| } |
| |
| /* Get the starting position in the framebuffer */ |
| |
| run = priv->fbmem + starty * priv->stride; |
| run += (startx * pinfo->bpp + 7) >> 3; |
| } |
| |
| if (pinfo->putarea != NULL) |
| { |
| /* Each Driver's callback function putarea may be optimized by checking |
| * if it is a full screen/full row mode or not. |
| * In case of full screen/row mode the memory layout of drivers memory |
| * and data provided to putarea function may be (or not, it depends of |
| * display and driver implementation) identical. |
| * Identical memory layout let us to use: |
| * - memcopy (if there is shadow buffer in driver implementation) |
| * - apply DMA channel to transfer data to driver memory. |
| */ |
| |
| ret = pinfo->putarea(pinfo->dev, starty, endy, startx, endx, |
| run, priv->stride); |
| if (ret < 0) |
| { |
| lcderr("Failed to update area"); |
| return ret; |
| } |
| } |
| else |
| { |
| width = endx - startx + 1; |
| |
| for (row = starty; row <= endy; row++) |
| { |
| ret = pinfo->putrun(pinfo->dev, row, startx, run, width); |
| if (ret < 0) |
| { |
| lcderr("Failed to update row"); |
| return ret; |
| } |
| |
| run += priv->stride; |
| } |
| } |
| |
| if (pinfo->redraw != NULL) |
| { |
| pinfo->redraw(pinfo->dev); |
| } |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: lcdfb_getvideoinfo |
| ****************************************************************************/ |
| |
| static int lcdfb_getvideoinfo(FAR struct fb_vtable_s *vtable, |
| FAR struct fb_videoinfo_s *vinfo) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| int ret = -EINVAL; |
| |
| lcdinfo("vtable=%p vinfo=%p\n", vtable, vinfo); |
| |
| DEBUGASSERT(vtable != NULL && vinfo != NULL); |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL && vinfo != NULL) |
| { |
| /* Get the video info from the contained LCD */ |
| |
| lcd = priv->lcd; |
| DEBUGASSERT(lcd->getvideoinfo != NULL); |
| ret = lcd->getvideoinfo(lcd, vinfo); |
| if (ret < 0) |
| { |
| lcderr("ERROR: LCD getvideoinfo() failed: %d\n", ret); |
| } |
| } |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: lcdfb_getplaneinfo |
| ****************************************************************************/ |
| |
| static int lcdfb_getplaneinfo(FAR struct fb_vtable_s *vtable, int planeno, |
| FAR struct fb_planeinfo_s *pinfo) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| int ret = -EINVAL; |
| |
| lcdinfo("vtable=%p planeno=%d pinfo=%p\n", vtable, planeno, pinfo); |
| |
| DEBUGASSERT(vtable != NULL && planeno == VIDEO_PLANE && pinfo != NULL); |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL && planeno == VIDEO_PLANE && pinfo != NULL) |
| { |
| /* Return the plane info */ |
| |
| pinfo->fbmem = priv->fbmem; |
| pinfo->fblen = priv->fblen; |
| pinfo->stride = priv->stride; |
| pinfo->display = priv->display; |
| pinfo->bpp = priv->pinfo.bpp; |
| |
| ret = OK; |
| } |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: lcdfb_getcmap |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_FB_CMAP |
| static int lcdfb_getcmap(FAR struct fb_vtable_s *vtable, |
| FAR struct fb_cmap_s *cmap) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| int ret = -EINVAL; |
| |
| lcdinfo("vtable=%p cmap=%p\n", vtable, cmap); |
| |
| DEBUGASSERT(vtable != NULL && cmap != NULL); |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL && cmap != NULL) |
| { |
| /* Get the color map from the contained LCD */ |
| |
| lcd = priv->lcd |
| DEBUGASSERT(lcd->getcmap != NULL); |
| ret = lcd->getcmap(lcd, cmap); |
| if (ret < 0) |
| { |
| lcderr("ERROR: LCD getcmap() failed: %d\n", ret); |
| } |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: lcdfb_putcmap |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_FB_CMAP |
| static int lcdfb_putcmap(FAR struct fb_vtable_s *vtable, |
| FAR const struct fb_cmap_s *cmap) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| int ret = -EINVAL; |
| |
| lcdinfo("vtable=%p cmap=%p\n", vtable, cmap); |
| |
| DEBUGASSERT(vtable != NULL && cmap != NULL); |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL && cmap != NULL) |
| { |
| /* Set the color map to the contained LCD */ |
| |
| lcd = priv->lcd |
| DEBUGASSERT(lcd->putcmap != NULL); |
| ret = lcd->putcmap(lcd, cmap); |
| if (ret < 0) |
| { |
| lcderr("ERROR: LCD putcmap() failed: %d\n", ret); |
| } |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: lcdfb_getcursor |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_FB_HWCURSOR |
| static int lcdfb_getcursor(FAR struct fb_vtable_s *vtable, |
| FAR struct fb_cursorattrib_s *attrib) |
| { |
| lcdinfo("vtable=%p attrib=%p\n", vtable, attrib); |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| int ret = -EINVAL; |
| |
| lcdinfo("vtable=%p attrib=%p\n", vtable, attrib); |
| |
| DEBUGASSERT(vtable != NULL && attrib != NULL); |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL && attrib != NULL) |
| { |
| /* Get the cursor info from the contained LCD */ |
| |
| lcd = priv->lcd |
| DEBUGASSERT(lcd->getcursor != NULL); |
| ret = lcd->getcursor(lcd, attrib); |
| if (ret < 0) |
| { |
| lcderr("ERROR: LCD getcursor() failed: %d\n", ret); |
| } |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: lcdfb_setcursor |
| ****************************************************************************/ |
| |
| #ifdef CONFIG_FB_HWCURSOR |
| static int lcdfb_setcursor(FAR struct fb_vtable_s *vtable, |
| FAR struct fb_setcursor_s *settings) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| int ret = -EINVAL; |
| |
| lcdinfo("vtable=%p settings=%p\n", vtable, settings); |
| |
| DEBUGASSERT(vtable != NULL && settings != NULL); |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL && settings != NULL) |
| { |
| /* Set the cursor info to the contained LCD */ |
| |
| lcd = priv->lcd |
| DEBUGASSERT(lcd->setcursor != NULL); |
| ret = lcd->setcursor(lcd, settings); |
| if (ret < 0) |
| { |
| lcderr("ERROR: LCD setcursor() failed: %d\n", ret); |
| } |
| } |
| |
| return ret; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Name: lcdfb_setpower |
| ****************************************************************************/ |
| |
| static int lcdfb_setpower(FAR struct fb_vtable_s *vtable, int power) |
| { |
| int ret = -EINVAL; |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| |
| DEBUGASSERT(vtable != NULL); |
| |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL) |
| { |
| lcd = priv->lcd; |
| DEBUGASSERT(lcd->setpower != NULL); |
| |
| ret = lcd->setpower(lcd, power); |
| if (ret < 0) |
| { |
| lcderr("ERROR: LCD setpower() failed: %d\n", ret); |
| } |
| } |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: lcdfb_ioctl |
| ****************************************************************************/ |
| |
| static int lcdfb_ioctl(FAR struct fb_vtable_s *vtable, |
| int cmd, unsigned long arg) |
| { |
| int ret = -EINVAL; |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| |
| DEBUGASSERT(vtable != NULL); |
| |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL) |
| { |
| lcd = priv->lcd; |
| |
| if (lcd->ioctl) |
| { |
| ret = lcd->ioctl(lcd, cmd, arg); |
| } |
| else |
| { |
| ret = -ENOTTY; |
| } |
| } |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: lcdfb_open |
| ****************************************************************************/ |
| |
| static int lcdfb_open(FAR struct fb_vtable_s *vtable) |
| { |
| int ret = OK; |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| |
| DEBUGASSERT(vtable != NULL); |
| |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL) |
| { |
| lcd = priv->lcd; |
| |
| if (lcd->open) |
| { |
| ret = lcd->open(lcd); |
| } |
| } |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: lcdfb_close |
| ****************************************************************************/ |
| |
| static int lcdfb_close(FAR struct fb_vtable_s *vtable) |
| { |
| int ret = OK; |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| |
| DEBUGASSERT(vtable != NULL); |
| |
| priv = (FAR struct lcdfb_dev_s *)vtable; |
| |
| if (priv != NULL) |
| { |
| lcd = priv->lcd; |
| |
| if (lcd->close) |
| { |
| ret = lcd->close(lcd); |
| } |
| } |
| |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: up_fbinitialize |
| * |
| * Description: |
| * Initialize the framebuffer video hardware associated with the display. |
| * |
| * Input Parameters: |
| * display - In the case of hardware with multiple displays, this |
| * specifies the display. Normally this is zero. |
| * |
| * Returned Value: |
| * Zero is returned on success; a negated errno value is returned on any |
| * failure. |
| * |
| ****************************************************************************/ |
| |
| int up_fbinitialize(int display) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcd_dev_s *lcd; |
| struct fb_videoinfo_s vinfo; |
| struct fb_area_s area; |
| int ret; |
| |
| lcdinfo("display=%d\n", display); |
| DEBUGASSERT((unsigned)display < UINT8_MAX); |
| |
| /* Allocate the framebuffer state structure */ |
| |
| priv = kmm_zalloc(sizeof(struct lcdfb_dev_s)); |
| if (priv == NULL) |
| { |
| lcderr("ERROR: Failed to allocate state structure\n"); |
| return -ENOMEM; |
| } |
| |
| /* Initialize the LCD-independent fields of the state structure */ |
| |
| priv->display = display; |
| |
| priv->vtable.getvideoinfo = lcdfb_getvideoinfo, |
| priv->vtable.getplaneinfo = lcdfb_getplaneinfo, |
| #ifdef CONFIG_FB_CMAP |
| priv->vtable.getcmap = lcdfb_getcmap, |
| priv->vtable.putcmap = lcdfb_putcmap, |
| #endif |
| #ifdef CONFIG_FB_HWCURSOR |
| priv->vtable.getcursor = lcdfb_getcursor, |
| priv->vtable.setcursor = lcdfb_setcursor, |
| #endif |
| priv->vtable.updatearea = lcdfb_updateearea, |
| priv->vtable.setpower = lcdfb_setpower, |
| priv->vtable.ioctl = lcdfb_ioctl, |
| priv->vtable.open = lcdfb_open, |
| priv->vtable.close = lcdfb_close, |
| |
| #ifdef CONFIG_LCD_EXTERNINIT |
| /* Use external graphics driver initialization */ |
| |
| lcd = board_graphics_setup(display); |
| if (lcd == NULL) |
| { |
| gerr("ERROR: board_graphics_setup failed, devno=%d\n", display); |
| ret = -ENODEV; |
| goto errout_with_state; |
| } |
| #else |
| /* Initialize the LCD device */ |
| |
| ret = board_lcd_initialize(); |
| if (ret < 0) |
| { |
| lcderr("ERROR: board_lcd_initialize() failed: %d\n", ret); |
| goto errout_with_state; |
| } |
| |
| /* Get the device instance */ |
| |
| lcd = board_lcd_getdev(display); |
| if (lcd == NULL) |
| { |
| lcderr("ERROR: board_lcd_getdev failed, devno=%d\n", display); |
| ret = -ENODEV; |
| goto errout_with_lcd; |
| } |
| #endif |
| |
| priv->lcd = lcd; |
| |
| /* Initialize the LCD-dependent fields of the state structure */ |
| |
| DEBUGASSERT(lcd->getvideoinfo != NULL); |
| ret = lcd->getvideoinfo(lcd, &vinfo); |
| if (ret < 0) |
| { |
| lcderr("ERROR: LCD getvideoinfo() failed: %d\n", ret); |
| goto errout_with_lcd; |
| } |
| |
| priv->xres = vinfo.xres; |
| priv->yres = vinfo.yres; |
| |
| DEBUGASSERT(lcd->getplaneinfo != NULL); |
| ret = lcd->getplaneinfo(lcd, VIDEO_PLANE, &priv->pinfo); |
| if (ret < 0) |
| { |
| lcderr("ERROR: LCD getplaneinfo() failed: %d\n", ret); |
| goto errout_with_lcd; |
| } |
| |
| /* Allocate (and clear) the framebuffer */ |
| |
| priv->stride = ((size_t)priv->xres * priv->pinfo.bpp + 7) >> 3; |
| priv->fblen = priv->stride * priv->yres; |
| |
| priv->fbmem = kmm_zalloc(priv->fblen); |
| if (priv->fbmem == NULL) |
| { |
| lcderr("ERROR: Failed to allocate frame buffer memory\n"); |
| ret = -ENOMEM; |
| goto errout_with_lcd; |
| } |
| |
| /* Add the state structure to the list of framebuffer interfaces */ |
| |
| priv->flink = g_lcdfb; |
| g_lcdfb = priv; |
| |
| /* Write the entire framebuffer to the LCD */ |
| |
| area.x = 0; |
| area.y = 0; |
| area.w = priv->xres; |
| area.h = priv->yres; |
| |
| ret = lcdfb_updateearea(&priv->vtable, &area); |
| if (ret < 0) |
| { |
| lcderr("FB update failed: %d\n", ret); |
| } |
| |
| /* Turn the LCD on at 75% power */ |
| |
| priv->lcd->setpower(priv->lcd, ((3*CONFIG_LCD_MAXPOWER + 3) / 4)); |
| return OK; |
| |
| errout_with_lcd: |
| #ifndef CONFIG_LCD_EXTERNINIT |
| board_lcd_uninitialize(); |
| #endif |
| |
| errout_with_state: |
| kmm_free(priv); |
| return ret; |
| } |
| |
| /**************************************************************************** |
| * Name: up_fbgetvplane |
| * |
| * Description: |
| * Return a a reference to the framebuffer object for the specified video |
| * plane of the specified plane. Many OSDs support multiple planes of |
| * video. |
| * |
| * Input Parameters: |
| * display - In the case of hardware with multiple displays, this |
| * specifies the display. Normally this is zero. |
| * vplane - Identifies the plane being queried. |
| * |
| * Returned Value: |
| * A non-NULL pointer to the frame buffer access structure is returned on |
| * success; NULL is returned on any failure. |
| * |
| ****************************************************************************/ |
| |
| FAR struct fb_vtable_s *up_fbgetvplane(int display, int vplane) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| |
| lcdinfo("display=%d vplane=%d\n", display, vplane); |
| DEBUGASSERT(vplane == VIDEO_PLANE); |
| |
| /* Look up the LCD framebuffer state structure for this display. */ |
| |
| priv = lcdfb_find(display); |
| if (priv == NULL) |
| { |
| lcderr("ERROR: lcd_find(%d) failed\n", display); |
| return NULL; |
| } |
| |
| return &priv->vtable; |
| } |
| |
| /**************************************************************************** |
| * Name: up_fbuninitialize |
| * |
| * Description: |
| * Uninitialize the framebuffer support for the specified display. |
| * |
| * Input Parameters: |
| * display - In the case of hardware with multiple displays, this |
| * specifies the display. Normally this is zero. |
| * |
| * Returned Value: |
| * None |
| * |
| ****************************************************************************/ |
| |
| void up_fbuninitialize(int display) |
| { |
| FAR struct lcdfb_dev_s *priv; |
| FAR struct lcdfb_dev_s *prev; |
| |
| /* Find the LCD framebuffer state associated with this display. |
| * REVISIT: Semaphore protections is needed if there is concurrent access. |
| */ |
| |
| for (prev = NULL, priv = g_lcdfb; |
| priv != NULL; |
| prev = priv, priv = priv->flink) |
| { |
| if (priv->display == display) |
| { |
| /* Remove the state structure from the list */ |
| |
| if (prev != NULL) |
| { |
| prev->flink = priv->flink; |
| } |
| else |
| { |
| g_lcdfb = priv->flink; |
| } |
| |
| #ifndef CONFIG_LCD_EXTERNINIT |
| /* Uninitialize the LCD */ |
| |
| board_lcd_uninitialize(); |
| #endif |
| |
| /* Free the frame buffer allocation */ |
| |
| kmm_free(priv->fbmem); |
| |
| /* Free the state structure allocation */ |
| |
| kmm_free(priv); |
| break; |
| } |
| } |
| } |
| |
| #endif /* CONFIG_LCD_FRAMEBUFFER */ |