fb: introduce framebuffer support to Minix

This patch introduces a framebuffer to Minix. It's written for the ARM
port of Minix, but has an architectural split that separates the
hardware dependent part from the non-hardware dependent part. Futhermore,
this driver was developed using a screen that has a native resolution of
1024x600 pixels and having lack of support for obtaining EDID from the
screen. Consequently, it uses a hardcoded resolution of 1024x600.

The driver uses an interface based on the Linux ioctl API, but supports
only a very limited subset.
This commit is contained in:
Thomas Veerman 2013-02-01 13:13:19 +01:00
parent 2aa82a9c7b
commit ba49a155b5
23 changed files with 3936 additions and 9 deletions

View file

@ -23,13 +23,14 @@ case $#:$1 in
ttypa ttypb ttypc ttypd ttype ttypf \
ttyq0 ttyq1 ttyq2 ttyq3 ttyq4 ttyq5 ttyq6 ttyq7 ttyq8 ttyq9 \
ttyqa ttyqb ttyqc ttyqd ttyqe ttyqf \
eth klog random uds filter fbd hello
eth klog random uds filter fbd hello fb0
;;
0:|1:-\?)
cat >&2 <<EOF
Usage: $0 [-n] key ...
Where key is one of the following:
ram mem kmem null boot zero # One of these makes all these memory devices
fb0 # Make /dev/fb0
fd0 fd1 ... # Floppy devices for drive 0, 1, ...
fd0p0 fd1p0 ... # Make floppy partitions fd0p[0-3], fd1p[0-3], ...
c0d0 c0d1 ... # Make disks c0d0, c0d1, ...
@ -254,7 +255,7 @@ do
;;
uds)
# unix domain sockets device
$e mknod uds c 18 0; $e chmod 644 random
$e mknod uds c 18 0;
$e chgrp operator uds
$e chmod 666 uds
;;
@ -278,6 +279,11 @@ do
$e mknod hello c 17 0
$e chmod 644 hello
;;
fb0)
# framebuffer driver
$e mknod fb0 c 19 0
$e chmod 644 fb0
;;
*)
echo "$0: don't know about $dev" >&2
ex=1

View file

@ -38,5 +38,4 @@ SUBDIR+= atnormalize dosread fdisk loadfont \
autopart part partition playwave \
recwave repartition screendump
.endif
.include <bsd.subdir.mk>

View file

@ -95,5 +95,6 @@
./usr/lib/libpadconf.a minix-sys
./usr/lib/libpadconf_pic.a minix-sys
./usr/mdec minix-sys
./usr/sbin/fb minix-sys
./usr/sbin/gpio minix-sys
./usr/sbin/random minix-sys

View file

@ -576,6 +576,7 @@
./usr/include/minix/drvlib.h minix-sys
./usr/include/minix/ds.h minix-sys
./usr/include/minix/endpoint.h minix-sys
./usr/include/minix/fb.h minix-sys
./usr/include/minix/fslib.h minix-sys
./usr/include/minix/gcov.h minix-sys
./usr/include/minix/gpio.h minix-sys
@ -792,6 +793,7 @@
./usr/include/sys/ioc_block.h minix-sys
./usr/include/sys/ioccom.h minix-sys
./usr/include/sys/ioc_disk.h minix-sys
./usr/include/sys/ioc_fb.h minix-sys
./usr/include/sys/ioc_fbd.h minix-sys
./usr/include/sys/ioc_file.h minix-sys
./usr/include/sys/ioc_memory.h minix-sys

View file

@ -23,7 +23,7 @@ SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \
.endif
.if ${MACHINE_ARCH} == "earm"
SUBDIR= gpio mmc log tty random
SUBDIR= fb gpio mmc log tty random
.endif
.endif # ${MKIMAGEONLY} != "yes"

15
drivers/fb/Makefile Normal file
View file

@ -0,0 +1,15 @@
# Makefile for the framebuffer driver.
PROG= fb
.include "arch/${MACHINE_ARCH}/Makefile.inc"
SRCS+= fb.c
DPADD+= ${LIBCHARDRIVER} ${LIBSYS}
LDADD+= -lchardriver -lsys
MAN=
BINDIR?= /usr/sbin
.include <minix.service.mk>

View file

@ -0,0 +1,7 @@
# Makefile for arch-dependent framebuffer code
.include <bsd.own.mk>
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
.PATH: ${HERE}
SRCS += fb_arch.c

