GDISP framebuffer driver + an implementation for the linux kernel framebuffer device

This commit is contained in:
inmarket 2014-05-22 17:21:19 +10:00
parent 52cfaf00cc
commit 285bd0f4d6
12 changed files with 674 additions and 4 deletions

View File

@ -0,0 +1,5 @@
GFXINC += $(GFXLIB)/boards/base/Linux-Framebuffer
GFXSRC +=
GFXDEFS += -DGFX_USE_OS_LINUX=TRUE
include $(GFXLIB)/drivers/gdisp/framebuffer/driver.mk

View File

@ -0,0 +1,217 @@
/*
* This file is subject to the terms of the GFX License. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://ugfx.org/license.html
*/
// Set this to your frame buffer pixel format. Note Linux frame buffer only supports RGB modes (no BGR modes).
#ifndef GDISP_LLD_PIXELFORMAT
#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565
#endif
#ifdef GDISP_DRIVER_VMT
#define FBDEV_PATH1 "/dev/fb0"
#define FBDEV_PATH2 "/dev/fb/0" // Optional - comment this out to only try the one device
#define USE_SET_MODE // Optional - comment this out to not to try to set the color mode we want
//#define VTDEV_PATH "/dev/tty0" // Optional - if defined use this tty to switch from text to graphics mode
#define _GNU_SOURCE 1
#include <fcntl.h>
#include <limits.h>
#include <linux/fb.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#if VTDEV_PATH
static void board_revert2textmode(void) {
int tty;
// Go back to text mode
if ((tty = open(VTDEV_PATH, O_RDWR)) >= 0) {
ioctl(tty, KDSETMODE, KD_TEXT);
close(tty);
}
}
static void board_switch2graphicsmode(void) {
int tty;
// Open the tty
if ((tty = open (VTDEV_PATH, O_RDWR)) < 0) {
fprintf(stderr, "GDISP Framebuffer: Cannot open tty %s\n", VTDEV_PATH);
exit(-1);
}
if (ioctl (tty, KDSETMODE, KD_GRAPHICS) == -1) {
fprintf(stderr, "GDISP Framebuffer: Cannot set to graphics mode\n");
exit(-1);
}
close(tty);
// Make sure we clean up properly
atexit(board_revert2textmode)
}
#endif
static void board_init(GDisplay *g, fbInfo *fbi) {
int fb;
char * env;
size_t fblen;
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
// Open the frame buffer device
if((env = getenv("FRAMEBUFFER")) != 0)
fb = open(env, O_RDWR);
else {
fb = open(FBDEV_PATH1, O_RDWR);
#ifdef FBDEV_PATH2
if (fb < 0) fb = open(FBDEV_PATH2, O_RDWR);
#endif
}
if(fb < 0) {
fprintf(stderr, "GDISP Framebuffer: Error opening the framebuffer device\n");
exit(-1);
}
// Get screen info
if (ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) == -1 || ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) == -1) {
fprintf(stderr, "GDISP Framebuffer: Error getting screen info\n");
exit(-1);
}
#ifdef USE_SET_MODE
info.reserved[0] = 0;
fb_var.reserved[1] = 0;
fb_var.reserved[2] = 0;
fb_var.xoffset = 0;
fb_var.yoffset = 0;
fb_var.bits_per_pixel = LLDCOLOR_BITS;
fb_var.activate = FB_ACTIVATE_NOW;
if (ioctl(fb, FBIOPUT_VSCREENINFO, &fb_var) == -1 || ioctl (fb, FBIOGET_VSCREENINFO, &fb_var) == -1) {
fprintf(stderr, "GDISP Framebuffer: Failed to set video mode\n");
exit(-1);
}
#endif
// Check things are as they should be
if (fb_fix.type != FB_TYPE_PACKED_PIXELS) {
fprintf(stderr, "GDISP Framebuffer: The display is not in a single plane graphics mode\n");
exit(-1);
}
if (fb_fix.visual != FB_VISUAL_TRUECOLOR) {
fprintf(stderr, "GDISP Framebuffer: The display is not in TRUECOLOR mode\n");
exit(-1);
}
if (fb_var.bits_per_pixel != LLDCOLOR_BITS) {
fprintf(stderr, "GDISP Framebuffer: The display is not %u bits per pixel\n", LLDCOLOR_BITS);
exit(-1);
}
if (fb_var.red.length != LLDCOLOR_BITS_R || fb_var.green.length != LLDCOLOR_BITS_G || fb_var.blue.length != LLDCOLOR_BITS_B) {
fprintf(stderr, "GDISP Framebuffer: The display pixel format is not %d%d%d\n", LLDCOLOR_BITS_R, LLDCOLOR_BITS_G, LLDCOLOR_BITS_B);
exit(-1);
}
if (fb_var.red.offset != LLDCOLOR_SHIFT_R || fb_var.green.offset != LLDCOLOR_SHIFT_G || fb_var.blue.offset != LLDCOLOR_SHIFT_B) {
#if LLDCOLOR_SHIFT_B == 0
fprintf(stderr, "GDISP Framebuffer: THe display pixel format is not RGB\n");
#else
fprintf(stderr, "GDISP Framebuffer: The display pixel format is not BGR\n");
#endif
exit(-1);
}
// Ensure we are at the origin of the virtual display area
if (fb_var.xoffset || fb_var.yoffset) {
fb_var.xoffset = 0;
fb_var.yoffset = 0;
ioctl(fb, FBIOPAN_DISPLAY, &fb_var);
}
// Switch to graphics mode (if required)
#ifdef VTDEV_PATH
board_switch2graphicsmode();
#endif
// Calculate the frame buffer length
fblen = fb_var.yres * fb_fix.line_length;
// Different systems need mapping in slightly different ways - Yuck!
#ifdef ARCH_LINUX_SPARC
#define CG3_MMAP_OFFSET 0x4000000
#define CG6_RAM 0x70016000
#define TCX_RAM8BIT 0x00000000
#define TCX_RAM24BIT 0x01000000
switch (fb_fix.accel) {
case FB_ACCEL_SUN_CGTHREE:
fbi->pixels = mmap(0, fblen, PROT_READ|PROT_WRITE, MAP_SHARED, fb, CG3_MMAP_OFFSET);
break;
case FB_ACCEL_SUN_CGSIX:
fbi->pixels = mmap(0, fblen, PROT_READ|PROT_WRITE, MAP_SHARED, fb, CG6_RAM);
break;
case FB_ACCEL_SUN_TCX:
fbi->pixels = mmap(0, fblen, PROT_READ|PROT_WRITE, MAP_SHARED, fb, TCX_RAM24BIT);
break;
default:
fprintf(stderr, "GDISP Framebuffer: Don't know how to mmap with accel %d\n", fb_fix.accel);
exit(-1);
}
#elif defined(BLACKFIN)
fbi->pixels = mmap(0, fblen, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FILE, fb, 0);
#elif defined(__uClinux__)
fbi->pixels = mmap(0, fblen, PROT_READ|PROT_WRITE, 0, fb, 0);
#else
fbi->pixels = mmap(0, fblen, PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);
#endif
if(!fbi->pixels || fbi->pixels == (void *)-1) {
fprintf(stderr, "GDISP Framebuffer: mmap of display buffer failed\n");
exit(-1);
}
// If this program gets children they should not inherit this file descriptor
fcntl(fb, F_SETFD, FD_CLOEXEC);
// We are finished with the file descriptor
close(fb);
// Set the rest of the details of the frame buffer
g->g.Width = fb_var.xres;
g->g.Height = fb_var.yres;
g->g.Backlight = 100;
g->g.Contrast = 50;
fbi->linelen = fb_fix.line_length;
}
#if GDISP_HARDWARE_FLUSH
static void board_flush(GDisplay *g) {
(void) g;
}
#endif
#if GDISP_NEED_CONTROL
static void board_backlight(GDisplay *g, uint8_t percent) {
(void) g;
(void) percent;
}
static void board_contrast(GDisplay *g, uint8_t percent) {
(void) g;
(void) percent;
}
static void board_power(GDisplay *g, powermode_t pwr) {
(void) g;
(void) pwr;
}
#endif
#endif /* GDISP_LLD_BOARD_IMPLEMENTATION */

