diff options
Diffstat (limited to 'sys/dev/ic/vgafb.c')
-rw-r--r-- | sys/dev/ic/vgafb.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/sys/dev/ic/vgafb.c b/sys/dev/ic/vgafb.c new file mode 100644 index 00000000000..8bda3471d3a --- /dev/null +++ b/sys/dev/ic/vgafb.c @@ -0,0 +1,530 @@ +/* $OpenBSD: vgafb.c,v 1.1 1998/09/27 03:55:59 rahnds Exp $ */ +/* $NetBSD: vga.c,v 1.3 1996/12/02 22:24:54 cgd Exp $ */ + +/* + * Copyright (c) 1995, 1996 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Chris G. Demetriou + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <machine/bus.h> + +#include <dev/wscons/wsconsvar.h> +#include <dev/ic/vgafbvar.h> + + +struct cfdriver vgafb_cd = { + NULL, "vgafb", DV_DULL, +}; + +void vgafb_cursor __P((void *, int, int, int)); +void vgafb_putstr __P((void *, int, int, char *, int)); +void vgafb_copycols __P((void *, int, int, int, int)); +void vgafb_erasecols __P((void *, int, int, int)); +void vgafb_copyrows __P((void *, int, int, int)); +void vgafb_eraserows __P((void *, int, int)); +void vgafb_set_attr __P((void *, int)); + +static void drawChar ( struct vgafb_config *vc, char ch, int cx, + int cy, char at); +static void setPixel( struct vgafb_config *vc, int x, int y, int v); +static void vgafb_invert_char ( struct vgafb_config *vc, int cx, int cy); +extern const char fontdata_8x16[]; + +struct wscons_emulfuncs vgafb_emulfuncs = { + vgafb_cursor, + vgafb_putstr, + vgafb_copycols, + vgafb_erasecols, + vgafb_copyrows, + vgafb_eraserows, + vgafb_set_attr, +}; + +int vgafb_print __P((void *, const char *)); + +#define FONT_WIDTH 8 +#define FONT_HEIGHT 16 + +/* + * The following functions implement back-end configuration grabbing + * and attachment. + */ +int +vgafb_common_probe(iot, memt, iobase, membase, memsize) + bus_space_tag_t iot, memt; + u_int32_t iobase, membase; + size_t memsize; +{ + bus_space_handle_t ioh_b, ioh_c, ioh_d, memh; + u_int16_t vgadata; + int gotio_b, gotio_c, gotio_d, gotmem, rv; + int width; + + gotio_b = gotio_c = gotio_d = gotmem = rv = 0; + + if (bus_space_map(iot, iobase+0x3b0, 0xc, 0, &ioh_b)) + goto bad; + gotio_b = 1; + if (bus_space_map(iot, iobase+0x3c0, 0x10, 0, &ioh_c)) + goto bad; + gotio_c = 1; + if (bus_space_map(iot, iobase+0x3d0, 0x10, 0, &ioh_d)) + goto bad; + gotio_d = 1; + if (bus_space_map(memt, membase, memsize, 0, &memh)) + goto bad; + gotmem = 1; + +#if 0 + /* CR1 - Horiz. Display End */ + bus_space_write_1(iot, ioh_d, 4, 0x1); + width = bus_space_read_1(iot, ioh_d, 5); + /* this is not bit width yet */ + + /* use CR17 - mode control for this?? */ + if ((width != 0xff) && (width < 600)) { + /* not accessable or in graphics mode? */ + goto bad; + } +#endif + + vgadata = bus_space_read_2(memt, memh, 0); + bus_space_write_2(memt, memh, 0, 0xa55a); + rv = (bus_space_read_2(memt, memh, 0) == 0xa55a); + bus_space_write_2(memt, memh, 0, vgadata); + +bad: + if (gotio_b) + bus_space_unmap(iot, ioh_b, 0xc); + if (gotio_c) + bus_space_unmap(iot, ioh_c, 0x10); + if (gotio_d) + bus_space_unmap(iot, ioh_d, 0x10); + if (gotmem) + bus_space_unmap(memt, memh, memsize); + + return (rv); +} + +void +vgafb_common_setup(iot, memt, vc, iobase, membase, memsize) + bus_space_tag_t iot, memt; + struct vgafb_config *vc; + u_int32_t iobase, membase; + size_t memsize; +{ + int cpos; + int width, height; + + vc->vc_iot = iot; + vc->vc_memt = memt; + + if (bus_space_map(vc->vc_iot, iobase+0x3b0, 0xc, 0, &vc->vc_ioh_b)) + panic("vgafb_common_setup: couldn't map io b"); + if (bus_space_map(vc->vc_iot, iobase+0x3c0, 0x10, 0, &vc->vc_ioh_c)) + panic("vgafb_common_setup: couldn't map io c"); + if (bus_space_map(vc->vc_iot, iobase+0x3d0, 0x10, 0, &vc->vc_ioh_d)) + panic("vgafb_common_setup: couldn't map io d"); + if (bus_space_map(vc->vc_memt, membase, memsize, 0, &vc->vc_memh)) + panic("vgafb_common_setup: couldn't map memory"); + + /* CR1 - Horiz. Display End */ + bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x1); + width = bus_space_read_1(iot, vc->vc_ioh_d, 5); + /* (stored value + 1) * depth -> pixel width */ + width = ( width + 1 ) * 8; + vc->vc_ncol = width / FONT_WIDTH; + + /* CR1 - Horiz. Display End */ + bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x12); + { + u_int8_t t1, t2, t3; + bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x12); + t1 = bus_space_read_1(iot, vc->vc_ioh_d, 5); + + bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x7); + t2 = bus_space_read_1(iot, vc->vc_ioh_d, 5); + height = t1 + ((t2&0x40) << 3) + + ((t2&0x02) << 7) + 1; + bus_space_write_1(iot, vc->vc_ioh_d, 4, 0x17); + t3 = bus_space_read_1(iot, vc->vc_ioh_d, 5); + if (t3 & 0x04) { + height *= 2; + } + } + vc->vc_nrow = height / FONT_HEIGHT; + + printf("col %d row %d\n", vc->vc_ncol, vc->vc_nrow ); +#if 0 + /* assume resolution is 640x480 */ + vc->vc_nrow = 25; + vc->vc_ncol = 80; + + bus_space_write_1(iot, vc->vc_ioh_d, VGA_IO_D_6845_ADDR, 14); + cpos = bus_space_read_1(iot, vc->vc_ioh_d, VGA_IO_D_6845_DATA) << 8; + bus_space_write_1(iot, vc->vc_ioh_d, VGA_IO_D_6845_ADDR, 15); + cpos |= bus_space_read_1(iot, vc->vc_ioh_d, VGA_IO_D_6845_DATA); + vc->vc_crow = cpos / vc->vc_ncol; + vc->vc_ccol = cpos % vc->vc_ncol; +#endif + + vc->vc_so = 0; + + /* clear screen, frob cursor, etc.? */ + vgafb_eraserows(vc, 0, vc->vc_nrow); +#if defined(alpha) + /* + * XXX DEC HAS SWITCHED THE CODES FOR BLUE AND RED!!! + * XXX Therefore, though the comments say "blue bg", the code uses + * XXX the value for a red background! + */ + vc->vc_at = 0x40 | 0x0f; /* blue bg|white fg */ + vc->vc_so_at = 0x40 | 0x0f | 0x80; /* blue bg|white fg|blink */ +#else + vc->vc_at = 0x00 | 0xf; /* black bg|white fg */ + vc->vc_so_at = 0x00 | 0xf | 0x80; /* black bg|white fg|blink */ +#endif +} + +void +vgafb_wscons_attach(parent, vc, console) + struct device *parent; + struct vgafb_config *vc; + int console; +{ + struct wscons_attach_args waa; + struct wscons_odev_spec *wo; + + waa.waa_isconsole = console; + wo = &waa.waa_odev_spec; + + wo->wo_emulfuncs = &vgafb_emulfuncs; + wo->wo_emulfuncs_cookie = vc; + + wo->wo_ioctl = vc->vc_ioctl; + wo->wo_mmap = vc->vc_mmap; + wo->wo_miscfuncs_cookie = vc; + + wo->wo_nrows = vc->vc_nrow; + wo->wo_ncols = vc->vc_ncol; + wo->wo_crow = vc->vc_crow; + wo->wo_ccol = vc->vc_ccol; + + config_found(parent, &waa, vgafb_print); +} + +void +vgafb_wscons_console(vc) + struct vgafb_config *vc; +{ + struct wscons_odev_spec wo; + + wo.wo_emulfuncs = &vgafb_emulfuncs; + wo.wo_emulfuncs_cookie = vc; + + /* ioctl and mmap are unused until real attachment. */ + + wo.wo_nrows = vc->vc_nrow; + wo.wo_ncols = vc->vc_ncol; + wo.wo_crow = vc->vc_crow; + wo.wo_ccol = vc->vc_ccol; + + wscons_attach_console(&wo); +} + +int +vgafb_print(aux, pnp) + void *aux; + const char *pnp; +{ + + if (pnp) + printf("wscons at %s", pnp); + return (UNCONF); +} + +int +vgafbioctl(v, cmd, data, flag, p) + void *v; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + /*struct vgafb_config *vc = v;*/ + + /* XXX */ + return -1; +} + +int +vgafbmmap(v, offset, prot) + void *v; + off_t offset; + int prot; +{ + struct vgafb_config *vc = v; + bus_space_handle_t h; + u_int32_t *port; + + if (offset >= 0x00000 && offset < 0x100000) /* 1MB of mem */ + h = vc->vc_memh + offset; + else if (offset >= 0x10000 && offset < 0x140000) /* 256KB of iohb */ + h = vc->vc_ioh_b; + else if (offset >= 0x140000 && offset < 0x180000) /* 256KB of iohc */ + h = vc->vc_ioh_c; + else if (offset >= 0x180000 && offset < 0x1c0000) /* 256KB of iohd */ + h = vc->vc_ioh_d; + else + return (-1); + + port = (u_int32_t *)(h << 5); +#ifdef alpha + return alpha_btop(port); /* XXX */ +#elif defined(i386) + return i386_btop(port); +#elif defined(__powerpc__) + return powerpc_btop(port); +#endif +} + +/* + * The following functions implement the MI ANSI terminal emulation on + * a VGA display. + */ +void +vgafb_cursor(id, on, row, col) + void *id; + int on, row, col; +{ + struct vgafb_config *vc = id; + bus_space_tag_t iot = vc->vc_iot; + bus_space_handle_t ioh_d = vc->vc_ioh_d; + int pos; + +#if 0 + printf("vgafb_cursor: %d %d\n", row, col); +#endif + if (( vc->vc_crow != -1) && (vc->vc_ccol != -1)) { + vgafb_invert_char (vc, vc->vc_ccol, vc->vc_crow); + } + /* turn the cursor off */ + if (!on) { + /* XXX disable cursor how??? */ + vc->vc_crow = vc->vc_ccol = -1; + } else { + vc->vc_crow = row; + + vc->vc_ccol = col; + vgafb_invert_char (vc, col, row); + } + +#if 0 + pos = row * vc->vc_ncol + col; + + bus_space_write_1(iot, ioh_d, VGA_IO_D_6845_ADDR, 14); + bus_space_write_1(iot, ioh_d, VGA_IO_D_6845_DATA, pos >> 8); + bus_space_write_1(iot, ioh_d, VGA_IO_D_6845_ADDR, 15); + bus_space_write_1(iot, ioh_d, VGA_IO_D_6845_DATA, pos); +#endif +} + +void +vgafb_putstr(id, row, col, cp, len) + void *id; + int row, col; + char *cp; + int len; +{ + struct vgafb_config *vc = id; + bus_space_tag_t memt = vc->vc_memt; + bus_space_handle_t memh = vc->vc_memh; + int i, off; + + for (i = 0; i < len; i++, cp++, col++) { + drawChar(vc, *cp, col, row, vc->vc_so ? vc->vc_so_at : vc->vc_at); + } +} + +void +vgafb_copycols(id, row, srccol, dstcol, ncols) + void *id; + int row, srccol, dstcol, ncols; +{ + struct vgafb_config *vc = id; + bus_size_t srcoff, dstoff; + int i; + + srcoff = ((row*FONT_HEIGHT) * (vc->vc_ncol*FONT_WIDTH) + + srccol*FONT_WIDTH); + dstoff = ((row*FONT_HEIGHT) * (vc->vc_ncol*FONT_WIDTH) + + dstcol*FONT_WIDTH); + for (i = 0; i < FONT_HEIGHT; i++) { + bus_space_copy_1(vc->vc_memt, vc->vc_memh, srcoff, + vc->vc_memh, dstoff, ncols*FONT_WIDTH); + } +} + +void +vgafb_erasecols(id, row, startcol, ncols) + void *id; + int row, startcol, ncols; +{ + struct vgafb_config *vc = id; + bus_size_t off; + int i; + + for (i=0; i < ncols; i++) { + drawChar( vc, ' ', startcol+i, row, vc->vc_at); + } +} + +void +vgafb_copyrows(id, srcrow, dstrow, nrows) + void *id; + int srcrow, dstrow, nrows; +{ + struct vgafb_config *vc = id; + bus_size_t srcoff, dstoff; + + srcoff = ((srcrow*FONT_HEIGHT) * (vc->vc_ncol*FONT_WIDTH) + 0); + dstoff = ((dstrow*FONT_HEIGHT) * (vc->vc_ncol*FONT_WIDTH) + 0); + + bus_space_copy_1(vc->vc_memt, vc->vc_memh, srcoff, vc->vc_memh, dstoff, + (nrows*FONT_HEIGHT) * (vc->vc_ncol*FONT_WIDTH)); +} + +void +vgafb_eraserows(id, startrow, nrows) + void *id; + int startrow, nrows; +{ + struct vgafb_config *vc = id; + bus_size_t off, count; + u_int16_t val; + + off = (startrow*FONT_HEIGHT) * (vc->vc_ncol*FONT_WIDTH) + 0; + count = (nrows*FONT_HEIGHT) * (vc->vc_ncol*FONT_WIDTH); + + val = (vc->vc_at & 0xf); + + bus_space_set_region_1(vc->vc_memt, vc->vc_memh, off, val, count); +} + +void +vgafb_set_attr(id, val) + void *id; + int val; +{ + struct vgafb_config *vc = id; + + vc->vc_so = val; +} + +static void +setPixel(vc, x, y, v) + struct vgafb_config *vc; + int x, y, v; +{ + bus_space_tag_t memt = vc->vc_memt; + bus_space_handle_t memh = vc->vc_memh; + + bus_space_write_1(memt, memh, x+(y*(vc->vc_ncol*FONT_WIDTH)), v); +} +static void +invertPixel(vc, x, y) + struct vgafb_config *vc; + int x, y; +{ + bus_space_tag_t memt = vc->vc_memt; + bus_space_handle_t memh = vc->vc_memh; + u_int8_t v; + + v = bus_space_read_1(memt, memh, x+(y*(vc->vc_ncol*FONT_WIDTH))); + v = ~v & 0xf; + bus_space_write_1(memt, memh, x+(y*(vc->vc_ncol*FONT_WIDTH)), v); +} + +static void +drawChar ( vc, ch, cx, cy, at) + struct vgafb_config *vc; + char ch; + int cx, cy; + char at; +{ + const char *cp; + unsigned char mask; + int i, j; + int x, y; + + i = ch * FONT_HEIGHT; + cp = &fontdata_8x16[ i ]; + + if ((cx == vc->vc_ccol) && (cy == vc->vc_crow)) { + char tmp = at; + at = ((at & 0xf) << 4) | ((at >> 4) & 0xf); + } + x = cx*FONT_WIDTH; y = cy*FONT_HEIGHT; + + for ( i = 0; i < FONT_HEIGHT; i++ ) + { + for ( j = 0; j < FONT_WIDTH; j++) + { + mask = 0x80 >> j; + if ( *cp & mask ) + setPixel(vc, x, y, (at >> 4) & 0xf ); + else + setPixel(vc, x, y, at & 0xf ); + x++; + } + cp++; y++; x = cx*FONT_WIDTH; + } +} +static void +vgafb_invert_char ( vc, cx, cy) + struct vgafb_config *vc; + int cx, cy; +{ + const char *cp; + unsigned char mask; + int i, j; + int x, y; + + x = cx*FONT_WIDTH; y = cy*FONT_HEIGHT; + + for ( i = 0; i < FONT_HEIGHT; i++ ) + { + for ( j = 0; j < FONT_WIDTH; j++) + { + invertPixel(vc, x, y); + x++; + } + cp++; y++; x = cx*FONT_WIDTH; + } +} |