View file

@ -0,0 +1,65 @@
#ifndef __DSS_H__
#define __DSS_H__
/* DSS Base Registers */
#define OMAP3_DSS_BASE 0x48050000
#define OMAP3_DISPC_BASE 0x48050400
#define OMAP3_VENC_BASE 0x48050C00
#define OMAP3_DSS_SYSCONFIG(b) (b + 0x10)
#define OMAP3_DSS_SYSSTATUS(b) (b + 0x14)
#define OMAP3_DISPC_IRQSTATUS(b) (b + 0x18)
#define OMAP3_DISPC_CONTROL(b) (b + 0x40)
#define OMAP3_DISPC_CONFIG(b) (b + 0x44)
#define OMAP3_DISPC_DEFAULT_COLOR0(b) (b + 0x4c)
#define OMAP3_DISPC_DEFAULT_COLOR1(b) (b + 0x50)
#define OMAP3_DISPC_TIMINGH(b) (b + 0x64)
#define OMAP3_DISPC_TIMINGV(b) (b + 0x68)
#define OMAP3_DISPC_POL_FREQ(b) (b + 0x6c)
#define OMAP3_DISPC_DIVISOR(b) (b + 0x70)
#define OMAP3_DISPC_SIZE_DIG(b) (b + 0x78)
#define OMAP3_DISPC_SIZE_LCD(b) (b + 0x7c)
#define OMAP3_DISPC_GFX_BA0(b) (b + 0x80)
#define OMAP3_DISPC_GFX_BA1(b) (b + 0x84)
#define OMAP3_DISPC_GFX_SIZE(b) (b + 0x8c)
#define OMAP3_DISPC_GFX_ATTRIBUTES(b) (b + 0xa0)
#define OMAP3_DISPC_GFX_ROW_INC(b) (b + 0xac)
#define OMAP3_DISPC_GFX_PIXEL_INC(b) (b + 0xb0)
#define LOADMODE_SHIFT 1
#define TFTSTN_SHIFT 3
#define DATALINES_SHIFT 8
#define GFXFORMAT_SHIFT 1
#define GFXBURSTSIZE_SHIFT 6
#define DSS_SOFTRESET (1 << 1)
#define DSS_RESETDONE (1 << 0)
#define DISPC_LCDENABLE (1 << 0)
#define DISPC_DIGITALENABLE (1 << 1)
#define DISPC_GOLCD (1 << 5)
#define DISPC_GODIGITAL (1 << 6)
#define DISPC_GPIN0 (1 << 13)
#define DISPC_GPIN1 (1 << 14)
#define DISPC_GPOUT0 (1 << 15)
#define DISPC_GPOUT1 (1 << 16)
#define DISPC_ENABLESIGNAL (1 << 28)
#define DISPC_FRAMEDONE (1 << 0)
#define DISPC_GFXENABLE (1 << 0)
#define DISPC_GFXFORMAT_BMP1 0x0
#define DISPC_GFXFORMAT_BMP2 0x1
#define DISPC_GFXFORMAT_BMP4 0x2
#define DISPC_GFXFORMAT_BMP8 0x3
#define DISPC_GFXFORMAT_RGB12 0x4
#define DISPC_GFXFORMAT_ARGB16 0x5
#define DISPC_GFXFORMAT_RGB16 0x6
#define DISPC_GFXFORMAT_RGB24 0x8
#define DISPC_GFXFORMAT_RGB24P 0x9
#define DISPC_GFXFORMAT_ARGB32 0xC
#define DISPC_GFXFORMAT_RGBA32 0xD
#define DISPC_GFXFORMAT_RGBx 0xE
#define DISPC_GFXBURSTSIZE_4 0x0
#define DISPC_GFXBURSTSIZE_8 0x1
#define DISPC_GFXBURSTSIZE_16 0x2
#endif /* __DSS_H__ */

View file