View File

@ -0,0 +1,155 @@
#
# !!!! Do NOT edit this makefile with an editor which replace tabs by spaces !!!!
#
##############################################################################################
#
# On command line:
#
# make all = Create project
#
# make clean = Clean project files.
#
# To rebuild project do "make clean" and "make all".
#
##############################################################################################
# Start of default section
#
TRGT =
CC = $(TRGT)gcc
AS = $(TRGT)gcc -x assembler-with-cpp
# List all default C defines here, like -D_DEBUG=1
DDEFS =
# List all default ASM defines here, like -D_DEBUG=1
DADEFS =
# List all default directories to look for include files here
DINCDIR =
# List the default directory to look for the libraries here
DLIBDIR =
# List all default libraries here
DLIBS = -lX11 -pthread -lrt
#
# End of default section
##############################################################################################
##############################################################################################
# Start of user section
#
# Define project name here
PROJECT = ugfx
# Imported source files and paths for uGFX
GFXLIB = ../ugfx
include ${GFXLIB}/gfx.mk
include ${GFXLIB}/boards/base/Linux-Framebuffer/board.mk
# Where is our source code - alter these for your project.
# Either just include the demo makefile or add your own definitions
include $(GFXLIB)/demos/modules/gdisp/basics/demo.mk
#MYFILES = my-project-directory
#MYCSRC = $(MYFILES)/main.c
#MYDEFS =
# List all user C define here, like -D_DEBUG=1
UDEFS = $(MYDEFS) $(GFXDEFS)
# Define ASM defines here
UADEFS =
# List C source files here
SRC = $(GFXSRC) \
$(MYCSRC)
# List ASM source files here
ASRC =
# List all user directories here
UINCDIR = $(MYFILES) $(GFXINC)
# List the user directory to look for the libraries here
ULIBDIR =
# List all user libraries here
ULIBS =
# Define optimisation level here
OPT = -ggdb -O0 -fomit-frame-pointer
#
# End of user defines
##############################################################################################
INCDIR = $(patsubst %,-I%,$(DINCDIR) $(UINCDIR))
LIBDIR = $(patsubst %,-L%,$(DLIBDIR) $(ULIBDIR))
DEFS = $(DDEFS) $(UDEFS)
ADEFS = $(DADEFS) $(UADEFS)
OBJS = $(ASRC:.s=.o) $(SRC:.c=.o)
LIBS = $(DLIBS) $(ULIBS)
ASFLAGS = -Wa,-amhls=$(<:.s=.lst) $(ADEFS)
CPFLAGS = $(OPT) -Wall -Wextra -Wstrict-prototypes -fverbose-asm $(DEFS)
ifeq ($(HOST_OSX),yes)
ifeq ($(OSX_SDK),)
OSX_SDK = /Developer/SDKs/MacOSX10.7.sdk
endif
ifeq ($(OSX_ARCH),)
OSX_ARCH = -mmacosx-version-min=10.3 -arch i386
endif
CPFLAGS += -isysroot $(OSX_SDK) $(OSX_ARCH)
LDFLAGS = -Wl -Map=$(PROJECT).map,-syslibroot,$(OSX_SDK),$(LIBDIR)
LIBS += $(OSX_ARCH)
else
# Linux, or other
CPFLAGS += -m32 -Wa,-alms=$(<:.c=.lst)
LDFLAGS = -m32 -Wl,-Map=$(PROJECT).map,--cref,--no-warn-mismatch $(LIBDIR)
endif
# Generate dependency information
CPFLAGS += -MD -MP -MF .dep/$(@F).d
#
# makefile rules
#
all: $(OBJS) $(PROJECT)
%.o : %.c
$(CC) -c $(CPFLAGS) -I . $(INCDIR) $< -o $@
%.o : %.s
$(AS) -c $(ASFLAGS) $< -o $@
$(PROJECT): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $@
gcov:
-mkdir gcov
$(COV) -u $(subst /,\,$(SRC))
-mv *.gcov ./gcov
clean:
-rm -f $(OBJS)
-rm -f $(PROJECT)
-rm -f $(PROJECT).map
-rm -f $(SRC:.c=.c.bak)
-rm -f $(SRC:.c=.lst)
-rm -f $(ASRC:.s=.s.bak)
-rm -f $(ASRC:.s=.lst)
-rm -fR .dep
#
# Include the dependency files, should be the last of the makefile
#
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# *** EOF ***

