1d6aed566Sopenharmony_ci/****************************************************************************
2d6aed566Sopenharmony_ci * video/fb.c
3d6aed566Sopenharmony_ci * Framebuffer character driver
4d6aed566Sopenharmony_ci *
5d6aed566Sopenharmony_ci *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
6d6aed566Sopenharmony_ci *   Author: Gregory Nutt <gnutt@nuttx.org>
7d6aed566Sopenharmony_ci *
8d6aed566Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
9d6aed566Sopenharmony_ci * modification, are permitted provided that the following conditions
10d6aed566Sopenharmony_ci * are met:
11d6aed566Sopenharmony_ci *
12d6aed566Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
13d6aed566Sopenharmony_ci *    notice, this list of conditions and the following disclaimer.
14d6aed566Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
15d6aed566Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in
16d6aed566Sopenharmony_ci *    the documentation and/or other materials provided with the
17d6aed566Sopenharmony_ci *    distribution.
18d6aed566Sopenharmony_ci * 3. Neither the name NuttX nor the names of its contributors may be
19d6aed566Sopenharmony_ci *    used to endorse or promote products derived from this software
20d6aed566Sopenharmony_ci *    without specific prior written permission.
21d6aed566Sopenharmony_ci *
22d6aed566Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23d6aed566Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24d6aed566Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25d6aed566Sopenharmony_ci * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26d6aed566Sopenharmony_ci * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27d6aed566Sopenharmony_ci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28d6aed566Sopenharmony_ci * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
29d6aed566Sopenharmony_ci * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30d6aed566Sopenharmony_ci * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31d6aed566Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32d6aed566Sopenharmony_ci * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33d6aed566Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE.
34d6aed566Sopenharmony_ci *
35d6aed566Sopenharmony_ci ****************************************************************************/
36d6aed566Sopenharmony_ci
37d6aed566Sopenharmony_ci/****************************************************************************
38d6aed566Sopenharmony_ci * Included Files
39d6aed566Sopenharmony_ci ****************************************************************************/
40d6aed566Sopenharmony_ci
41d6aed566Sopenharmony_ci#include "fb.h"
42d6aed566Sopenharmony_ci
43d6aed566Sopenharmony_ci#include "errno.h"
44d6aed566Sopenharmony_ci#include "string.h"
45d6aed566Sopenharmony_ci
46d6aed566Sopenharmony_ci#define gerr        PRINT_ERR
47d6aed566Sopenharmony_ci#define DEBUGASSERT LOS_ASSERT
48d6aed566Sopenharmony_ci
49d6aed566Sopenharmony_ci/****************************************************************************
50d6aed566Sopenharmony_ci * Private Types
51d6aed566Sopenharmony_ci ****************************************************************************/
52d6aed566Sopenharmony_ci
53d6aed566Sopenharmony_ci/* This structure defines one framebuffer device.  Note that which is
54d6aed566Sopenharmony_ci * everything in this structure is constant data set up and initialization
55d6aed566Sopenharmony_ci * time.  Therefore, no there is requirement for serialized access to this
56d6aed566Sopenharmony_ci * structure.
57d6aed566Sopenharmony_ci */
58d6aed566Sopenharmony_ci
59d6aed566Sopenharmony_cistruct fb_chardev_s {
60d6aed566Sopenharmony_ci    struct fb_vtable_s *vtable; /* Framebuffer interface */
61d6aed566Sopenharmony_ci    void *fbmem;                /* Start of frame buffer memory */
62d6aed566Sopenharmony_ci    size_t fblen;               /* Size of the framebuffer */
63d6aed566Sopenharmony_ci    uint8_t plane;              /* Video plan number */
64d6aed566Sopenharmony_ci    uint8_t bpp;                /* Bits per pixel */
65d6aed566Sopenharmony_ci};
66d6aed566Sopenharmony_ci
67d6aed566Sopenharmony_ci#define FB_DEV_MAXNUM 32
68d6aed566Sopenharmony_cistatic struct fb_chardev_s *g_fb_dev[FB_DEV_MAXNUM] = {NULL};
69d6aed566Sopenharmony_ci
70d6aed566Sopenharmony_ci/****************************************************************************
71d6aed566Sopenharmony_ci * Public Functions
72d6aed566Sopenharmony_ci ****************************************************************************/
73d6aed566Sopenharmony_ciint fb_open(const char *key, struct fb_mem **result)
74d6aed566Sopenharmony_ci{
75d6aed566Sopenharmony_ci    struct fb_mem *fbmem = NULL;
76d6aed566Sopenharmony_ci    struct fb_chardev_s *fb;
77d6aed566Sopenharmony_ci    struct fb_vtable_s *vtable;
78d6aed566Sopenharmony_ci    int ret = -EINVAL;
79d6aed566Sopenharmony_ci
80d6aed566Sopenharmony_ci    if (key == NULL || strlen(key) >= PATH_MAX) {
81d6aed566Sopenharmony_ci        return -EINVAL;
82d6aed566Sopenharmony_ci    }
83d6aed566Sopenharmony_ci    FbMemHold();
84d6aed566Sopenharmony_ci    ret = FbMemLookup(key, &fbmem, 0);
85d6aed566Sopenharmony_ci    FbMemDrop();
86d6aed566Sopenharmony_ci    if (ret == 0) {
87d6aed566Sopenharmony_ci        fb = (struct fb_chardev_s *)fbmem->data;
88d6aed566Sopenharmony_ci        if (fb == NULL) {
89d6aed566Sopenharmony_ci            return -ENODEV;
90d6aed566Sopenharmony_ci        }
91d6aed566Sopenharmony_ci
92d6aed566Sopenharmony_ci        vtable = fb->vtable;
93d6aed566Sopenharmony_ci        if (vtable == NULL) {
94d6aed566Sopenharmony_ci            return -EINVAL;
95d6aed566Sopenharmony_ci        }
96d6aed566Sopenharmony_ci
97d6aed566Sopenharmony_ci        if (vtable->fb_open) {
98d6aed566Sopenharmony_ci            ret = vtable->fb_open(vtable);
99d6aed566Sopenharmony_ci            if (ret == 0) {
100d6aed566Sopenharmony_ci                *result = fbmem;
101d6aed566Sopenharmony_ci            }
102d6aed566Sopenharmony_ci        }
103d6aed566Sopenharmony_ci    }
104d6aed566Sopenharmony_ci    return ret;
105d6aed566Sopenharmony_ci}
106d6aed566Sopenharmony_ci
107d6aed566Sopenharmony_ciint fb_close(struct fb_mem *fbmem)
108d6aed566Sopenharmony_ci{
109d6aed566Sopenharmony_ci    struct fb_chardev_s *fb;
110d6aed566Sopenharmony_ci    struct fb_vtable_s *vtable;
111d6aed566Sopenharmony_ci    int ret = -EINVAL;
112d6aed566Sopenharmony_ci
113d6aed566Sopenharmony_ci    fb = (struct fb_chardev_s *)fbmem->data;
114d6aed566Sopenharmony_ci    if (fb == NULL) {
115d6aed566Sopenharmony_ci        return -ENODEV;
116d6aed566Sopenharmony_ci    }
117d6aed566Sopenharmony_ci
118d6aed566Sopenharmony_ci    vtable = fb->vtable;
119d6aed566Sopenharmony_ci    if (vtable == NULL) {
120d6aed566Sopenharmony_ci        return -EINVAL;
121d6aed566Sopenharmony_ci    }
122d6aed566Sopenharmony_ci
123d6aed566Sopenharmony_ci    if (vtable->fb_release) {
124d6aed566Sopenharmony_ci        ret = vtable->fb_release(vtable);
125d6aed566Sopenharmony_ci    }
126d6aed566Sopenharmony_ci    return ret;
127d6aed566Sopenharmony_ci}
128d6aed566Sopenharmony_ci
129d6aed566Sopenharmony_ciint fb_ioctl(struct fb_mem *fbMem, int cmd, unsigned long arg)
130d6aed566Sopenharmony_ci{
131d6aed566Sopenharmony_ci    struct fb_chardev_s *fb = NULL;
132d6aed566Sopenharmony_ci    int ret;
133d6aed566Sopenharmony_ci
134d6aed566Sopenharmony_ci    /* Get the framebuffer instance */
135d6aed566Sopenharmony_ci    fb = (struct fb_chardev_s *)fbMem->data;
136d6aed566Sopenharmony_ci    /* Process the IOCTL command */
137d6aed566Sopenharmony_ci
138d6aed566Sopenharmony_ci    switch (cmd) {
139d6aed566Sopenharmony_ci        case FIOC_MMAP:
140d6aed566Sopenharmony_ci            { /* Get color plane info */
141d6aed566Sopenharmony_ci                void **ppv = (void **)((uintptr_t)arg);
142d6aed566Sopenharmony_ci                /* Return the address corresponding to the start of frame buffer. */
143d6aed566Sopenharmony_ci                DEBUGASSERT(ppv != NULL);
144d6aed566Sopenharmony_ci                *ppv = fb->fbmem;
145d6aed566Sopenharmony_ci                ret = OK;
146d6aed566Sopenharmony_ci            }
147d6aed566Sopenharmony_ci            break;
148d6aed566Sopenharmony_ci
149d6aed566Sopenharmony_ci        case FBIOGET_VIDEOINFO:
150d6aed566Sopenharmony_ci            { /* Get color plane info */
151d6aed566Sopenharmony_ci                struct fb_videoinfo_s *vinfo = (struct fb_videoinfo_s *)((uintptr_t)arg);
152d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->getvideoinfo != NULL);
153d6aed566Sopenharmony_ci                ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
154d6aed566Sopenharmony_ci            }
155d6aed566Sopenharmony_ci            break;
156d6aed566Sopenharmony_ci
157d6aed566Sopenharmony_ci        case FBIOGET_PLANEINFO:
158d6aed566Sopenharmony_ci            { /* Get video plane info */
159d6aed566Sopenharmony_ci                struct fb_planeinfo_s *pinfo = (struct fb_planeinfo_s *)((uintptr_t)arg);
160d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->getplaneinfo != NULL);
161d6aed566Sopenharmony_ci                ret = fb->vtable->getplaneinfo(fb->vtable, fb->plane, &pinfo);
162d6aed566Sopenharmony_ci            }
163d6aed566Sopenharmony_ci            break;
164d6aed566Sopenharmony_ci
165d6aed566Sopenharmony_ci#ifdef CONFIG_FB_CMAP
166d6aed566Sopenharmony_ci        case FBIOGET_CMAP:
167d6aed566Sopenharmony_ci            { /* Get RGB color mapping */
168d6aed566Sopenharmony_ci                struct fb_cmap_s *cmap = (struct fb_cmap_s *)((uintptr_t)arg);
169d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->getcmap != NULL);
170d6aed566Sopenharmony_ci                ret = fb->vtable->getcmap(fb->vtable, &cmap);
171d6aed566Sopenharmony_ci            }
172d6aed566Sopenharmony_ci            break;
173d6aed566Sopenharmony_ci
174d6aed566Sopenharmony_ci        case FBIOPUT_CMAP:
175d6aed566Sopenharmony_ci            { /* Put RGB color mapping */
176d6aed566Sopenharmony_ci                struct fb_cmap_s *cmap = (struct fb_cmap_s *)((uintptr_t)arg);
177d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->putcmap != NULL);
178d6aed566Sopenharmony_ci                ret = fb->vtable->putcmap(fb->vtable, &cmap);
179d6aed566Sopenharmony_ci            }
180d6aed566Sopenharmony_ci            break;
181d6aed566Sopenharmony_ci#endif
182d6aed566Sopenharmony_ci#ifdef CONFIG_FB_HWCURSOR
183d6aed566Sopenharmony_ci        case FBIOGET_CURSOR:
184d6aed566Sopenharmony_ci            { /* Get cursor attributes */
185d6aed566Sopenharmony_ci                struct fb_cursorattrib_s *attrib = (struct fb_cursorattrib_s *)((uintptr_t)arg);
186d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->getcursor != NULL);
187d6aed566Sopenharmony_ci                ret = fb->vtable->getcursor(fb->vtable, &attrib);
188d6aed566Sopenharmony_ci            }
189d6aed566Sopenharmony_ci            break;
190d6aed566Sopenharmony_ci
191d6aed566Sopenharmony_ci        case FBIOPUT_CURSOR:
192d6aed566Sopenharmony_ci            { /* Set cursor attributes */
193d6aed566Sopenharmony_ci                struct fb_setcursor_s *cursor = (struct fb_setcursor_s *)((uintptr_t)arg);
194d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->setcursor != NULL);
195d6aed566Sopenharmony_ci                ret = fb->vtable->setcursor(fb->vtable, &cursor);
196d6aed566Sopenharmony_ci            }
197d6aed566Sopenharmony_ci            break;
198d6aed566Sopenharmony_ci#endif
199d6aed566Sopenharmony_ci
200d6aed566Sopenharmony_ci#ifdef CONFIG_FB_UPDATE
201d6aed566Sopenharmony_ci        case FBIO_UPDATE:
202d6aed566Sopenharmony_ci            { /* Update the modified framebuffer data  */
203d6aed566Sopenharmony_ci                struct fb_area_s *area = (struct fb_area_s *)((uintptr_t)arg);
204d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->updatearea != NULL);
205d6aed566Sopenharmony_ci                ret = fb->vtable->updatearea(fb->vtable, area);
206d6aed566Sopenharmony_ci            }
207d6aed566Sopenharmony_ci            break;
208d6aed566Sopenharmony_ci#endif
209d6aed566Sopenharmony_ci
210d6aed566Sopenharmony_ci#ifdef CONFIG_FB_SYNC
211d6aed566Sopenharmony_ci        case FBIO_WAITFORVSYNC:
212d6aed566Sopenharmony_ci            { /* Wait upon vertical sync */
213d6aed566Sopenharmony_ci                ret = fb->vtable->waitforvsync(fb->vtable);
214d6aed566Sopenharmony_ci            }
215d6aed566Sopenharmony_ci            break;
216d6aed566Sopenharmony_ci#endif
217d6aed566Sopenharmony_ci
218d6aed566Sopenharmony_ci#ifdef CONFIG_FB_OVERLAY
219d6aed566Sopenharmony_ci        case FBIO_SELECT_OVERLAY:
220d6aed566Sopenharmony_ci            { /* Select video overlay */
221d6aed566Sopenharmony_ci                struct fb_overlayinfo_s oinfo;
222d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->getoverlayinfo != NULL);
223d6aed566Sopenharmony_ci                ret = fb->vtable->getoverlayinfo(fb->vtable, arg, &oinfo);
224d6aed566Sopenharmony_ci                if (ret == OK) {
225d6aed566Sopenharmony_ci                    fb->fbmem = oinfo.fbmem;
226d6aed566Sopenharmony_ci                    fb->fblen = oinfo.fblen;
227d6aed566Sopenharmony_ci                    fb->bpp = oinfo.bpp;
228d6aed566Sopenharmony_ci                }
229d6aed566Sopenharmony_ci            }
230d6aed566Sopenharmony_ci            break;
231d6aed566Sopenharmony_ci
232d6aed566Sopenharmony_ci        case FBIOGET_OVERLAYINFO:
233d6aed566Sopenharmony_ci            { /* Get video overlay info */
234d6aed566Sopenharmony_ci                struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
235d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->getoverlayinfo != NULL);
236d6aed566Sopenharmony_ci                ret = fb->vtable->getoverlayinfo(fb->vtable, oinfo->overlay, &oinfo);
237d6aed566Sopenharmony_ci            }
238d6aed566Sopenharmony_ci            break;
239d6aed566Sopenharmony_ci
240d6aed566Sopenharmony_ci        case FBIOSET_TRANSP:
241d6aed566Sopenharmony_ci            { /* Set video overlay transparency */
242d6aed566Sopenharmony_ci                struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
243d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->settransp != NULL);
244d6aed566Sopenharmony_ci                ret = fb->vtable->settransp(fb->vtable, &oinfo);
245d6aed566Sopenharmony_ci            }
246d6aed566Sopenharmony_ci            break;
247d6aed566Sopenharmony_ci
248d6aed566Sopenharmony_ci        case FBIOSET_CHROMAKEY:
249d6aed566Sopenharmony_ci            { /* Set video overlay chroma key */
250d6aed566Sopenharmony_ci                struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
251d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->setchromakey != NULL);
252d6aed566Sopenharmony_ci                ret = fb->vtable->setchromakey(fb->vtable, &oinfo);
253d6aed566Sopenharmony_ci            }
254d6aed566Sopenharmony_ci            break;
255d6aed566Sopenharmony_ci
256d6aed566Sopenharmony_ci        case FBIOSET_COLOR:
257d6aed566Sopenharmony_ci            { /* Set video overlay color */
258d6aed566Sopenharmony_ci                struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
259d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->setcolor != NULL);
260d6aed566Sopenharmony_ci                ret = fb->vtable->setcolor(fb->vtable, &oinfo);
261d6aed566Sopenharmony_ci            }
262d6aed566Sopenharmony_ci            break;
263d6aed566Sopenharmony_ci
264d6aed566Sopenharmony_ci        case FBIOSET_BLANK:
265d6aed566Sopenharmony_ci            { /* Blank or unblank video overlay */
266d6aed566Sopenharmony_ci                struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
267d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->setblank != NULL);
268d6aed566Sopenharmony_ci                ret = fb->vtable->setblank(fb->vtable, &oinfo);
269d6aed566Sopenharmony_ci            }
270d6aed566Sopenharmony_ci            break;
271d6aed566Sopenharmony_ci
272d6aed566Sopenharmony_ci        case FBIOSET_AREA:
273d6aed566Sopenharmony_ci            { /* Set active video overlay area */
274d6aed566Sopenharmony_ci                struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
275d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->setarea != NULL);
276d6aed566Sopenharmony_ci                ret = fb->vtable->setarea(fb->vtable, &oinfo);
277d6aed566Sopenharmony_ci            }
278d6aed566Sopenharmony_ci            break;
279d6aed566Sopenharmony_ci
280d6aed566Sopenharmony_ci#ifdef CONFIG_FB_OVERLAY_BLIT
281d6aed566Sopenharmony_ci        case FBIOSET_BLIT:
282d6aed566Sopenharmony_ci            { /* Blit operation between video overlays */
283d6aed566Sopenharmony_ci                struct fb_overlayblit_s *blit = (struct fb_overlayblit_s *)((uintptr_t)arg);
284d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->blit != NULL);
285d6aed566Sopenharmony_ci                ret = fb->vtable->blit(fb->vtable, &blit);
286d6aed566Sopenharmony_ci            }
287d6aed566Sopenharmony_ci            break;
288d6aed566Sopenharmony_ci
289d6aed566Sopenharmony_ci        case FBIOSET_BLEND:
290d6aed566Sopenharmony_ci            { /* Blend operation between video overlays */
291d6aed566Sopenharmony_ci                struct fb_overlayblend_s *blend = (struct fb_overlayblend_s *)((uintptr_t)arg);
292d6aed566Sopenharmony_ci                DEBUGASSERT(fb->vtable != NULL && fb->vtable->blend != NULL);
293d6aed566Sopenharmony_ci                ret = fb->vtable->blend(fb->vtable, &blend);
294d6aed566Sopenharmony_ci            }
295d6aed566Sopenharmony_ci            break;
296d6aed566Sopenharmony_ci#endif
297d6aed566Sopenharmony_ci#endif /* CONFIG_FB_OVERLAY */
298d6aed566Sopenharmony_ci
299d6aed566Sopenharmony_ci        default:
300d6aed566Sopenharmony_ci            DEBUGASSERT(fb->vtable != NULL && fb->vtable->fb_ioctl != NULL);
301d6aed566Sopenharmony_ci            ret = fb->vtable->fb_ioctl(fb->vtable, cmd, arg);
302d6aed566Sopenharmony_ci            break;
303d6aed566Sopenharmony_ci    }
304d6aed566Sopenharmony_ci
305d6aed566Sopenharmony_ci    return ret;
306d6aed566Sopenharmony_ci}
307d6aed566Sopenharmony_ci
308d6aed566Sopenharmony_ciint getplaneinfo(struct fb_mem *fbmem, struct fb_planeinfo_s **result)
309d6aed566Sopenharmony_ci{
310d6aed566Sopenharmony_ci    int ret;
311d6aed566Sopenharmony_ci    struct fb_chardev_s *fb;
312d6aed566Sopenharmony_ci
313d6aed566Sopenharmony_ci    fb = (struct fb_chardev_s *)fbmem->data;
314d6aed566Sopenharmony_ci
315d6aed566Sopenharmony_ci    struct fb_planeinfo_s pinfo;
316d6aed566Sopenharmony_ci
317d6aed566Sopenharmony_ci    ret = fb->vtable->getplaneinfo(fb->vtable, fb->plane, &pinfo);
318d6aed566Sopenharmony_ci    if (ret == 0) {
319d6aed566Sopenharmony_ci        *result = &pinfo;
320d6aed566Sopenharmony_ci    }
321d6aed566Sopenharmony_ci
322d6aed566Sopenharmony_ci    return 0;
323d6aed566Sopenharmony_ci}
324d6aed566Sopenharmony_ci
325d6aed566Sopenharmony_ci/****************************************************************************
326d6aed566Sopenharmony_ci * Name: fb_register
327d6aed566Sopenharmony_ci *
328d6aed566Sopenharmony_ci * Description:
329d6aed566Sopenharmony_ci *   Register the framebuffer character device at /dev/fbN where N is the
330d6aed566Sopenharmony_ci *   display number if the devices supports only a single plane.  If the
331d6aed566Sopenharmony_ci *   hardware supports multiple color planes, then the device will be
332d6aed566Sopenharmony_ci *   registered at /dev/fbN.M where N is the again display number but M
333d6aed566Sopenharmony_ci *   is the display plane.
334d6aed566Sopenharmony_ci *
335d6aed566Sopenharmony_ci * Input Parameters:
336d6aed566Sopenharmony_ci *   display - The display number for the case of boards supporting multiple
337d6aed566Sopenharmony_ci *             displays or for hardware that supports multiple
338d6aed566Sopenharmony_ci *             layers (each layer is consider a display).  Typically zero.
339d6aed566Sopenharmony_ci *   plane   - Identifies the color plane on hardware that supports separate
340d6aed566Sopenharmony_ci *             framebuffer "planes" for each color component.
341d6aed566Sopenharmony_ci *
342d6aed566Sopenharmony_ci * Returned Value:
343d6aed566Sopenharmony_ci *   Zero (OK) is returned success; a negated errno value is returned on any
344d6aed566Sopenharmony_ci *   failure.
345d6aed566Sopenharmony_ci *
346d6aed566Sopenharmony_ci ****************************************************************************/
347d6aed566Sopenharmony_ci
348d6aed566Sopenharmony_ciint fb_register(int display, int plane)
349d6aed566Sopenharmony_ci{
350d6aed566Sopenharmony_ci    struct fb_chardev_s *fb = NULL;
351d6aed566Sopenharmony_ci    struct fb_videoinfo_s vinfo;
352d6aed566Sopenharmony_ci    struct fb_planeinfo_s pinfo;
353d6aed566Sopenharmony_ci#ifdef CONFIG_FB_OVERLAY
354d6aed566Sopenharmony_ci    struct fb_overlayinfo_s oinfo;
355d6aed566Sopenharmony_ci#endif
356d6aed566Sopenharmony_ci    char devname[16];
357d6aed566Sopenharmony_ci    int nplanes;
358d6aed566Sopenharmony_ci    int ret;
359d6aed566Sopenharmony_ci
360d6aed566Sopenharmony_ci    if (display < 0 || display >= FB_DEV_MAXNUM) return -EINVAL;
361d6aed566Sopenharmony_ci
362d6aed566Sopenharmony_ci    /* Allocate a framebuffer state instance */
363d6aed566Sopenharmony_ci    fb = (struct fb_chardev_s *)malloc(sizeof(struct fb_chardev_s));
364d6aed566Sopenharmony_ci    if (fb == NULL) {
365d6aed566Sopenharmony_ci        return -ENOMEM;
366d6aed566Sopenharmony_ci    }
367d6aed566Sopenharmony_ci
368d6aed566Sopenharmony_ci    /* Initialize the frame buffer device. */
369d6aed566Sopenharmony_ci    ret = up_fbinitialize(display);
370d6aed566Sopenharmony_ci    if (ret < 0) {
371d6aed566Sopenharmony_ci        gerr("ERROR: up_fbinitialize() failed for display %d: %d\n", display, ret);
372d6aed566Sopenharmony_ci        goto errout_with_fb;
373d6aed566Sopenharmony_ci    }
374d6aed566Sopenharmony_ci
375d6aed566Sopenharmony_ci    DEBUGASSERT((unsigned)plane <= UINT8_MAX);
376d6aed566Sopenharmony_ci    fb->plane = plane;
377d6aed566Sopenharmony_ci
378d6aed566Sopenharmony_ci    fb->vtable = up_fbgetvplane(display, plane);
379d6aed566Sopenharmony_ci    if (fb->vtable == NULL) {
380d6aed566Sopenharmony_ci        gerr("ERROR: up_fbgetvplane() failed, vplane=%d\n", plane);
381d6aed566Sopenharmony_ci        goto errout_with_fb;
382d6aed566Sopenharmony_ci    }
383d6aed566Sopenharmony_ci
384d6aed566Sopenharmony_ci    /* Initialize the frame buffer instance. */
385d6aed566Sopenharmony_ci    DEBUGASSERT(fb->vtable->getvideoinfo != NULL);
386d6aed566Sopenharmony_ci    ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
387d6aed566Sopenharmony_ci    if (ret < 0) {
388d6aed566Sopenharmony_ci        gerr("ERROR: getvideoinfo() failed: %d\n", ret);
389d6aed566Sopenharmony_ci        goto errout_with_fb;
390d6aed566Sopenharmony_ci    }
391d6aed566Sopenharmony_ci
392d6aed566Sopenharmony_ci    nplanes = vinfo.nplanes;
393d6aed566Sopenharmony_ci    DEBUGASSERT(vinfo.nplanes > 0 && (unsigned)plane < vinfo.nplanes);
394d6aed566Sopenharmony_ci
395d6aed566Sopenharmony_ci    DEBUGASSERT(fb->vtable->getplaneinfo != NULL);
396d6aed566Sopenharmony_ci    ret = fb->vtable->getplaneinfo(fb->vtable, plane, &pinfo);
397d6aed566Sopenharmony_ci    if (ret < 0) {
398d6aed566Sopenharmony_ci        gerr("ERROR: getplaneinfo() failed: %d\n", ret);
399d6aed566Sopenharmony_ci        goto errout_with_fb;
400d6aed566Sopenharmony_ci    }
401d6aed566Sopenharmony_ci
402d6aed566Sopenharmony_ci    fb->fbmem = pinfo.fbmem;
403d6aed566Sopenharmony_ci    fb->fblen = pinfo.fblen;
404d6aed566Sopenharmony_ci    fb->bpp = pinfo.bpp;
405d6aed566Sopenharmony_ci
406d6aed566Sopenharmony_ci    /* Clear the framebuffer memory */
407d6aed566Sopenharmony_ci    memset(pinfo.fbmem, 0, pinfo.fblen);
408d6aed566Sopenharmony_ci
409d6aed566Sopenharmony_ci#ifdef CONFIG_FB_OVERLAY
410d6aed566Sopenharmony_ci    /* Initialize first overlay but do not select */
411d6aed566Sopenharmony_ci    DEBUGASSERT(fb->vtable->getoverlayinfo != NULL);
412d6aed566Sopenharmony_ci    ret = fb->vtable->getoverlayinfo(fb->vtable, 0, &oinfo);
413d6aed566Sopenharmony_ci    if (ret < 0) {
414d6aed566Sopenharmony_ci        gerr("ERROR: getoverlayinfo() failed: %d\n", ret);
415d6aed566Sopenharmony_ci        goto errout_with_fb;
416d6aed566Sopenharmony_ci    }
417d6aed566Sopenharmony_ci
418d6aed566Sopenharmony_ci    /* Clear the overlay memory. Necessary when plane 0 and overlay 0
419d6aed566Sopenharmony_ci     * different.
420d6aed566Sopenharmony_ci     */
421d6aed566Sopenharmony_ci
422d6aed566Sopenharmony_ci    memset(oinfo.fbmem, 0, oinfo.fblen);
423d6aed566Sopenharmony_ci#endif
424d6aed566Sopenharmony_ci
425d6aed566Sopenharmony_ci    /* Register the framebuffer device */
426d6aed566Sopenharmony_ci    if (nplanes < 2) {
427d6aed566Sopenharmony_ci        (void)sprintf_s(devname, 16, "/dev/fb%d", display);
428d6aed566Sopenharmony_ci    } else {
429d6aed566Sopenharmony_ci        (void)sprintf_s(devname, 16, "/dev/fb%d.%d", display, plane);
430d6aed566Sopenharmony_ci    }
431d6aed566Sopenharmony_ci
432d6aed566Sopenharmony_ci    ret = register_driver(devname, (void *)fb);
433d6aed566Sopenharmony_ci    if (ret < 0) {
434d6aed566Sopenharmony_ci        gerr("ERROR: register_driver() failed: %d\n", ret);
435d6aed566Sopenharmony_ci        goto errout_with_fb;
436d6aed566Sopenharmony_ci    }
437d6aed566Sopenharmony_ci
438d6aed566Sopenharmony_ci    g_fb_dev[display] = fb;
439d6aed566Sopenharmony_ci
440d6aed566Sopenharmony_ci    return OK;
441d6aed566Sopenharmony_ci
442d6aed566Sopenharmony_cierrout_with_fb:
443d6aed566Sopenharmony_ci    free(fb);
444d6aed566Sopenharmony_ci    return ret;
445d6aed566Sopenharmony_ci}
446d6aed566Sopenharmony_ci
447d6aed566Sopenharmony_ciint fb_unregister(int display)
448d6aed566Sopenharmony_ci{
449d6aed566Sopenharmony_ci    struct fb_chardev_s *fb = NULL;
450d6aed566Sopenharmony_ci    char devname[16];
451d6aed566Sopenharmony_ci
452d6aed566Sopenharmony_ci    if (display < 0 || display >= FB_DEV_MAXNUM) return -EINVAL;
453d6aed566Sopenharmony_ci
454d6aed566Sopenharmony_ci    (void)sprintf_s(devname, 16, "/dev/fb%d", display);
455d6aed566Sopenharmony_ci    unregister_driver(devname);
456d6aed566Sopenharmony_ci
457d6aed566Sopenharmony_ci    up_fbuninitialize(display);
458d6aed566Sopenharmony_ci
459d6aed566Sopenharmony_ci    fb = g_fb_dev[display];
460d6aed566Sopenharmony_ci    free(fb);
461d6aed566Sopenharmony_ci    g_fb_dev[display] = NULL;
462d6aed566Sopenharmony_ci
463d6aed566Sopenharmony_ci    return 0;
464d6aed566Sopenharmony_ci}