@ -0,0 +1,271 @@
/* Architecture dependent part for the framebuffer on the OMAP3. Since we don't
* have support for EDID (which requires support for i2c, also something we
* don't have, yet), but we do have a screen with 1024*600 resolution for our
* testing purposes, we hardcode that resolution here. There's obvious room for
* improvement. */
#include <minix/chardriver.h>
#include <minix/drivers.h>
#include <minix/fb.h>
#include <minix/type.h>
#include <minix/vm.h>
#include <assert.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include "dss.h"
#define SCREEN_WIDTH 1024
#define SCREEN_HEIGHT 600
#define PAGES_NR 2
static vir_bytes dss_phys_base; /* Address of dss phys memory map */
static vir_bytes dispc_phys_base; /* Address of dispc phys memory map */
static vir_bytes fb_vir;
static phys_bytes fb_phys;
static size_t fb_size;
static int initialized = 0;
struct panel_config {
u32_t timing_h;
u32_t timing_v;
u32_t pol_freq;
u32_t divisor;
u32_t lcd_size;
u32_t panel_type;
u32_t data_lines;
u32_t load_mode;
u32_t panel_color;
};
static const struct panel_config default_cfg = {
/* See OMAP TRM section 15.7 for the register values/encoding */
.timing_h = 0x1a4024c9, /* Horizontal timing */
.timing_v = 0x02c00509, /* Vertical timing */
.pol_freq = 0x00007028, /* Pol Freq */
.divisor = 0x00010001, /* 96MHz Pixel Clock */
.lcd_size = ((SCREEN_HEIGHT - 1) << 16 | (SCREEN_WIDTH - 1)),
.panel_type = 0x01, /* TFT */
.data_lines = 0x03, /* 24 Bit RGB */
.load_mode = 0x02, /* Frame Mode */
.panel_color = 0xFFFFFF /* WHITE */
};
static const struct fb_fix_screeninfo fbfs = {
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.line_length = SCREEN_WIDTH * 4,
.mmio_start = 0, /* Not implemented for char. special, so */
.mmio_len = 0 /* these are set to 0 */
};
static struct fb_var_screeninfo fbvs = {
.xres = SCREEN_WIDTH,
.yres = SCREEN_HEIGHT,
.xres_virtual = SCREEN_WIDTH,
.yres_virtual = SCREEN_HEIGHT*2,
.xoffset = 0,
.yoffset = 0,
.bits_per_pixel = 32,
.red = {
.offset = 16,
.length = 8,
.msb_right = 0
},
.green = {
.offset = 8,
.length = 8,
.msb_right = 0
},
.blue = {
.offset = 0,
.length = 8,
.msb_right = 0
},
.transp = {
.offset = 24,
.length = 8,
.msb_right = 0
}
};
static inline u32_t
readw(vir_bytes addr)
{
return *((volatile u32_t *) addr);
}
static inline void
writew(vir_bytes addr, u32_t val)
{
*((volatile u32_t *) addr) = val;
}
static void
arch_configure_display(int minor)
{
/* Tell hardware where frame buffer is and turn display on */
u32_t off, rdispc;
if (!initialized) return;
if (minor != 0) return;
off = fbvs.yoffset * fbvs.xres_virtual * (fbvs.bits_per_pixel/8);
writew((vir_bytes) OMAP3_DISPC_GFX_BA0(dispc_phys_base),
fb_phys + (phys_bytes) off);
rdispc = readw((vir_bytes) OMAP3_DISPC_CONTROL(dispc_phys_base));
rdispc |= DISPC_LCDENABLE | DISPC_DIGITALENABLE | DISPC_GOLCD |
DISPC_GODIGITAL | DISPC_GPOUT0 | DISPC_GPOUT1;
writew((vir_bytes) OMAP3_DISPC_CONTROL(dispc_phys_base), rdispc);
}
int
arch_get_device(int minor, struct device *dev)
{
if (!initialized) return ENXIO;
if (minor != 0) return ENXIO;
dev->dv_base = fb_vir;
dev->dv_size = fb_size;
return OK;
}
int
arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
{
if (!initialized) return ENXIO;
if (minor != 0) return ENXIO;
*fbvsp = fbvs;
return OK;
}
int
arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp)
{
int r = OK;
assert(fbvsp != NULL);
if (!initialized) return ENXIO;
if (minor != 0) return ENXIO;
/* For now we only allow to play with the yoffset setting */
if (fbvsp->yoffset != fbvs.yoffset) {
if (fbvsp->yoffset < 0 || fbvsp->yoffset > fbvs.yres) {
return EINVAL;
}
fbvs.yoffset = fbvsp->yoffset;
}
/* Now update hardware with new settings */
arch_configure_display(minor);
return OK;
}
int
arch_get_fixscreeninfo(int minor, struct fb_fix_screeninfo *fbfsp)
{
if (!initialized) return ENXIO;
if (minor != 0) return ENXIO;
*fbfsp = fbfs;
return OK;
}
int
arch_pan_display(int minor, struct fb_var_screeninfo *fbvsp)
{
return arch_put_varscreeninfo(minor, fbvsp);
}
int
arch_fb_init(int minor, struct device *dev)
{
u32_t rdispc;
struct minix_mem_range mr;
const struct panel_config *panel_cfg = &default_cfg;
assert(dev != NULL);
if (minor != 0) return ENXIO; /* We support only one minor */
if (initialized) {
dev->dv_base = fb_vir;
dev->dv_size = fb_size;
return OK;
}
initialized = 1;
/* Configure DSS memory access */
mr.mr_base = OMAP3_DSS_BASE;
mr.mr_limit = mr.mr_base + 0x60;
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
panic("Unable to request access to DSS(1) memory");
}
dss_phys_base = (vir_bytes) vm_map_phys(SELF, (void *) OMAP3_DSS_BASE,
0x60);
if (dss_phys_base == (vir_bytes) MAP_FAILED) {
panic("Unable to request access to DSS(2) memory");
}
/* Configure DISPC memory access */
mr.mr_base = OMAP3_DISPC_BASE;
mr.mr_limit = mr.mr_base + 0x430;
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
panic("Unable to request access to DISPC(1) memory");
}
dispc_phys_base = (vir_bytes) vm_map_phys(SELF,
(void *) OMAP3_DISPC_BASE,
0x430);
if (dispc_phys_base == (vir_bytes) MAP_FAILED) {
panic("Unable to request access to DISPC(2) memory");
}
/* Set timings, screen mode, screen size, etc. */
writew(OMAP3_DISPC_TIMINGH(dispc_phys_base), panel_cfg->timing_h);
writew(OMAP3_DISPC_TIMINGV(dispc_phys_base), panel_cfg->timing_v);
writew(OMAP3_DISPC_POL_FREQ(dispc_phys_base), panel_cfg->pol_freq);
writew(OMAP3_DISPC_DIVISOR(dispc_phys_base), panel_cfg->divisor);
writew(OMAP3_DISPC_CONFIG(dispc_phys_base),
panel_cfg->load_mode << LOADMODE_SHIFT);
writew(OMAP3_DISPC_CONTROL(dispc_phys_base),
panel_cfg->panel_type << TFTSTN_SHIFT |
panel_cfg->data_lines << DATALINES_SHIFT);
writew((vir_bytes) OMAP3_DISPC_SIZE_LCD(dispc_phys_base),
panel_cfg->lcd_size);
writew((vir_bytes) OMAP3_DISPC_GFX_SIZE(dispc_phys_base),
panel_cfg->lcd_size);
writew(OMAP3_DISPC_DEFAULT_COLOR0(dispc_phys_base),
panel_cfg->panel_color);
/* Enable gfx engine */
writew(OMAP3_DISPC_GFX_ATTRIBUTES(dispc_phys_base),
(DISPC_GFXBURSTSIZE_16 << GFXBURSTSIZE_SHIFT) |
(DISPC_GFXFORMAT_RGB24 << GFXFORMAT_SHIFT) |
(DISPC_GFXENABLE));
writew(OMAP3_DISPC_GFX_ROW_INC(dispc_phys_base), 1);
writew(OMAP3_DISPC_GFX_PIXEL_INC(dispc_phys_base), 1);
/* Allocate contiguous physical memory for the display buffer */
fb_size = fbvs.yres_virtual * fbvs.xres_virtual *
(fbvs.bits_per_pixel / 8);
fb_vir = (vir_bytes) alloc_contig(fb_size, 0, &fb_phys);
if (fb_vir == (vir_bytes) MAP_FAILED) {
panic("Unable to allocate contiguous memory\n");
}
dev->dv_base = fb_vir;
dev->dv_size = fb_size;
/* Configure buffer settings and turn on LCD/Digital */
arch_configure_display(minor);
return OK;
}