View File

@ -0,0 +1,5 @@
Copy these files into your own project directory and alter them to suite.
Notes:
1/ Look at the MYFILES definition and the MYCSRC definition.

View File

@ -0,0 +1,6 @@
This directory contains the interface for Linux using a framebuffer display.
On this board uGFX currently supports:
- GDISP via the framebuffer driver
There is an example Makefile and project in the examples directory.

View File

@ -1,9 +1,7 @@
This directory contains the interface for Linux
running either native Linux.
This directory contains the interface for Linux using X.
On this board uGFX currently supports:
- GDISP via the X driver
- GINPUT-touch via the X driver
There is an example Makefile and project in the examples directory.

View File

@ -5,7 +5,8 @@
*** Changes After 2.1 ***
FEATURE: Added nested containers demo
FEATURE: Revised GWIN redraw strategy
FEATURE: Added generic framebuffer driver
FEATURE: Added Linux-Framebuffer board definition
*** Release 2.1 ***
FIX: Significant improvements to the way the MCU touch driver works.

View File

@ -0,0 +1,57 @@
/*
* This file is subject to the terms of the GFX License. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://ugfx.org/license.html
*/
// Set this to your frame buffer pixel format.
#ifndef GDISP_LLD_PIXELFORMAT
#define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_BGR888
#endif
// Uncomment this if your frame buffer device requires flushing
//#define GDISP_HARDWARE_FLUSH TRUE
#ifdef GDISP_DRIVER_VMT
static void board_init(GDisplay *g, fbInfo *fbi) {
// TODO: Initialize your frame buffer device here
// TODO: Set the details of the frame buffer
g->g.Width = 640;
g->g.Height = 480;
g->g.Backlight = 100;
g->g.Contrast = 50;
fbi->linelen = g->g.Width * sizeof(LLDCOLOR_TYPE); // bytes per row
fbi->pixels = 0; // pointer to the memory frame buffer
}
#if GDISP_HARDWARE_FLUSH
static void board_flush(GDisplay *g) {
// TODO: Can be an empty function if your hardware doesn't support this
(void) g;
}
#endif
#if GDISP_NEED_CONTROL
static void board_backlight(GDisplay *g, uint8_t percent) {
// TODO: Can be an empty function if your hardware doesn't support this
(void) g;
(void) percent;
}
static void board_contrast(GDisplay *g, uint8_t percent) {
// TODO: Can be an empty function if your hardware doesn't support this
(void) g;
(void) percent;
}
static void board_power(GDisplay *g, powermode_t pwr) {
// TODO: Can be an empty function if your hardware doesn't support this
(void) g;
(void) pwr;
}
#endif
#endif /* GDISP_LLD_BOARD_IMPLEMENTATION */

