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:
parent
2aa82a9c7b
commit
ba49a155b5
23 changed files with 3936 additions and 9 deletions
|
@ -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
|
||||
|
|
|
@ -38,5 +38,4 @@ SUBDIR+= atnormalize dosread fdisk loadfont \
|
|||
autopart part partition playwave \
|
||||
recwave repartition screendump
|
||||
.endif
|
||||
|
||||
.include <bsd.subdir.mk>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
15
drivers/fb/Makefile
Normal 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>
|
7
drivers/fb/arch/earm/Makefile.inc
Normal file
7
drivers/fb/arch/earm/Makefile.inc
Normal 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
|
65
drivers/fb/arch/earm/dss.h
Normal file
65
drivers/fb/arch/earm/dss.h
Normal 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__ */
|
271
drivers/fb/arch/earm/fb_arch.c
Normal file
271
drivers/fb/arch/earm/fb_arch.c
Normal 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
426
drivers/fb/fb.c
Normal 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
13
drivers/fb/fb.h
Normal 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
3054
drivers/fb/logos.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
38
include/minix/fb.h
Normal 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_ */
|
|
@ -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
14
include/sys/ioc_fb.h
Normal 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 */
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue