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