View File

@ -0,0 +1,2 @@
GFXINC += $(GFXLIB)/drivers/gdisp/framebuffer
GFXSRC += $(GFXLIB)/drivers/gdisp/framebuffer/gdisp_lld_framebuffer.c

View File

@ -0,0 +1,38 @@
/*
* This file is subject to the terms of the GFX License. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://ugfx.org/license.html
*/
#ifndef _GDISP_LLD_CONFIG_H
#define _GDISP_LLD_CONFIG_H
#if GFX_USE_GDISP
/*===========================================================================*/
/* Driver hardware support. */
/*===========================================================================*/
#define GDISP_HARDWARE_DRAWPIXEL TRUE
#define GDISP_HARDWARE_PIXELREAD TRUE
#define GDISP_HARDWARE_CONTROL TRUE
// Any other support comes from the board file
#include "board_framebuffer.h"
#ifndef GDISP_LLD_PIXELFORMAT
#error "GDISP FrameBuffer: You must specify a GDISP_LLD_PIXELFORMAT in your board_framebuffer.h or your makefile"
#endif
// This driver currently only supports unpacked formats with more than 8 bits per pixel
// that is, we only support GRAY_SCALE with 8 bits per pixel or any unpacked TRUE_COLOR format.
// Note: At the time this file is included we have not calculated all our color
// definitions so we need to do this by hand.
#if (GDISP_LLD_PIXELFORMAT & 0x4000) && (GDISP_LLD_PIXELFORMAT & 0xFF) != 8
#error "GDISP FrameBuffer: This driver does not support the specified GDISP_LLD_PIXELFORMAT"
#endif
#endif /* GFX_USE_GDISP */
#endif /* _GDISP_LLD_CONFIG_H */

View File