426
drivers/fb/fb.c Normal file
View file

@ -0,0 +1,426 @@
#include <minix/fb.h>
#include <minix/chardriver.h>
#include <minix/drivers.h>
#include <minix/ds.h>
#include <minix/type.h>
#include <minix/vm.h>
#include <sys/ioc_fb.h>
#include <assert.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include "logos.h"
#include "fb.h"
#define FB_DEV_NR 1
/*
* Function prototypes for the fb driver.
*/
static int fb_open(message *m);
static int fb_close(message *m);
static struct device * fb_prepare(dev_t device);
static int fb_transfer(endpoint_t endpt, int opcode, u64_t position,
iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
flags);
static int fb_do_read(endpoint_t ep, iovec_t *iov, int minor, u64_t pos,
size_t *io_bytes);
static int fb_do_write(endpoint_t ep, iovec_t *iov, int minor, u64_t pos,
size_t *io_bytes);
static int fb_ioctl(message *m);
static void paint_bootlogo(int minor);
static void paint_restartlogo(int minor);
static void paint_centered(int minor, char *data, int width, int height);
static int do_get_varscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid);
static int do_put_varscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid);
static int do_get_fixscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid);
static int do_pan_display(int minor, endpoint_t ep, cp_grant_id_t gid);
/* SEF functions and variables. */
static void sef_local_startup(void);
static int sef_cb_init(int type, sef_init_info_t *info);
static int sef_cb_lu_state_save(int);
static int lu_state_restore(void);
/* Entry points to the fb driver. */
static struct chardriver fb_tab =
{
fb_open,
fb_close,
fb_ioctl,
fb_prepare,
fb_transfer,
nop_cleanup,
nop_alarm,
nop_cancel,
nop_select,
NULL
};
/** Represents the /dev/fb device. */
static struct device fb_device[FB_DEV_NR];
static int fb_minor, has_restarted = 0;
static int open_counter[FB_DEV_NR]; /* Open count */
static int
fb_open(message *m)
{
static int initialized = 0;
if (m->DEVICE < 0 || m->DEVICE >= FB_DEV_NR) return ENXIO;
if (arch_fb_init(m->DEVICE, &fb_device[m->DEVICE]) == OK) {
open_counter[m->DEVICE]++;
if (!initialized) {
if (has_restarted) {
paint_restartlogo(m->DEVICE);
has_restarted = 0;
} else {
paint_bootlogo(m->DEVICE);
}
initialized = 1;
}
return OK;
}
return ENXIO ;
}
static int
fb_close(message *m)
{
if (m->DEVICE < 0 || m->DEVICE >= FB_DEV_NR) return ENXIO;
assert(open_counter[m->DEVICE] > 0);
open_counter[m->DEVICE]--;
return OK;
}
static struct device *
fb_prepare(dev_t dev)
{
if (dev < 0 || dev >= FB_DEV_NR) return NULL;
assert(open_counter[dev] > 0);
fb_minor = dev;
return &fb_device[dev];
}
static int
fb_transfer(endpoint_t endpt, int opcode, u64_t position,
iovec_t *iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
unsigned int UNUSED(flags))
{
size_t io_bytes = 0, ret;
if (nr_req != 1) {
/* This should never trigger for char drivers at the moment. */
printf("fb: vectored transfer, using first element only\n");
}
switch (opcode) {
case DEV_GATHER_S:
/* Userland read operation */
ret = fb_do_read(endpt, iov, fb_minor, position, &io_bytes);
iov->iov_size -= io_bytes;
break;
case DEV_SCATTER_S:
/* Userland write operation */
ret = fb_do_write(endpt, iov, fb_minor, position, &io_bytes);
iov->iov_size -= io_bytes;
break;
default:
return EINVAL;
}
return ret;
}
static int
fb_do_read(endpoint_t ep, iovec_t *iov, int minor, u64_t pos, size_t *io_bytes)
{
struct device dev;
arch_get_device(minor, &dev);
if (pos >= dev.dv_size) return EINVAL;
if (dev.dv_size - pos < iov->iov_size) {
*io_bytes = dev.dv_size - pos;
} else {
*io_bytes = iov->iov_size;
}
if (*io_bytes <= 0) {
return OK;
}
return sys_safecopyto(ep, (cp_grant_id_t) iov->iov_addr, 0,
(vir_bytes) (dev.dv_base + ex64lo(pos)),
*io_bytes);
}
static int
fb_ioctl(message *m)
{
/* Process I/O control requests */
endpoint_t ep;
cp_grant_id_t gid;
int minor;
unsigned int request;
int r;
minor = m->DEVICE;
request = m->COUNT;
ep = (endpoint_t) m->USER_ENDPT;
gid = (cp_grant_id_t) m->IO_GRANT;
if (minor != 0) return EINVAL;
switch(request) {
case FBIOGET_VSCREENINFO:
r = do_get_varscreeninfo(minor, ep, gid);
return r;
case FBIOPUT_VSCREENINFO:
r = do_put_varscreeninfo(minor, ep, gid);
return r;
case FBIOGET_FSCREENINFO:
r = do_get_fixscreeninfo(minor, ep, gid);
return r;
case FBIOPAN_DISPLAY:
r = do_pan_display(minor, ep, gid);
return r;
}
return EINVAL;
}
static int
do_get_varscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid)
{
int r;
struct fb_var_screeninfo fbvs;
if ((r = arch_get_varscreeninfo(minor, &fbvs)) == OK) {
r = sys_safecopyto(ep, gid, 0, (vir_bytes) &fbvs, sizeof(fbvs));
}
return r;
}
static int
do_put_varscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid)
{
int r;
struct fb_var_screeninfo fbvs_copy;
if ((r = sys_safecopyfrom(ep, gid, 0, (vir_bytes) &fbvs_copy,
sizeof(fbvs_copy))) != OK) {
return r;
}
return arch_put_varscreeninfo(minor, &fbvs_copy);
}
static int
do_pan_display(int minor, endpoint_t ep, cp_grant_id_t gid)
{
int r;
struct fb_var_screeninfo fbvs_copy;
if ((r = sys_safecopyfrom(ep, gid, 0, (vir_bytes) &fbvs_copy,
sizeof(fbvs_copy))) != OK) {
return r;
}
return arch_pan_display(minor, &fbvs_copy);
}
static int
do_get_fixscreeninfo(int minor, endpoint_t ep, cp_grant_id_t gid)
{
int r;
struct fb_fix_screeninfo fbfs;
if ((r = arch_get_fixscreeninfo(minor, &fbfs)) == OK) {
r = sys_safecopyto(ep, gid, 0, (vir_bytes) &fbfs, sizeof(fbfs));
}
return r;
}
static int
fb_do_write(endpoint_t ep, iovec_t *iov, int minor, u64_t pos, size_t *io_bytes)
{
struct device dev;
arch_get_device(minor, &dev);
if (pos >= dev.dv_size) {
return EINVAL;
}
if (dev.dv_size - pos < iov->iov_size) {
*io_bytes = dev.dv_size - pos;
} else {
*io_bytes = iov->iov_size;
}
if (*io_bytes <= 0) {
return OK;
}
return sys_safecopyfrom(ep, (cp_grant_id_t) iov->iov_addr, 0,
(vir_bytes) (dev.dv_base + ex64lo(pos)),
*io_bytes);
}
static int
sef_cb_lu_state_save(int UNUSED(state)) {
/* Save the state. */
ds_publish_u32("open_counter", open_counter[0], DSF_OVERWRITE);
return OK;
}
static int
lu_state_restore() {
/* Restore the state. */
u32_t value;
ds_retrieve_u32("open_counter", &value);
ds_delete_u32("open_counter");
open_counter[0] = (int) value;
return OK;
}
static void
sef_local_startup()
{
/* Register init callbacks. Use the same function for all event types */
sef_setcb_init_fresh(sef_cb_init);
sef_setcb_init_lu(sef_cb_init);
sef_setcb_init_restart(sef_cb_init);
/* Register live update callbacks */
/* - Agree to update immediately when LU is requested in a valid state*/
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
/* - Support live update starting from any standard state */
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
/* - Register a custom routine to save the state. */
sef_setcb_lu_state_save(sef_cb_lu_state_save);
/* Let SEF perform startup. */
sef_startup();
}
static int
sef_cb_init(int type, sef_init_info_t *UNUSED(info))
{
/* Initialize the fb driver. */
int do_announce_driver = TRUE;
open_counter[0] = 0;
switch(type) {
case SEF_INIT_FRESH:
printf("framebuffer fresh: pid %d\n", getpid());
break;
case SEF_INIT_LU:
/* Restore the state. */
lu_state_restore();
do_announce_driver = FALSE;
printf("framebuffer: I'm a new version!\n");
break;
case SEF_INIT_RESTART:
printf("framebuffer restarted: pid %d\n", getpid());
has_restarted = 1;
break;
}
/* Announce we are up when necessary. */
if (do_announce_driver) {
chardriver_announce();
}
/* Initialization completed successfully. */
return OK;
}
int
main(void)
{
sef_local_startup();
chardriver_task(&fb_tab, CHARDRIVER_SYNC);
return OK;
}
static void
paint_bootlogo(int minor)
{
paint_centered(minor, bootlogo_data, bootlogo_width, bootlogo_height);
}
static void
paint_restartlogo(int minor)
{
paint_centered(minor, restartlogo_data, restartlogo_width,
restartlogo_height);
micro_delay(1 * 1000000); /* 1 second */
}
static void
paint_centered(int minor, char *data, int width, int height)
{
u8_t pixel[3];
u32_t i, min_x, min_y, max_x, max_y, x_painted = 0, rows = 0;
int r, bytespp;
struct device dev;
struct fb_var_screeninfo fbvs;
/* Put display in a known state to simplify positioning code below */
if ((r = arch_get_varscreeninfo(minor, &fbvs)) != OK) {
printf("fb: unable to get screen info: %d\n", r);
}
fbvs.yoffset = 0;
if ((r = arch_pan_display(minor, &fbvs)) != OK) {
printf("fb: unable to pan display: %d\n", r);
}
arch_get_device(minor, &dev);
/* Paint on a white canvas */
bytespp = fbvs.bits_per_pixel / 8;
for (i = 0; i < fbvs.xres * fbvs.yres * bytespp; i+= bytespp)
*((u32_t *)((u32_t) dev.dv_base + i)) = 0x00FFFFFF;
/* First seek to start */
min_x = fbvs.xres / 2 - width / 2;
max_x = fbvs.xres / 2 + width / 2;
min_y = fbvs.yres / 2 - height / 2;
max_y = fbvs.yres / 2 + height / 2;
i = min_x * fbvs.xres + min_y;
/* Add the image data */
for (i = ((min_y * fbvs.xres) + min_x) * bytespp; rows < height;) {
GET_PIXEL(data, pixel);
((unsigned char *)((u32_t) dev.dv_base + i))[0] = pixel[2];
((unsigned char *)((u32_t) dev.dv_base + i))[1] = pixel[1];
((unsigned char *)((u32_t) dev.dv_base + i))[2] = pixel[0];
((unsigned char *)((u32_t) dev.dv_base + i))[3] = 0;
x_painted++;/* Keep tab of how many row pixels we've painted */
if (x_painted == width) {
/* We've reached the end of the row, carriage return
* and go to next line.
*/
x_painted = 0;
rows++;
i = (((min_y + rows) * fbvs.xres) + min_x) * 4;
} else {
i += 4;
}
}
}

