diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2014-03-18 23:23:10 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2014-03-18 23:23:10 +0000 |
commit | 98da4b14905005a075c8bbde39c65736d947bed9 (patch) | |
tree | fddfaca79575ed87958dfe035a6a8a55072e6950 /sys/arch/sgi/gio | |
parent | 0e2ce90ab42caa84a113eb84c2ad7c6b72175807 (diff) |
- Fix clipping bounds in fill and blt operations; the lower-right corner is
supposed to be outside the clipping region, not inside (i.e. there was an
off-by-one everywhere).
- Add colormap support, by programming the RAMDAC palette registers at init
time, and also implement the colormap ioctls.
Diffstat (limited to 'sys/arch/sgi/gio')
-rw-r--r-- | sys/arch/sgi/gio/light.c | 252 | ||||
-rw-r--r-- | sys/arch/sgi/gio/lightreg.h | 11 |
2 files changed, 194 insertions, 69 deletions
diff --git a/sys/arch/sgi/gio/light.c b/sys/arch/sgi/gio/light.c index a39516e8628..a13bf64ca60 100644 --- a/sys/arch/sgi/gio/light.c +++ b/sys/arch/sgi/gio/light.c @@ -1,8 +1,8 @@ -/* $OpenBSD: light.c,v 1.4 2012/10/03 22:46:09 miod Exp $ */ +/* $OpenBSD: light.c,v 1.5 2014/03/18 23:23:09 miod Exp $ */ /* $NetBSD: light.c,v 1.5 2007/03/04 06:00:39 christos Exp $ */ /* - * Copyright (c) 2012 Miodrag Vallat. + * Copyright (c) 2012, 2014 Miodrag Vallat. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -98,6 +98,8 @@ struct light_devconfig { struct light_softc *dc_sc; struct wsscreen_descr dc_wsd; + + uint8_t dc_cmap[256 * 3]; }; /* always 1024x768x8 */ @@ -126,11 +128,11 @@ int light_show_screen(void *, void *, int, void (*)(void *, int, int), void *); struct wsdisplay_accessops light_accessops = { - .ioctl = light_ioctl, - .mmap = light_mmap, - .alloc_screen = light_alloc_screen, - .free_screen = light_free_screen, - .show_screen = light_show_screen, + .ioctl = light_ioctl, + .mmap = light_mmap, + .alloc_screen = light_alloc_screen, + .free_screen = light_free_screen, + .show_screen = light_show_screen, }; int light_do_cursor(struct rasops_info *); @@ -144,10 +146,8 @@ static __inline__ uint32_t rex_read(struct light_devconfig *, uint32_t, uint32_t); static __inline__ void rex_write(struct light_devconfig *, uint32_t, uint32_t, uint32_t); -static __inline__ -uint8_t rex_vc1_read(struct light_devconfig *); -static __inline__ -void rex_vc1_write(struct light_devconfig *, uint8_t); +uint8_t rex_vc1_sysctl_read(struct light_devconfig *); +void rex_vc1_sysctl_write(struct light_devconfig *, uint8_t); static __inline__ void rex_wait(struct light_devconfig *); static __inline__ @@ -156,6 +156,10 @@ void rex_copy_rect(struct light_devconfig *, int, int, int, int, int, int, int); void rex_fill_rect(struct light_devconfig *, int, int, int, int, int); +int light_getcmap(struct light_devconfig *, struct wsdisplay_cmap *); +void light_loadcmap(struct light_devconfig *, int, int); +int light_putcmap(struct light_devconfig *, struct wsdisplay_cmap *); + void light_attach_common(struct light_devconfig *, struct gio_attach_args *); void light_init_screen(struct light_devconfig *); @@ -163,15 +167,15 @@ static struct light_devconfig light_console_dc; #define LIGHT_IS_LG1(_rev) ((_rev) < 2) /* else LG2 */ -/******************************************************************************* - * REX routines and helper functions - ******************************************************************************/ +/* + * REX routines and helper functions. + */ static __inline__ uint32_t rex_read(struct light_devconfig *dc, uint32_t rset, uint32_t r) { - return (bus_space_read_4(dc->dc_st, dc->dc_sh, rset + r)); + return bus_space_read_4(dc->dc_st, dc->dc_sh, rset + r); } static __inline__ @@ -181,20 +185,20 @@ rex_write(struct light_devconfig *dc, uint32_t rset, uint32_t r, uint32_t v) bus_space_write_4(dc->dc_st, dc->dc_sh, rset + r, v); } -static __inline__ uint8_t -rex_vc1_read(struct light_devconfig *dc) +rex_vc1_sysctl_read(struct light_devconfig *dc) { rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_SYSCTL); + rex_read(dc, REX_PAGE1_GO, REX_P1REG_VC1_ADDRDATA); - return (rex_read(dc, REX_PAGE1_SET, REX_P1REG_VC1_ADDRDATA)); + return rex_read(dc, REX_PAGE1_SET, REX_P1REG_VC1_ADDRDATA); } -static __inline__ void -rex_vc1_write(struct light_devconfig *dc, uint8_t val) +rex_vc1_sysctl_write(struct light_devconfig *dc, uint8_t val) { rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_SYSCTL); + rex_write(dc, REX_PAGE1_SET, REX_P1REG_VC1_ADDRDATA, val); rex_write(dc, REX_PAGE1_GO, REX_P1REG_VC1_ADDRDATA, val); } @@ -213,7 +217,7 @@ rex_revision(struct light_devconfig *dc) { rex_write(dc, REX_PAGE1_SET, REX_P1REG_CFGSEL, REX_CFGSEL_VC1_LADDR); rex_read(dc, REX_PAGE1_GO, REX_P1REG_WCLOCKREV); - return (rex_read(dc, REX_PAGE1_SET, REX_P1REG_WCLOCKREV) & 0x7); + return rex_read(dc, REX_PAGE1_SET, REX_P1REG_WCLOCKREV) & 0x7; } void @@ -227,11 +231,11 @@ rex_copy_rect(struct light_devconfig *dc, int from_x, int from_y, int to_x, /* adjust for y. NB: STOPONX, STOPONY are inclusive */ if (to_y > from_y) { - ystarti = to_y + height - 1; + ystarti = to_y + height; yendi = to_y; } else { ystarti = to_y; - yendi = to_y + height - 1; + yendi = to_y + height; } rex_wait(dc); @@ -269,9 +273,103 @@ rex_fill_rect(struct light_devconfig *dc, int from_x, int from_y, int to_x, rex_read(dc, REX_PAGE0_GO, REX_P0REG_COMMAND); } -/******************************************************************************* - * match/attach functions - ******************************************************************************/ +/* + * Colormap routines + */ + +int +light_getcmap(struct light_devconfig *dc, struct wsdisplay_cmap *cm) +{ + u_int index = cm->index, count = cm->count, i; + u_int colcount = 1 << dc->dc_ri.ri_depth; + int rc; + u_int8_t color[256], *c, *r; + + if (index >= colcount || count > colcount - index) + return EINVAL; + + c = dc->dc_cmap + 0 + index * 3; + for (i = count, r = color; i != 0; i--) { + *r++ = *c; + c += 3; + } + if ((rc = copyout(color, cm->red, count)) != 0) + return rc; + + c = dc->dc_cmap + 1 + index * 3; + for (i = count, r = color; i != 0; i--) { + *r++ = *c; + c += 3; + } + if ((rc = copyout(color, cm->green, count)) != 0) + return rc; + + c = dc->dc_cmap + 2 + index * 3; + for (i = count, r = color; i != 0; i--) { + *r++ = *c; + c += 3; + } + if ((rc = copyout(color, cm->blue, count)) != 0) + return rc; + + return 0; +} + +int +light_putcmap(struct light_devconfig *dc, struct wsdisplay_cmap *cm) +{ + u_int index = cm->index, count = cm->count; + u_int colcount = 1 << dc->dc_ri.ri_depth; + int i, rc; + u_int8_t r[256], g[256], b[256], *nr, *ng, *nb, *c; + + if (index >= colcount || count > colcount - index) + return EINVAL; + + if ((rc = copyin(cm->red, r, count)) != 0) + return rc; + if ((rc = copyin(cm->green, g, count)) != 0) + return rc; + if ((rc = copyin(cm->blue, b, count)) != 0) + return rc; + + nr = r, ng = g, nb = b; + c = dc->dc_cmap + index * 3; + for (i = count; i != 0; i--) { + *c++ = *nr++; + *c++ = *ng++; + *c++ = *nb++; + } + + return 0; +} + +void +light_loadcmap(struct light_devconfig *dc, int from, int count) +{ + u_int8_t *cmap = dc->dc_cmap; + + /* XXX should wait for retrace first */ + + cmap += 3 * from; + rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_DAC_RADDR); + rex_write(dc, REX_PAGE1_SET, REX_P1REG_DAC_ADDRDATA, from); + rex_write(dc, REX_PAGE1_GO, REX_P1REG_DAC_ADDRDATA, from); + + rex_write(dc, REX_PAGE1_GO, REX_P1REG_CFGSEL, REX_CFGSEL_DAC_CMAP); + while (count-- > 0) { + rex_write(dc, REX_PAGE1_GO, REX_P1REG_DAC_ADDRDATA, *cmap); + rex_write(dc, REX_PAGE1_SET, REX_P1REG_DAC_ADDRDATA, *cmap++); + rex_write(dc, REX_PAGE1_GO, REX_P1REG_DAC_ADDRDATA, *cmap); + rex_write(dc, REX_PAGE1_SET, REX_P1REG_DAC_ADDRDATA, *cmap++); + rex_write(dc, REX_PAGE1_GO, REX_P1REG_DAC_ADDRDATA, *cmap); + rex_write(dc, REX_PAGE1_SET, REX_P1REG_DAC_ADDRDATA, *cmap++); + } +} + +/* + * Autoconf and console glue + */ int light_match(struct device *parent, void *vcf, void *aux) @@ -314,8 +412,8 @@ light_attach(struct device *parent, struct device *self, void *aux) printf(": LG%dMC\n", LIGHT_IS_LG1(sc->sc_dc->dc_boardrev) ? 1 : 2); printf(", revision %d\n", dc->dc_boardrev); - printf("%s: %dx%d %d-bit frame buffer\n", - self->dv_xname, LIGHT_XRES, LIGHT_YRES, LIGHT_DEPTH); + printf("%s: %dx%d %d-bit frame buffer\n", self->dv_xname, + dc->dc_ri.ri_width, dc->dc_ri.ri_height, dc->dc_ri.ri_depth); sc->sc_scrlist[0] = &dc->dc_wsd; sc->sc_wsl.nscreens = 1; @@ -359,8 +457,8 @@ light_attach_common(struct light_devconfig *dc, struct gio_attach_args *ga) dc->dc_boardrev = rex_revision(dc); - rex_vc1_write(dc, rex_vc1_read(dc) & ~(VC1_SYSCTL_CURSOR | - VC1_SYSCTL_CURSOR_ON)); + rex_vc1_sysctl_write(dc, rex_vc1_sysctl_read(dc) & + ~(VC1_SYSCTL_CURSOR | VC1_SYSCTL_CURSOR_ON)); } void @@ -371,7 +469,6 @@ light_init_screen(struct light_devconfig *dc) memset(ri, 0, sizeof(struct rasops_info)); ri->ri_hw = dc; ri->ri_flg = RI_CENTER | RI_FULLCLEAR; - ri->ri_flg |= RI_FORCEMONO; /* XXX until colormap support... */ /* for the proper operation of rasops computations, pretend 8bpp */ ri->ri_depth = 8; ri->ri_stride = LIGHT_XRES; @@ -395,12 +492,15 @@ light_init_screen(struct light_devconfig *dc) dc->dc_wsd.fontheight = ri->ri_font->fontheight; dc->dc_wsd.capabilities = ri->ri_caps; - rex_fill_rect(dc, 0, 0, LIGHT_XRES - 1, LIGHT_YRES - 1, WSCOL_BLACK); + memcpy(dc->dc_cmap, rasops_cmap, sizeof(dc->dc_cmap)); + light_loadcmap(dc, 0, 1 << ri->ri_depth); + + rex_fill_rect(dc, 0, 0, ri->ri_width, ri->ri_height, WSCOL_BLACK); } -/******************************************************************************* +/* * wsdisplay_emulops - ******************************************************************************/ + */ int light_do_cursor(struct rasops_info *ri) @@ -434,17 +534,17 @@ light_putchar(void *c, int row, int col, u_int ch, long attr) ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul); if ((ch == ' ' || ch == 0) && ul == 0) { - rex_fill_rect(dc, x, y, x + font->fontwidth - 1, - y + font->fontheight - 1, bg); + rex_fill_rect(dc, x, y, x + font->fontwidth, + y + font->fontheight, bg); return 0; } rex_wait(dc); rex_write(dc, REX_PAGE0_SET, REX_P0REG_YSTARTI, y); - rex_write(dc, REX_PAGE0_SET, REX_P0REG_YENDI, y + font->fontheight - 1); + rex_write(dc, REX_PAGE0_SET, REX_P0REG_YENDI, y + font->fontheight); rex_write(dc, REX_PAGE0_SET, REX_P0REG_XSTARTI, x); - rex_write(dc, REX_PAGE0_SET, REX_P0REG_XENDI, x + font->fontwidth - 1); + rex_write(dc, REX_PAGE0_SET, REX_P0REG_XENDI, x + font->fontwidth); rex_write(dc, REX_PAGE0_SET, REX_P0REG_COLORREDI, ri->ri_devcmap[fg] & 0xff); rex_write(dc, REX_PAGE0_SET, REX_P0REG_COLORBACK, @@ -464,21 +564,21 @@ light_putchar(void *c, int row, int col, u_int ch, long attr) if (font->fontwidth <= 8) { for (i = font->fontheight; i != 0; i--) { if (ul && i == 1) - pattern = 0xff000000; + pattern = 0xff; else - pattern = *bitmap << 24; + pattern = *bitmap; rex_write(dc, REX_PAGE0_GO, REX_P0REG_ZPATTERN, - pattern); + pattern << 24); bitmap += font->stride; } } else { for (i = font->fontheight; i != 0; i--) { if (ul && i == 1) - pattern = 0xffff0000; + pattern = 0xffff; else - pattern = *(uint16_t *)bitmap << 16; + pattern = *(uint16_t *)bitmap; rex_write(dc, REX_PAGE0_GO, REX_P0REG_ZPATTERN, - pattern); + pattern << 16); bitmap += font->stride; } } @@ -495,11 +595,11 @@ light_copycols(void *c, int row, int srccol, int dstcol, int ncols) struct wsdisplay_font *font = ri->ri_font; int from_x, to_x, y, width, height; - from_x = ri->ri_xorigin + srccol * font->fontwidth; - to_x = ri->ri_xorigin + dstcol * font->fontwidth; - y = ri->ri_yorigin + row * font->fontheight; - width = ncols * font->fontwidth; - height = font->fontheight; + from_x = ri->ri_xorigin + srccol * font->fontwidth; + to_x = ri->ri_xorigin + dstcol * font->fontwidth; + y = ri->ri_yorigin + row * font->fontheight; + width = ncols * font->fontwidth; + height = font->fontheight; rex_copy_rect(dc, from_x, y, to_x, y, width, height, OPENGL_LOGIC_OP_COPY); @@ -519,10 +619,10 @@ light_erasecols(void *c, int row, int startcol, int ncols, long attr) ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, NULL); - from_x = ri->ri_xorigin + startcol * font->fontwidth; - from_y = ri->ri_yorigin + row * font->fontheight; - to_x = from_x + (ncols * font->fontwidth) - 1; - to_y = from_y + font->fontheight - 1; + from_x = ri->ri_xorigin + startcol * font->fontwidth; + from_y = ri->ri_yorigin + row * font->fontheight; + to_x = from_x + ncols * font->fontwidth; + to_y = from_y + font->fontheight; rex_fill_rect(dc, from_x, from_y, to_x, to_y, bg); @@ -538,11 +638,11 @@ light_copyrows(void *c, int srcrow, int dstrow, int nrows) struct wsdisplay_font *font = ri->ri_font; int x, from_y, to_y, width, height; - x = ri->ri_xorigin; - from_y = ri->ri_yorigin + srcrow * font->fontheight; - to_y = ri->ri_yorigin + dstrow * font->fontheight; - width = ri->ri_emuwidth; - height = nrows * font->fontheight; + x = ri->ri_xorigin; + from_y = ri->ri_yorigin + srcrow * font->fontheight; + to_y = ri->ri_yorigin + dstrow * font->fontheight; + width = ri->ri_emuwidth; + height = nrows * font->fontheight; rex_copy_rect(dc, x, from_y, x, to_y, width, height, OPENGL_LOGIC_OP_COPY); @@ -562,26 +662,29 @@ light_eraserows(void *c, int row, int nrows, long attr) ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, NULL); if (nrows == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) { - rex_fill_rect(dc, 0, 0, LIGHT_XRES - 1, LIGHT_YRES - 1, bg); + rex_fill_rect(dc, 0, 0, ri->ri_width, ri->ri_height, bg); return 0; } rex_fill_rect(dc, ri->ri_xorigin, - ri->ri_yorigin + row * font->fontheight - 1, - ri->ri_xorigin + ri->ri_emuwidth - 1, - ri->ri_yorigin + (row + nrows) * font->fontheight - 1, bg); + ri->ri_yorigin + row * font->fontheight, + ri->ri_xorigin + ri->ri_emuwidth, + ri->ri_yorigin + (row + nrows) * font->fontheight, bg); return 0; } -/******************************************************************************* +/* * wsdisplay_accessops - ******************************************************************************/ + */ int light_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) { + struct light_devconfig *dc = v; struct wsdisplay_fbinfo *fb; + struct wsdisplay_cmap *cm; + int rc; switch (cmd) { case WSDISPLAYIO_GTYPE: @@ -589,10 +692,23 @@ light_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) break; case WSDISPLAYIO_GINFO: fb = (struct wsdisplay_fbinfo *)data; - fb->width = LIGHT_XRES; - fb->height = LIGHT_YRES; - fb->depth = LIGHT_DEPTH; - fb->cmsize = 1 << LIGHT_DEPTH; + fb->width = dc->dc_ri.ri_width; + fb->height = dc->dc_ri.ri_height; + fb->depth = dc->dc_ri.ri_depth; + fb->cmsize = 1 << fb->depth; + break; + case WSDISPLAYIO_GETCMAP: + cm = (struct wsdisplay_cmap *)data; + rc = light_getcmap(dc, cm); + if (rc != 0) + return rc; + break; + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + rc = light_putcmap(dc, cm); + if (rc != 0) + return rc; + light_loadcmap(dc, cm->index, cm->count); break; default: return -1; diff --git a/sys/arch/sgi/gio/lightreg.h b/sys/arch/sgi/gio/lightreg.h index d6926717a1e..17576b62a67 100644 --- a/sys/arch/sgi/gio/lightreg.h +++ b/sys/arch/sgi/gio/lightreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lightreg.h,v 1.1 2012/04/17 15:36:55 miod Exp $ */ +/* $OpenBSD: lightreg.h,v 1.2 2014/03/18 23:23:09 miod Exp $ */ /* $NetBSD: lightreg.h,v 1.3 2006/12/29 00:31:48 rumble Exp $ */ /* @@ -49,6 +49,7 @@ /* configuration register offsets (from REX_PAGE1_{SET,GO}) */ #define REX_P1REG_WCLOCKREV 0x00000054 /* nsclock / revision */ +#define REX_P1REG_DAC_ADDRDATA 0x00000058 /* DAC r/w addr and data 8bit */ #define REX_P1REG_CFGSEL 0x0000005c /* function selector */ #define REX_P1REG_VC1_ADDRDATA 0x00000060 /* vc1 r/w addr and data 8bit */ #define REX_P1REG_CFGMODE 0x00000068 /* REX system config */ @@ -80,6 +81,14 @@ #define REX_CFGSEL_VC1_LADDR 0x00000004 /* low address bits */ #define REX_CFGSEL_VC1_HADDR 0x00000005 /* high address bits */ #define REX_CFGSEL_VC1_SYSCTL 0x00000006 +#define REX_CFGSEL_DAC_WADDR 0x00000000 /* write address */ +#define REX_CFGSEL_DAC_CMAP 0x00000001 /* colormap data */ +#define REX_CFGSEL_DAC_PMASK 0x00000002 /* pixel read mask */ +#define REX_CFGSEL_DAC_RADDR 0x00000003 /* read address */ +#define REX_CFGSEL_DAC_OVWADDR 0x00000004 /* overlay write address */ +#define REX_CFGSEL_DAC_OV 0x00000005 /* overlay registers */ +#define REX_CFGSEL_DAC_CTL 0x00000006 /* control registers */ +#define REX_CFGSEL_DAC_OVRADDR 0x00000007 /* overlay read address */ /* vc1 sysctl bits (byte) */ #define VC1_SYSCTL_VIDEO_ON 0x04 |