[PATCH] pc386/console: alternative framebuffer implementation for cirrus GD5446 QEMU device
Pavel Pisa
ppisa4lists at pikron.com
Wed Jun 20 17:35:48 UTC 2012
The driver is compatible with PCI GD5446 provided by QEMU.
QEMU option "-vga cirrus".
Driver locates PCI device and configures it for linear framebuffer
when "/dev/fb0" is open. Default mode and bit depths are
controlled by FB_CIRRUS_DEFAULT_MODE, FB_CIRRUS_DEFAULT_BPP
defines. 32, 24 and 16 bits per pixel with FB_VISUAL_TRUECOLOR
are supported. 8 bit mode is not finished - requires palette support.
To use alternative Cirrus framebuffer, replace line
libbsp_a_SOURCES += console/fb_vga.c
in
c/src/lib/libbsp/i386/pc386/Makefile.am b/c/src/lib/libbsp/i386/pc386/Makefile.am
by
libbsp_a_SOURCES += console/fb_cirrus.c
Signed-off-by: Pavel Pisa <pisa at cmp.felk.cvut.cz>
---
c/src/lib/libbsp/i386/pc386/console/fb_cirrus.c | 709 ++++++++++++++++++++
.../lib/libbsp/i386/pc386/console/vga_registers.h | 102 +++
2 files changed, 811 insertions(+)
create mode 100644 c/src/lib/libbsp/i386/pc386/console/fb_cirrus.c
create mode 100644 c/src/lib/libbsp/i386/pc386/console/vga_registers.h
diff --git a/c/src/lib/libbsp/i386/pc386/console/fb_cirrus.c b/c/src/lib/libbsp/i386/pc386/console/fb_cirrus.c
new file mode 100644
index 0000000..760003e
--- /dev/null
+++ b/c/src/lib/libbsp/i386/pc386/console/fb_cirrus.c
@@ -0,0 +1,709 @@
+/*
+ * Copyright (c) 2012 - Pavel Pisa ( pisa at cmp.felk.cvut.cz )
+ *
+ * MODULE DESCRIPTION:
+ * This module implements FB driver for "Cirrus GD5446" found in Qemu
+ * emulator.
+ *
+ * The code is based on fb_vga.c written by
+ * Copyright (c) 2000 Rosimildo da Silva ( rdasilva at connecttel.com )
+ * and it is inspired by X11 and Linux kernel sources
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <rtems/libio.h>
+#include <rtems/pci.h>
+
+#include <rtems/fb.h>
+
+#include "vga_registers.h"
+
+/* these routines are defined in vgainit.c.*/
+extern void ega_hwinit( void );
+extern void ega_hwterm( void );
+
+/* mutex attribure */
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+#define FB_CIRRUS_MAX_CARDS 1
+
+#define CIRRUS_VENDOR_ID 0x1013
+#define CIRRUS_GD5446_DEVICE_ID 0x00b8
+
+/* video modes
+ 640 x 480
+ 800 x 600
+ 1024 x 768
+ 1280 x 1024
+*/
+struct fb_cirrus_modeline {
+ int clock;
+ int hdisplay;
+ int hsync_start;
+ int hsync_end;
+ int htotal;
+ int hskew;
+ int vdisplay;
+ int vsync_start;
+ int vsync_end;
+ int vtotal;
+ int vscan;
+ unsigned int flags;
+};
+
+struct fb_cirrus_state {
+ int found;
+ int pbus;
+ int pdev;
+ int pfun;
+ uint32_t pci_bar[4];
+ struct fb_var_screeninfo fb_var;
+ struct fb_fix_screeninfo fb_fix;
+ void *mmregs;
+ struct fb_cirrus_modeline *active_mode;
+};
+
+/* 1/4bpp 8bpp 15/16bpp 24bpp 32bpp */
+static int fb_cirrus_max_clocks[] = { 135100, 135100, 85500, 85500, 0 };
+
+static struct fb_cirrus_modeline fb_cirrus_std_modelines[] = {
+ { .clock = 31500,
+ .hdisplay = 640, .hsync_start = 664, .hsync_end = 704, .htotal = 832, .hskew = 0,
+ .vdisplay = 480, .vsync_start = 489, .vsync_end = 492, .vtotal = 520, .vscan = 0,
+ .flags = 0
+ },
+ { .clock = 40000,
+ .hdisplay = 800, .hsync_start = 840, .hsync_end = 968, .htotal = 1056, .hskew = 0,
+ .vdisplay = 600, .vsync_start = 601, .vsync_end = 605, .vtotal = 628, .vscan = 0,
+ .flags = 0
+ },
+ { .clock = 0,
+ },
+};
+
+#ifndef FB_CIRRUS_DEFAULT_MODE
+/* TUNABLE - until better place is found, the mode is selected there */
+/* index 0 provides 640x480 at 60 Hz, index 1 800x600 at 60 Hz */
+#define FB_CIRRUS_DEFAULT_MODE 0
+#endif
+
+#ifndef FB_CIRRUS_DEFAULT_BPP
+/* Bits per pixel, 8, 16, 24 and 32 are supported */
+/* 8 bit mode requires palete support which is not finished yet */
+#define FB_CIRRUS_DEFAULT_BPP 24
+#endif
+
+static struct fb_cirrus_state fb_cirrus[FB_CIRRUS_MAX_CARDS];
+
+static int
+fb_cirrus_read_config_dword(
+ struct fb_cirrus_state *fbst,
+ unsigned char where,
+ uint32_t *pval)
+{
+ return pci_read_config_dword(
+ fbst->pbus, fbst->pdev, fbst->pfun,
+ where, pval);
+}
+
+static int
+fb_cirrus_write_config_dword(
+ struct fb_cirrus_state *fbst,
+ unsigned char where,
+ uint32_t val)
+{
+ return pci_write_config_dword(
+ fbst->pbus, fbst->pdev, fbst->pfun,
+ where, val);
+}
+
+static void
+fb_cirrus_write_reg8 (
+ const struct fb_cirrus_state *fbst,
+ unsigned int reg,
+ unsigned int val)
+{
+ *(volatile uint8_t*)((char *)fbst->mmregs + reg) = val;
+}
+
+static void
+fb_cirrus_write_reg32 (
+ const struct fb_cirrus_state *fbst,
+ unsigned int reg,
+ uint32_t val)
+{
+ *(volatile uint32_t*)((char *)fbst->mmregs + reg) = val;
+}
+
+static unsigned int
+fb_cirrus_read_reg8 (
+ const struct fb_cirrus_state *fbst,
+ unsigned int reg)
+{
+ return *(volatile uint8_t*)((char *)fbst->mmregs + reg);
+}
+
+static uint32_t
+fb_cirrus_read_reg32 (
+ const struct fb_cirrus_state *fbst,
+ unsigned int reg)
+{
+ return *(volatile uint32_t*)((char *)fbst->mmregs + reg);
+}
+#define SEQ_INDEX 4
+#define SEQ_DATA 5
+
+static void
+fb_cirrus_write_seq_reg (
+ const struct fb_cirrus_state *fbst,
+ unsigned int reg,
+ unsigned int val)
+{
+ fb_cirrus_write_reg8(fbst, SEQ_INDEX, reg);
+ fb_cirrus_write_reg8(fbst, SEQ_DATA, val);
+}
+
+#define CRT_INDEX 0x14
+#define CRT_DATA 0x15
+
+static void
+fb_cirrus_write_crt_reg (
+ const struct fb_cirrus_state *fbst,
+ unsigned int reg,
+ unsigned int val)
+{
+ fb_cirrus_write_reg8(fbst, CRT_INDEX, reg);
+ fb_cirrus_write_reg8(fbst, CRT_DATA, val);
+}
+
+#define GDC_INDEX 0xe
+#define GDC_DATA 0xf
+
+static void
+fb_cirrus_write_gdc_reg (
+ const struct fb_cirrus_state *fbst,
+ unsigned int reg,
+ unsigned int val)
+{
+ fb_cirrus_write_reg8(fbst, GDC_INDEX, reg);
+ fb_cirrus_write_reg8(fbst, GDC_DATA, val);
+}
+
+
+#define VGA_DAC_MASK 0x6
+
+static void
+fb_cirrus_write_hdr_reg (
+ const struct fb_cirrus_state *fbst,
+ unsigned int val)
+{
+ volatile unsigned int dummy __attribute__((unused));
+ dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK);
+ dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK);
+ dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK);
+ dummy = fb_cirrus_read_reg8(fbst, VGA_DAC_MASK);
+ fb_cirrus_write_reg8(fbst, VGA_DAC_MASK, val);
+}
+
+static void
+fb_cirrus_set_start_address(
+ struct fb_cirrus_state *fbst,
+ unsigned offset)
+{
+ uint32_t addr;
+ uint8_t tmp;
+
+ addr = offset >> 2;
+ fb_cirrus_write_crt_reg(fbst, 0x0c, (uint8_t)((addr >> 8) & 0xff));
+ fb_cirrus_write_crt_reg(fbst, 0x0d, (uint8_t)(addr & 0xff));
+
+ fb_cirrus_write_reg8(fbst, CRT_INDEX, 0x1b);
+ tmp = fb_cirrus_read_reg8(fbst, CRT_DATA);
+ tmp &= 0xf2;
+ tmp |= (addr >> 16) & 0x01;
+ tmp |= (addr >> 15) & 0x0c;
+ fb_cirrus_write_crt_reg(fbst, 0x1b, tmp);
+ fb_cirrus_write_reg8(fbst, CRT_INDEX, 0x1d);
+ tmp = fb_cirrus_read_reg8(fbst, CRT_DATA);
+ tmp &= 0x7f;
+ tmp |= (addr >> 12) & 0x80;
+ fb_cirrus_write_crt_reg(fbst, 0x1d, tmp);
+}
+
+
+static int
+fb_cirrus_set_crt_mode(
+ struct fb_cirrus_state *fbst,
+ struct fb_cirrus_modeline *mode)
+{
+ int hsyncstart, hsyncend, htotal, hdispend;
+ int vtotal, vdispend;
+ int tmp;
+ int sr07 = 0, hdr = 0;
+ int x, y;
+
+ htotal = mode->htotal / 8;
+ hsyncend = mode->hsync_end / 8;
+ hsyncstart = mode->hsync_start / 8;
+ hdispend = mode->hdisplay / 8;
+
+ vtotal = mode->vtotal;
+ vdispend = mode->vdisplay;
+
+ vdispend -= 1;
+ vtotal -= 2;
+
+ htotal -= 5;
+ hdispend -= 1;
+ hsyncstart += 1;
+ hsyncend += 1;
+
+ fb_cirrus_write_crt_reg(fbst, CRTC_EndVertRetrace, 0x20);
+ fb_cirrus_write_crt_reg(fbst, CRTC_HorzTotal, htotal);
+ fb_cirrus_write_crt_reg(fbst, CRTC_HorzDispEnd, hdispend);
+ fb_cirrus_write_crt_reg(fbst, CRTC_StartHorzRetrace, hsyncstart);
+ fb_cirrus_write_crt_reg(fbst, CRTC_EndHorzRetrace, hsyncend);
+ fb_cirrus_write_crt_reg(fbst, CRTC_VertTotal, vtotal & 0xff);
+ fb_cirrus_write_crt_reg(fbst, CRTC_VertDispEnd, vdispend & 0xff);
+
+ tmp = 0x40;
+ if ((vdispend + 1) & 512)
+ tmp |= 0x20;
+ fb_cirrus_write_crt_reg(fbst, CRTC_MaxScanLine, tmp);
+
+ tmp = 16;
+ if (vtotal & 256)
+ tmp |= 1;
+ if (vdispend & 256)
+ tmp |= 2;
+ if ((vdispend + 1) & 256)
+ tmp |= 8;
+ if (vtotal & 512)
+ tmp |= 32;
+ if (vdispend & 512)
+ tmp |= 64;
+ fb_cirrus_write_crt_reg(fbst, CRTC_Overflow, tmp);
+
+ tmp = 0;
+
+ if ((htotal + 5) & 64)
+ tmp |= 16;
+ if ((htotal + 5) & 128)
+ tmp |= 32;
+ if (vtotal & 256)
+ tmp |= 64;
+ if (vtotal & 512)
+ tmp |= 128;
+
+ fb_cirrus_write_crt_reg(fbst, 0x1A, tmp);
+
+ /* Disable Hercules/CGA compatibility */
+ fb_cirrus_write_crt_reg(fbst, CRTC_ModeCtrl, 0x03);
+
+ fb_cirrus_write_reg8(fbst, SEQ_INDEX, 0x7);
+ sr07 = fb_cirrus_read_reg8(fbst, SEQ_DATA);
+ sr07 &= 0xe0;
+ hdr = 0;
+ switch (fbst->fb_var.bits_per_pixel) {
+ case 8:
+ sr07 |= 0x11;
+ break;
+ case 16:
+ sr07 |= 0xc7; /* has been 0xc1 */
+ hdr = 0xc0;
+ break;
+ case 24:
+ sr07 |= 0x15;
+ hdr = 0xc5;
+ break;
+ case 32:
+ sr07 |= 0x19;
+ hdr = 0xc5;
+ break;
+ default:
+ printk("FBCIRRUS fb_cirrus_set_crt_mode unsuported BPP\n");
+ return -1;
+ }
+
+ fb_cirrus_write_seq_reg(fbst, 0x7, sr07);
+
+ /* Program the pitch */
+ tmp = fbst->fb_fix.line_length / 8;
+ fb_cirrus_write_crt_reg(fbst, CRTC_Offset, tmp);
+
+ /* Enable extended blanking and pitch bits, and enable full memory */
+ tmp = 0x22;
+ tmp |= (fbst->fb_fix.line_length >> 7) & 0x10;
+ tmp |= (fbst->fb_fix.line_length >> 6) & 0x40;
+ fb_cirrus_write_crt_reg(fbst, 0x1b, tmp);
+
+ /* Enable high-colour modes */
+ fb_cirrus_write_gdc_reg(fbst, GDC_Mode, 0x40);
+
+ /* And set graphics mode */
+ fb_cirrus_write_gdc_reg(fbst, GDC_Misc, 0x01);
+
+ fb_cirrus_write_hdr_reg(fbst, hdr);
+
+ fb_cirrus_set_start_address(fbst, 0);
+
+
+ if (1) {
+ uint32_t pixmask;
+
+ if(fbst->fb_var.bits_per_pixel == 32)
+ pixmask = 0xffffff;
+ else
+ pixmask = (1 << fbst->fb_var.bits_per_pixel) - 1;
+
+ printk("FBCIRRUS mode set, test patter output\n");
+
+ /*while(1)*/
+ for(y = 0; y < fbst->fb_var.yres; y++) {
+ for(x = 0; x < fbst->fb_var.xres; x++) {
+ uint32_t color;
+ char *addr = (char *)fbst->fb_fix.smem_start;
+ addr += y * fbst->fb_fix.line_length;
+ addr += x * fbst->fb_var.bits_per_pixel / 8;
+ color = x & 1 ? 0 : y & 1 ? pixmask & 0x000ff00f : pixmask;
+ if(y == fbst->fb_var.yres - 1) {
+ if((x > 0) && (x < fbst->fb_var.xres-1))
+ color = pixmask & 0x00555555;
+ }
+ switch (fbst->fb_var.bits_per_pixel) {
+ case 8: *(volatile uint8_t*) addr = color;
+ break;
+ case 16: *(volatile uint16_t*) addr = color;
+ break;
+ case 24: *(volatile uint32_t*) addr =
+ (*(volatile uint32_t*) addr & 0xff000000) | color;
+ break;
+ case 32: *(volatile uint32_t*) addr = color;
+ break;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static uint16_t red16[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff
+};
+static uint16_t green16[] = {
+ 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa,
+ 0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff
+};
+static uint16_t blue16[] = {
+ 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa,
+ 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff
+};
+
+/* Functionality to support multiple VGA frame buffers can be added easily,
+ * but is not supported at this moment because there is no need for two or
+ * more "classic" VGA adapters. Multiple frame buffer drivers may be
+ * implemented and If we had implement it they would be named as "/dev/fb0",
+ * "/dev/fb1", "/dev/fb2" and so on.
+ */
+/*
+ * fbvga device driver INITIALIZE entry point.
+ */
+rtems_device_driver frame_buffer_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+ int res;
+ struct fb_cirrus_state *fbst;
+ char devname[12];
+ char *p;
+
+ if(minor >= FB_CIRRUS_MAX_CARDS) {
+ printk( "FBCIRRUS initialize -- unsupported minor\n" );
+ return RTEMS_UNSATISFIED;
+ }
+
+ fbst = &fb_cirrus[minor];
+
+ res = pci_find_device(
+ CIRRUS_VENDOR_ID,
+ CIRRUS_GD5446_DEVICE_ID,
+ minor,
+ &fbst->pbus,
+ &fbst->pdev,
+ &fbst->pfun
+ );
+
+ if ( res != PCIB_ERR_SUCCESS ) {
+ fbst->found = -1;
+ printk( "FBCIRRUS initialize -- device not found\n" );
+ return RTEMS_UNSATISFIED;
+ }
+
+ printk( "FBCIRRUS -- driver initializing..\n" );
+
+ /*
+ * Register the device
+ */
+ p = strcpy(devname, "/dev/fb0");
+ *(--p) = '0' + minor;
+
+ status = rtems_io_register_name (devname, major, 0);
+ if (status != RTEMS_SUCCESSFUL) {
+ fbst->found = -1;
+ printk("Error registering /dev/fbX FBCIRRUS framebuffer device!\n");
+ rtems_fatal_error_occurred( status );
+ }
+
+ fbst->found = 1;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * fbvga device driver OPEN entry point
+ */
+rtems_device_driver frame_buffer_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ struct fb_cirrus_state *fbst;
+ int line_bytes;
+
+ if(minor >= FB_CIRRUS_MAX_CARDS) {
+ printk( "FBCIRRUS initialize -- unsupported minor\n" );
+ return RTEMS_UNSATISFIED;
+ }
+
+ fbst = &fb_cirrus[minor];
+
+ if (pthread_mutex_trylock(&mutex)!= 0) {
+ printk( "FBCIRRUS open cannot grab mutex.\n" );
+ return RTEMS_UNSATISFIED;
+ }
+
+ printf("FBCIRRUS found %d pbus %d pdev %d pfun %d\n",
+ fbst->found, fbst->pbus, fbst->pdev, fbst->pfun);
+
+ fb_cirrus_read_config_dword(fbst, PCI_BASE_ADDRESS_0, &fbst->pci_bar[0]);
+ fb_cirrus_read_config_dword(fbst, PCI_BASE_ADDRESS_1, &fbst->pci_bar[1]);
+ fb_cirrus_read_config_dword(fbst, PCI_BASE_ADDRESS_2, &fbst->pci_bar[2]);
+ fb_cirrus_read_config_dword(fbst, PCI_BASE_ADDRESS_3, &fbst->pci_bar[3]);
+
+ fbst->pci_bar[0] &= PCI_BASE_ADDRESS_MEM_MASK;
+ fbst->pci_bar[1] &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ printf("FBCIRRUS PCI BARs 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n",
+ fbst->pci_bar[0], fbst->pci_bar[1], fbst->pci_bar[2], fbst->pci_bar[3]);
+
+ if (_CPU_is_paging_enabled()) {
+ _CPU_map_phys_address((void **) &(fbst->fb_fix.smem_start),
+ (void *)(fbst->pci_bar[0]),
+ 0x1000000 ,
+ PTE_CACHE_DISABLE | PTE_WRITABLE);
+ _CPU_map_phys_address((void **) &(fbst->mmregs),
+ (void *)(fbst->pci_bar[1]),
+ 0x1000,
+ PTE_CACHE_DISABLE | PTE_WRITABLE);
+ } else {
+ fbst->fb_fix.smem_start = (volatile char *)fbst->pci_bar[0];
+ fbst->mmregs = (void *)fbst->pci_bar[1];
+ }
+
+ fbst->fb_fix.smem_len = 0x1000000;
+
+ fbst->fb_fix.type = FB_TYPE_PACKED_PIXELS;
+ fbst->fb_fix.visual = FB_VISUAL_TRUECOLOR;
+
+ printf("FBCIRRUS remapped fb 0x%08lx mmregs 0x%08lx\n",
+ (unsigned long)fbst->fb_fix.smem_start, (unsigned long)fbst->mmregs);
+
+ fbst->active_mode = &fb_cirrus_std_modelines[FB_CIRRUS_DEFAULT_MODE];
+
+ fbst->fb_var.bits_per_pixel = FB_CIRRUS_DEFAULT_BPP;
+
+ fbst->fb_var.xres = fbst->active_mode->hdisplay;
+ fbst->fb_var.yres = fbst->active_mode->vdisplay;
+
+ line_bytes = fbst->fb_var.xres * fbst->fb_var.bits_per_pixel;
+
+ line_bytes = (line_bytes + 7) / 8;
+
+ fbst->fb_fix.line_length = line_bytes;
+
+ fb_cirrus_set_crt_mode(fbst, fbst->active_mode);
+
+ printk( "FBCIRRUS open called.\n" );
+ return RTEMS_SUCCESSFUL;
+
+}
+
+/*
+ * fbvga device driver CLOSE entry point
+ */
+rtems_device_driver frame_buffer_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ if (pthread_mutex_unlock(&mutex) == 0){
+ /* restore previous state. for VGA this means return to text mode.
+ * leave out if graphics hardware has been initialized in
+ * frame_buffer_initialize() */
+ printk( "FBCIRRUS close called.\n" );
+ return RTEMS_SUCCESSFUL;
+ }
+
+ return RTEMS_UNSATISFIED;
+}
+
+/*
+ * fbvga device driver READ entry point.
+ */
+rtems_device_driver frame_buffer_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ struct fb_cirrus_state *fbst;
+
+ if(minor >= FB_CIRRUS_MAX_CARDS) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ fbst = &fb_cirrus[minor];
+
+ rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
+ rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fbst->fb_fix.smem_len ) ? (fbst->fb_fix.smem_len -
rw_args->offset) : rw_args->count;
+ memcpy(rw_args->buffer, (const void *) (fbst->fb_fix.smem_start + rw_args->offset), rw_args->bytes_moved);
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * frame_buffer device driver WRITE entry point.
+ */
+rtems_device_driver frame_buffer_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ struct fb_cirrus_state *fbst;
+
+ if(minor >= FB_CIRRUS_MAX_CARDS) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ fbst = &fb_cirrus[minor];
+
+ rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t *)arg;
+ rw_args->bytes_moved = ((rw_args->offset + rw_args->count) > fbst->fb_fix.smem_len ) ? (fbst->fb_fix.smem_len -
rw_args->offset) : rw_args->count;
+ memcpy( (void *) (fbst->fb_fix.smem_start + rw_args->offset), rw_args->buffer, rw_args->bytes_moved);
+ return RTEMS_SUCCESSFUL;
+}
+
+static int get_fix_screen_info(struct fb_cirrus_state *fbst, struct fb_fix_screeninfo *info )
+{
+ *info = fbst->fb_fix;
+ return 0;
+}
+
+static int get_var_screen_info(struct fb_cirrus_state *fbst, struct fb_var_screeninfo *info )
+{
+ *info = fbst->fb_var;
+ return 0;
+}
+
+static int get_palette(struct fb_cirrus_state *fbst, struct fb_cmap *cmap )
+{
+ uint32_t i;
+
+ if ( cmap->start + cmap->len >= 16 )
+ return 1;
+
+ for( i = 0; i < cmap->len; i++ ) {
+ cmap->red[ cmap->start + i ] = red16[ cmap->start + i ];
+ cmap->green[ cmap->start + i ] = green16[ cmap->start + i ];
+ cmap->blue[ cmap->start + i ] = blue16[ cmap->start + i ];
+ }
+ return 0;
+}
+
+static int set_palette(struct fb_cirrus_state *fbst, struct fb_cmap *cmap )
+{
+ uint32_t i;
+
+ if ( cmap->start + cmap->len >= 16 )
+ return 1;
+
+ for( i = 0; i < cmap->len; i++ ) {
+ red16[ cmap->start + i ] = cmap->red[ cmap->start + i ];
+ green16[ cmap->start + i ] = cmap->green[ cmap->start + i ];
+ blue16[ cmap->start + i ] = cmap->blue[ cmap->start + i ];
+ }
+ return 0;
+}
+
+/*
+ * IOCTL entry point -- This method is called to carry
+ * all services of this interface.
+ */
+rtems_device_driver frame_buffer_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_libio_ioctl_args_t *args = arg;
+ struct fb_cirrus_state *fbst;
+
+ if(minor >= FB_CIRRUS_MAX_CARDS) {
+ return RTEMS_UNSATISFIED;
+ }
+
+ fbst = &fb_cirrus[minor];
+
+ printk( "FBCIRRUS ioctl called, cmd=%x\n", args->command );
+
+ switch( args->command ) {
+ case FBIOGET_FSCREENINFO:
+ args->ioctl_return = get_fix_screen_info( fbst, ( struct fb_fix_screeninfo * ) args->buffer );
+ break;
+ case FBIOGET_VSCREENINFO:
+ args->ioctl_return = get_var_screen_info( fbst, ( struct fb_var_screeninfo * ) args->buffer );
+ break;
+ case FBIOPUT_VSCREENINFO:
+ /* not implemented yet*/
+ args->ioctl_return = -1;
+ return RTEMS_UNSATISFIED;
+ case FBIOGETCMAP:
+ args->ioctl_return = get_palette( fbst, ( struct fb_cmap * ) args->buffer );
+ break;
+ case FBIOPUTCMAP:
+ args->ioctl_return = set_palette( fbst, ( struct fb_cmap * ) args->buffer );
+ break;
+
+ default:
+ args->ioctl_return = 0;
+ break;
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
diff --git a/c/src/lib/libbsp/i386/pc386/console/vga_registers.h b/c/src/lib/libbsp/i386/pc386/console/vga_registers.h
new file mode 100644
index 0000000..816269f
--- /dev/null
+++ b/c/src/lib/libbsp/i386/pc386/console/vga_registers.h
@@ -0,0 +1,102 @@
+
+/*
+ * Copyright (c) 1992, 1993, 1996
+ * Berkeley Software Design, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Berkeley Software
+ * Design, Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * BSDI video.h,v 2.2 1996/04/08 19:33:12 bostic Exp
+ *
+ * Subset of the full header file adapted for RTEMS operating system from
+ *
+ * FreeBSD: src/usr.bin/doscmd/video.h,v 1.2.2.1 2002/04/25 11:04:51 tg Exp $
+ */
+
+/* CRTC registers
+
+ We use the VGA register functions and don't care about the MDA. We also
+ leave out the undocumented registers at 0x22, 0x24, 0x3?. */
+#define CRTC_HorzTotal 0x00
+#define CRTC_HorzDispEnd 0x01
+#define CRTC_StartHorzBlank 0x02
+#define CRTC_EndHorzBlank 0x03
+#define CRTC_StartHorzRetrace 0x04
+#define CRTC_EndHorzRetrace 0x05
+#define CRTC_VertTotal 0x06
+#define CRTC_Overflow 0x07
+#define CRTC_ResetRowScan 0x08
+#define CRTC_MaxScanLine 0x09
+#define CRTC_CursStart 0x0a
+#define CRTC_CursEnd 0x0b
+#define CRTC_StartAddrHi 0x0c
+#define CRTC_StartAddrLo 0x0d
+#define CRTC_CurLocHi 0x0e
+#define CRTC_CurLocLo 0x0f
+#define CRTC_StartVertRetrace 0x10
+#define CRTC_EndVertRetrace 0x11
+#define CRTC_VertDispEnd 0x12
+#define CRTC_Offset 0x13
+#define CRTC_UnderlineLoc 0x14
+#define CRTC_StartVertBlank 0x15
+#define CRTC_EndVertBlank 0x16
+#define CRTC_ModeCtrl 0x17
+#define CRTC_LineCompare 0x18
+
+#define CRTC_Size 0x19
+
+/* Port addresses for the CRTC
+
+ The registers are read by
+ OUT index_port, reg_nr
+ IN data_port, res
+
+ They are written by
+ OUT index_port, reg_nr
+ OUT data_port, value
+*/
+
+#define CRTC_IndexPortColor 0x03d4 /* CRTC Address Register (Color) */
+#define CRTC_DataPortColor 0x03d5 /* CRTC Data Register (Color) */
+#define CRTC_IndexPortMono 0x03b4 /* CRTC Address Register (Mono) */
+#define CRTC_DataPortMono 0x03b5 /* CRTC Data Register (Mono) */
+
+/* GDC registers */
+#define GDC_SetReset 0x00
+#define GDC_EnableSetReset 0x01
+#define GDC_ColorCompare 0x02
+#define GDC_DataRotate 0x03
+#define GDC_ReadMapSelect 0x04
+#define GDC_Mode 0x05
+#define GDC_Misc 0x06
+#define GDC_ColorDontCare 0x07
+#define GDC_BitMask 0x08
+
+#define GDC_Size 0x09
+
+/* Port addresses for the GDC */
+#define GDC_IndexPort 0x03ce
+#define GDC_DataPort 0x03cf
+
--
1.7.10
More information about the devel
mailing list