13
drivers/fb/fb.h Normal file
View file

@ -0,0 +1,13 @@
#ifndef __FB_H__
#define __FB_H__
int arch_fb_init(int minor, struct device *dev);
int arch_get_device(int minor, struct device *dev);
int arch_get_varscreeninfo(int minor, struct fb_var_screeninfo *fbvsp);
int arch_put_varscreeninfo(int minor, struct fb_var_screeninfo *fbvs_copy);
int arch_get_fixscreeninfo(int minor, struct fb_fix_screeninfo *fbfsp);
int arch_pan_display(int minor, struct fb_var_screeninfo *fbvs_copy);
#define FB_MESSAGE "Hello, world! From framebuffer!\n"
#endif /* __FB_H__ */

3054
drivers/fb/logos.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -57,7 +57,7 @@ PROG_DRIVERS+= acpi
.if ${MACHINE_ARCH} == "earm"
EXTRA+= rc.arm mylogin.sh ttys
PROG_DRIVERS+= mmc tty gpio
PROG_DRIVERS+= fb mmc tty gpio
PROG_COMMANDS+= cp dd getty time sleep stty umount
PROG_BIN+= cat ls rm sync
PROTO= proto.arm.small

View file

@ -18,6 +18,7 @@ d--755 0 0
fsck.mfs ---755 0 0 fsck.mfs
$
sbin d--755 0 0
fb ---755 0 0 fb
mmc ---755 0 0 mmc
mfs ---755 0 0 mfs
gpio ---755 0 0 gpio

