• 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                 /* Return the address corresponding to the start of frame buffer. */
143                 DEBUGASSERT(ppv != NULL);
144                 *ppv = fb->fbmem;
145                 ret = OK;
146             }
147             break;
148 
149         case FBIOGET_VIDEOINFO:
150             { /* Get color plane info */
151                 struct fb_videoinfo_s *vinfo = (struct fb_videoinfo_s *)((uintptr_t)arg);
152                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->getvideoinfo != NULL);
153                 ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
154             }
155             break;
156 
157         case FBIOGET_PLANEINFO:
158             { /* Get video plane info */
159                 struct fb_planeinfo_s *pinfo = (struct fb_planeinfo_s *)((uintptr_t)arg);
160                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->getplaneinfo != NULL);
161                 ret = fb->vtable->getplaneinfo(fb->vtable, fb->plane, &pinfo);
162             }
163             break;
164 
165 #ifdef CONFIG_FB_CMAP
166         case FBIOGET_CMAP:
167             { /* Get RGB color mapping */
168                 struct fb_cmap_s *cmap = (struct fb_cmap_s *)((uintptr_t)arg);
169                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->getcmap != NULL);
170                 ret = fb->vtable->getcmap(fb->vtable, &cmap);
171             }
172             break;
173 
174         case FBIOPUT_CMAP:
175             { /* Put RGB color mapping */
176                 struct fb_cmap_s *cmap = (struct fb_cmap_s *)((uintptr_t)arg);
177                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->putcmap != NULL);
178                 ret = fb->vtable->putcmap(fb->vtable, &cmap);
179             }
180             break;
181 #endif
182 #ifdef CONFIG_FB_HWCURSOR
183         case FBIOGET_CURSOR:
184             { /* Get cursor attributes */
185                 struct fb_cursorattrib_s *attrib = (struct fb_cursorattrib_s *)((uintptr_t)arg);
186                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->getcursor != NULL);
187                 ret = fb->vtable->getcursor(fb->vtable, &attrib);
188             }
189             break;
190 
191         case FBIOPUT_CURSOR:
192             { /* Set cursor attributes */
193                 struct fb_setcursor_s *cursor = (struct fb_setcursor_s *)((uintptr_t)arg);
194                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->setcursor != NULL);
195                 ret = fb->vtable->setcursor(fb->vtable, &cursor);
196             }
197             break;
198 #endif
199 
200 #ifdef CONFIG_FB_UPDATE
201         case FBIO_UPDATE:
202             { /* Update the modified framebuffer data  */
203                 struct fb_area_s *area = (struct fb_area_s *)((uintptr_t)arg);
204                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->updatearea != NULL);
205                 ret = fb->vtable->updatearea(fb->vtable, area);
206             }
207             break;
208 #endif
209 
210 #ifdef CONFIG_FB_SYNC
211         case FBIO_WAITFORVSYNC:
212             { /* Wait upon vertical sync */
213                 ret = fb->vtable->waitforvsync(fb->vtable);
214             }
215             break;
216 #endif
217 
218 #ifdef CONFIG_FB_OVERLAY
219         case FBIO_SELECT_OVERLAY:
220             { /* Select video overlay */
221                 struct fb_overlayinfo_s oinfo;
222                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->getoverlayinfo != NULL);
223                 ret = fb->vtable->getoverlayinfo(fb->vtable, arg, &oinfo);
224                 if (ret == OK) {
225                     fb->fbmem = oinfo.fbmem;
226                     fb->fblen = oinfo.fblen;
227                     fb->bpp = oinfo.bpp;
228                 }
229             }
230             break;
231 
232         case FBIOGET_OVERLAYINFO:
233             { /* Get video overlay info */
234                 struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
235                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->getoverlayinfo != NULL);
236                 ret = fb->vtable->getoverlayinfo(fb->vtable, oinfo->overlay, &oinfo);
237             }
238             break;
239 
240         case FBIOSET_TRANSP:
241             { /* Set video overlay transparency */
242                 struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
243                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->settransp != NULL);
244                 ret = fb->vtable->settransp(fb->vtable, &oinfo);
245             }
246             break;
247 
248         case FBIOSET_CHROMAKEY:
249             { /* Set video overlay chroma key */
250                 struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
251                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->setchromakey != NULL);
252                 ret = fb->vtable->setchromakey(fb->vtable, &oinfo);
253             }
254             break;
255 
256         case FBIOSET_COLOR:
257             { /* Set video overlay color */
258                 struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
259                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->setcolor != NULL);
260                 ret = fb->vtable->setcolor(fb->vtable, &oinfo);
261             }
262             break;
263 
264         case FBIOSET_BLANK:
265             { /* Blank or unblank video overlay */
266                 struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
267                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->setblank != NULL);
268                 ret = fb->vtable->setblank(fb->vtable, &oinfo);
269             }
270             break;
271 
272         case FBIOSET_AREA:
273             { /* Set active video overlay area */
274                 struct fb_overlayinfo_s *oinfo = (struct fb_overlayinfo_s *)((uintptr_t)arg);
275                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->setarea != NULL);
276                 ret = fb->vtable->setarea(fb->vtable, &oinfo);
277             }
278             break;
279 
280 #ifdef CONFIG_FB_OVERLAY_BLIT
281         case FBIOSET_BLIT:
282             { /* Blit operation between video overlays */
283                 struct fb_overlayblit_s *blit = (struct fb_overlayblit_s *)((uintptr_t)arg);
284                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->blit != NULL);
285                 ret = fb->vtable->blit(fb->vtable, &blit);
286             }
287             break;
288 
289         case FBIOSET_BLEND:
290             { /* Blend operation between video overlays */
291                 struct fb_overlayblend_s *blend = (struct fb_overlayblend_s *)((uintptr_t)arg);
292                 DEBUGASSERT(fb->vtable != NULL && fb->vtable->blend != NULL);
293                 ret = fb->vtable->blend(fb->vtable, &blend);
294             }
295             break;
296 #endif
297 #endif /* CONFIG_FB_OVERLAY */
298 
299         default:
300             DEBUGASSERT(fb->vtable != NULL && fb->vtable->fb_ioctl != NULL);
301             ret = fb->vtable->fb_ioctl(fb->vtable, cmd, arg);
302             break;
303     }
304 
305     return ret;
306 }
307 
getplaneinfo(struct fb_mem * fbmem,struct fb_planeinfo_s ** result)308 int getplaneinfo(struct fb_mem *fbmem, struct fb_planeinfo_s **result)
309 {
310     int ret;
311     struct fb_chardev_s *fb;
312 
313     fb = (struct fb_chardev_s *)fbmem->data;
314 
315     struct fb_planeinfo_s pinfo;
316 
317     ret = fb->vtable->getplaneinfo(fb->vtable, fb->plane, &pinfo);
318     if (ret == 0) {
319         *result = &pinfo;
320     }
321 
322     return 0;
323 }
324 
325 /****************************************************************************
326  * Name: fb_register
327  *
328  * Description:
329  *   Register the framebuffer character device at /dev/fbN where N is the
330  *   display number if the devices supports only a single plane.  If the
331  *   hardware supports multiple color planes, then the device will be
332  *   registered at /dev/fbN.M where N is the again display number but M
333  *   is the display plane.
334  *
335  * Input Parameters:
336  *   display - The display number for the case of boards supporting multiple
337  *             displays or for hardware that supports multiple
338  *             layers (each layer is consider a display).  Typically zero.
339  *   plane   - Identifies the color plane on hardware that supports separate
340  *             framebuffer "planes" for each color component.
341  *
342  * Returned Value:
343  *   Zero (OK) is returned success; a negated errno value is returned on any
344  *   failure.
345  *
346  ****************************************************************************/
347 
fb_register(int display,int plane)348 int fb_register(int display, int plane)
349 {
350     struct fb_chardev_s *fb = NULL;
351     struct fb_videoinfo_s vinfo;
352     struct fb_planeinfo_s pinfo;
353 #ifdef CONFIG_FB_OVERLAY
354     struct fb_overlayinfo_s oinfo;
355 #endif
356     char devname[16];
357     int nplanes;
358     int ret;
359 
360     if (display < 0 || display >= FB_DEV_MAXNUM) return -EINVAL;
361 
362     /* Allocate a framebuffer state instance */
363     fb = (struct fb_chardev_s *)malloc(sizeof(struct fb_chardev_s));
364     if (fb == NULL) {
365         return -ENOMEM;
366     }
367 
368     /* Initialize the frame buffer device. */
369     ret = up_fbinitialize(display);
370     if (ret < 0) {
371         gerr("ERROR: up_fbinitialize() failed for display %d: %d\n", display, ret);
372         goto errout_with_fb;
373     }
374 
375     DEBUGASSERT((unsigned)plane <= UINT8_MAX);
376     fb->plane = plane;
377 
378     fb->vtable = up_fbgetvplane(display, plane);
379     if (fb->vtable == NULL) {
380         gerr("ERROR: up_fbgetvplane() failed, vplane=%d\n", plane);
381         goto errout_with_fb;
382     }
383 
384     /* Initialize the frame buffer instance. */
385     DEBUGASSERT(fb->vtable->getvideoinfo != NULL);
386     ret = fb->vtable->getvideoinfo(fb->vtable, &vinfo);
387     if (ret < 0) {
388         gerr("ERROR: getvideoinfo() failed: %d\n", ret);
389         goto errout_with_fb;
390     }
391 
392     nplanes = vinfo.nplanes;
393     DEBUGASSERT(vinfo.nplanes > 0 && (unsigned)plane < vinfo.nplanes);
394 
395     DEBUGASSERT(fb->vtable->getplaneinfo != NULL);
396     ret = fb->vtable->getplaneinfo(fb->vtable, plane, &pinfo);
397     if (ret < 0) {
398         gerr("ERROR: getplaneinfo() failed: %d\n", ret);
399         goto errout_with_fb;
400     }
401 
402     fb->fbmem = pinfo.fbmem;
403     fb->fblen = pinfo.fblen;
404     fb->bpp = pinfo.bpp;
405 
406     /* Clear the framebuffer memory */
407     memset(pinfo.fbmem, 0, pinfo.fblen);
408 
409 #ifdef CONFIG_FB_OVERLAY
410     /* Initialize first overlay but do not select */
411     DEBUGASSERT(fb->vtable->getoverlayinfo != NULL);
412     ret = fb->vtable->getoverlayinfo(fb->vtable, 0, &oinfo);
413     if (ret < 0) {
414         gerr("ERROR: getoverlayinfo() failed: %d\n", ret);
415         goto errout_with_fb;
416     }
417 
418     /* Clear the overlay memory. Necessary when plane 0 and overlay 0
419      * different.
420      */
421 
422     memset(oinfo.fbmem, 0, oinfo.fblen);
423 #endif
424 
425     /* Register the framebuffer device */
426     if (nplanes < 2) {
427         (void)sprintf_s(devname, 16, "/dev/fb%d", display);
428     } else {
429         (void)sprintf_s(devname, 16, "/dev/fb%d.%d", display, plane);
430     }
431 
432     ret = register_driver(devname, (void *)fb);
433     if (ret < 0) {
434         gerr("ERROR: register_driver() failed: %d\n", ret);
435         goto errout_with_fb;
436     }
437 
438     g_fb_dev[display] = fb;
439 
440     return OK;
441 
442 errout_with_fb:
443     free(fb);
444     return ret;
445 }
446 
fb_unregister(int display)447 int fb_unregister(int display)
448 {
449     struct fb_chardev_s *fb = NULL;
450     char devname[16];
451 
452     if (display < 0 || display >= FB_DEV_MAXNUM) return -EINVAL;
453 
454     (void)sprintf_s(devname, 16, "/dev/fb%d", display);
455     unregister_driver(devname);
456 
457     up_fbuninitialize(display);
458 
459     fb = g_fb_dev[display];
460     free(fb);
461     g_fb_dev[display] = NULL;
462 
463     return 0;
464 }