223 lines
6.6 KiB
C
223 lines
6.6 KiB
C
|
/*
|
||
|
* 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.io/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_RGB888
|
||
|
#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
|
||
|
fb_var.reserved[0] = 0;
|
||
|
fb_var.reserved[1] = 0;
|
||
|
fb_var.reserved[2] = 0;
|
||
|
fb_var.xoffset = 0;
|
||
|
fb_var.yoffset = 0;
|
||
|
#if LLDCOLOR_BITS == 15
|
||
|
fb_var.bits_per_pixel = LLDCOLOR_BITS; // Handle RGB555 & BGR555
|
||
|
#else
|
||
|
fb_var.bits_per_pixel = sizeof(LLDCOLOR_TYPE)*8;
|
||
|
#endif
|
||
|
fb_var.grayscale = 0;
|
||
|
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 != sizeof(LLDCOLOR_TYPE)*8) {
|
||
|
fprintf(stderr, "GDISP Framebuffer: The display is %u not %u bits per pixel\n", fb_var.bits_per_pixel, LLDCOLOR_TYPE_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, gU8 percent) {
|
||
|
(void) g;
|
||
|
(void) percent;
|
||
|
}
|
||
|
|
||
|
static void board_contrast(GDisplay *g, gU8 percent) {
|
||
|
(void) g;
|
||
|
(void) percent;
|
||
|
}
|
||
|
|
||
|
static void board_power(GDisplay *g, gPowermode pwr) {
|
||
|
(void) g;
|
||
|
(void) pwr;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#endif /* GDISP_LLD_BOARD_IMPLEMENTATION */
|