@ -0,0 +1,175 @@
/*
* This file is subject to the terms of the GFX License. If a copy of
* the license was not distributed with this file, you can obtain one at:
*
* http://ugfx.org/license.html
*/
#include "gfx.h"
#if GFX_USE_GDISP
typedef struct fbInfo {
void * pixels; // The pixel buffer
coord_t linelen; // The number of bytes per display line
} fbInfo;
#define GDISP_DRIVER_VMT GDISPVMT_framebuffer
#include "drivers/gdisp/framebuffer/gdisp_lld_config.h"
#include "src/gdisp/driver.h"
#include "board_framebuffer.h"
typedef struct fbPriv {
fbInfo fbi; // Display information
} fbPriv;
/*===========================================================================*/
/* Driver local routines . */
/*===========================================================================*/
#define PIXIL_POS(g, x, y) ((y) * ((fbPriv *)(g)->priv)->fbi.linelen + (x) * sizeof(LLDCOLOR_TYPE))
#define PIXEL_ADDR(g, pos) ((LLDCOLOR_TYPE *)(((char *)((fbPriv *)(g)->priv)->fbi.pixels)+pos))
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
// Initialize the private structure
if (!(g->priv = gfxAlloc(sizeof(fbPriv))))
gfxHalt("GDISP Framebuffer: Failed to allocate private memory");
((fbPriv *)g->priv)->fbi.pixels = 0;
((fbPriv *)g->priv)->fbi.linelen = 0;
// Initialize the GDISP structure
g->g.Orientation = GDISP_ROTATE_0;
g->g.Powermode = powerOn;
g->board = 0; // preinitialize
board_init(g, &((fbPriv *)g->priv)->fbi);
return TRUE;
}
#if GDISP_HARDWARE_FLUSH
LLDSPEC void gdisp_lld_flush(GDisplay *g) {
board_flush(g);
}
#endif
LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
unsigned pos;
#if GDISP_NEED_CONTROL
switch(g->g.Orientation) {
case GDISP_ROTATE_0:
default:
pos = PIXIL_POS(g, g->p.x, g->p.y);
break;
case GDISP_ROTATE_90:
pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1);
break;
case GDISP_ROTATE_180:
pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1);
break;
case GDISP_ROTATE_270:
pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x);
break;
}
#else
pos = PIXIL_POS(g, g->p.x, g->p.y);
#endif
PIXEL_ADDR(g, pos)[0] = gdispColor2Native(g->p.color);
}
LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
unsigned pos;
LLDCOLOR_TYPE color;
#if GDISP_NEED_CONTROL
switch(g->g.Orientation) {
case GDISP_ROTATE_0:
default:
pos = PIXIL_POS(g, g->p.x, g->p.y);
break;
case GDISP_ROTATE_90:
pos = PIXIL_POS(g, g->p.y, g->g.Width-g->p.x-1);
break;
case GDISP_ROTATE_180:
pos = PIXIL_POS(g, g->g.Width-g->p.x-1, g->g.Height-g->p.y-1);
break;
case GDISP_ROTATE_270:
pos = PIXIL_POS(g, g->g.Height-g->p.y-1, g->p.x);
break;
}
#else
pos = PIXIL_POS(g, g->p.x, g->p.y);
#endif
color = PIXEL_ADDR(g, pos)[0];
return gdispNative2Color(color);
}
#if GDISP_NEED_CONTROL
LLDSPEC void gdisp_lld_control(GDisplay *g) {
switch(g->p.x) {
case GDISP_CONTROL_POWER:
if (g->g.Powermode == (powermode_t)g->p.ptr)
return;
switch((powermode_t)g->p.ptr) {
case powerOff: case powerOn: case powerSleep: case powerDeepSleep:
board_power(g, (powermode_t)g->p.ptr);
break;
default:
return;
}
g->g.Powermode = (powermode_t)g->p.ptr;
return;
case GDISP_CONTROL_ORIENTATION:
if (g->g.Orientation == (orientation_t)g->p.ptr)
return;
switch((orientation_t)g->p.ptr) {
case GDISP_ROTATE_0:
case GDISP_ROTATE_180:
if (g->g.Orientation == GDISP_ROTATE_90 || g->g.Orientation == GDISP_ROTATE_270) {
coord_t tmp;
tmp = g->g.Width;
g->g.Width = g->g.Height;
g->g.Height = tmp;
}
break;
case GDISP_ROTATE_90:
case GDISP_ROTATE_270:
if (g->g.Orientation == GDISP_ROTATE_0 || g->g.Orientation == GDISP_ROTATE_180) {
coord_t tmp;
tmp = g->g.Width;
g->g.Width = g->g.Height;
g->g.Height = tmp;
}
break;
default:
return;
}
g->g.Orientation = (orientation_t)g->p.ptr;
return;
case GDISP_CONTROL_BACKLIGHT:
if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100;
board_backlight(g, (unsigned)g->p.ptr);
g->g.Backlight = (unsigned)g->p.ptr;
return;
case GDISP_CONTROL_CONTRAST:
if ((unsigned)g->p.ptr > 100) g->p.ptr = (void *)100;
board_contrast(g, (unsigned)g->p.ptr);
g->g.Contrast = (unsigned)g->p.ptr;
return;
}
}
#endif
#endif /* GFX_USE_GDISP */

View File

@ -0,0 +1,11 @@
To use this driver:
1. Add in your gfxconf.h:
a) #define GFX_USE_GDISP TRUE
2. To your makefile add the following lines:
include $(GFXLIB)/gfx.mk
include $(GFXLIB)/drivers/gdisp/framebuffer/driver.mk
3. Add a board_framebuffer.h to you project directory (or board directory)
base on one of the templates.