View file

@ -336,6 +336,7 @@
c1d7p3s2 b--600 0 0 8 254
c1d7p3s3 b--600 0 0 8 255
console c--600 0 4 4 0
fb0 c--644 0 0 19 0
fbd b--600 0 0 14 0
fd0 b--666 0 0 2 0
filter b--644 0 0 11 0

View file

@ -14,5 +14,5 @@ exec </dev/null
#/bin/mount /dev/c0d0p1 /mnt
#gpio
#mount -t gpio none /gpio
#service up /sbin/fb -dev /dev/fb0 -period 2HZ
exit

View file

@ -554,6 +554,18 @@ service mmc
irq 83; # IRQ 83 allowed
};
service fb
{
system
UMAP # 14
DEVIO # 21
PRIVCTL # 4
;
ipc
SYSTEM pm rs ds vm vfs
;
};
service gpio
{
system

View file

@ -10,7 +10,7 @@ INCS+= acpi.h audio_fw.h bitmap.h \
config.h const.h cpufeature.h crtso.h \
debug.h devio.h devman.h dmap.h \
driver.h drivers.h drvlib.h ds.h \
endpoint.h fslib.h gpio.h gcov.h hash.h \
endpoint.h fb.h fslib.h gpio.h gcov.h hash.h \
hgfs.h ioctl.h input.h ipc.h ipcconst.h \
keymap.h limits.h log.h mmio.h mount.h mthread.h minlib.h \
netdriver.h optset.h padconf.h partition.h portio.h \

View file

@ -38,6 +38,7 @@ enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY,
#define RANDOM_MAJOR 16 /* 16 = /dev/random (random driver) */
#define HELLO_MAJOR 17 /* 17 = /dev/hello (hello driver) */
#define UDS_MAJOR 18 /* 18 = /dev/uds (pfs) */
#define FB_MAJOR 19 /* 18 = /dev/fb0 (fb driver) */
/* Minor device numbers for memory driver. */

38
include/minix/fb.h Normal file
View file

@ -0,0 +1,38 @@
#ifndef __MINIX_FB_H_
#define __MINIX_FB_H_
#include <minix/type.h>
struct fb_fix_screeninfo {
char id[16]; /* Identification string */
u16_t xpanstep;
u16_t ypanstep;
u16_t ywrapstep;
u32_t line_length;
phys_bytes mmio_start;
size_t mmio_len;
u16_t reserved[15];
};
struct fb_bitfield {
u32_t offset;
u32_t length;
u32_t msb_right;
};
struct fb_var_screeninfo {
u32_t xres; /* visible resolution */
u32_t yres;
u32_t xres_virtual; /* virtual resolution */
u32_t yres_virtual;
u32_t xoffset; /* offset from virtual to visible */
u32_t yoffset;
u32_t bits_per_pixel;
struct fb_bitfield red; /* bitfield in fb mem if true color */
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
u16_t reserved[10];
};
#endif /* __MINIX_FB_H_ */

View file

@ -3,8 +3,8 @@ INCSDIR= /usr/include/sys
# Minix specific system headers
INCS= elf64.h elf_common.h elf_core.h elf_generic.h \
ioc_block.h ioc_disk.h ioc_fbd.h ioc_file.h ioc_memory.h ioc_net.h \
ioc_sound.h ioc_tape.h ioc_tty.h \
ioc_block.h ioc_disk.h ioc_fb.h ioc_fbd.h ioc_file.h ioc_memory.h \
ioc_net.h ioc_sound.h ioc_tape.h ioc_tty.h \
kbdio.h \
procfs.h statfs.h svrctl.h video.h vm.h

14
include/sys/ioc_fb.h Normal file
View file

@ -0,0 +1,14 @@
/* sys/ioc_fb.h - Framebuffer command codes
*
*/
#ifndef _S_I_FB_H
#define _S_I_FB_H
/* The I/O control requests. */
#define FBIOGET_VSCREENINFO _IOR('V', 1, struct fb_var_screeninfo)
#define FBIOPUT_VSCREENINFO _IOW('V', 2, struct fb_var_screeninfo)
#define FBIOGET_FSCREENINFO _IOR('V', 3, struct fb_fix_screeninfo)
#define FBIOPAN_DISPLAY _IOW('V', 4, struct fb_var_screeninfo)
#endif /* _S_I_FB_H */

View file

@ -20,6 +20,7 @@
#include <sys/ioc_memory.h> /* 'm' */
#include <sys/ioc_tape.h> /* 'M' */
#include <sys/ioc_sound.h> /* 's' */
#include <sys/ioc_fb.h> /* 'F' */
#if defined(_NETBSD_SOURCE)
#define TIOCDRAIN TCDRAIN