/* $OpenBSD: omrasops.c,v 1.16 2020/05/25 09:55:48 jsg Exp $ */ /* $NetBSD: omrasops.c,v 1.1 2000/01/05 08:48:56 nisimura Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Tohru Nishimura. * * 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. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``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 THE FOUNDATION OR CONTRIBUTORS * 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. */ /* * Designed specifically for 'm68k bitorder'; * - most significant byte is stored at lower address, * - most significant bit is displayed at left most on screen. * Implementation relies on; * - every memory reference is done in aligned 32bit chunks, * - font glyphs are stored in 32bit padded. */ #include #include #include #include #include #include #include #include #define OMFB_PLANEMASK BMAP_BMSEL /* planemask register */ #define OMFB_ROPFUNC BMAP_FN /* ROP function code */ /* wscons emulator operations */ int om_copycols(void *, int, int, int, int); int om_copyrows(void *, int, int, int num); int om_erasecols(void *, int, int, int, uint32_t); int om_eraserows(void *, int, int, uint32_t); int om1_cursor(void *, int, int, int); int om1_putchar(void *, int, int, u_int, uint32_t); int om4_cursor(void *, int, int, int); int om4_putchar(void *, int, int, u_int, uint32_t); /* depth-depended setup functions */ void setup_omrasops1(struct rasops_info *); void setup_omrasops4(struct rasops_info *); /* internal functions for 1bpp/4bpp */ int om1_windowmove(struct rasops_info *, u_int16_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t, int16_t, int16_t); int om4_windowmove(struct rasops_info *, u_int16_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t, int16_t, int16_t); /* MI function in src/sys/dev/rasops/rasops.c */ int rasops_pack_cattr(void *, int, int, int, uint32_t *); static int (*om_windowmove)(struct rasops_info *, u_int16_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t, u_int16_t, int16_t, int16_t); extern struct wsscreen_descr omfb_stdscreen; #define ALL1BITS (~0U) #define ALL0BITS (0U) #define BLITWIDTH (32) #define ALIGNMASK (0x1f) #define BYTESDONE (4) /* * Blit a character at the specified co-ordinates. * - 1bpp version - */ int om1_putchar(void *cookie, int row, int startcol, u_int uc, uint32_t attr) { struct rasops_info *ri = cookie; u_int8_t *p; int scanspan, startx, height, width, align, y; u_int32_t lmask, rmask, glyph, inverse; int i, fg, bg; u_int8_t *fb; scanspan = ri->ri_stride; y = ri->ri_font->fontheight * row; startx = ri->ri_font->fontwidth * startcol; height = ri->ri_font->fontheight; fb = (u_int8_t *)ri->ri_font->data + (uc - ri->ri_font->firstchar) * ri->ri_fontscale; ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); inverse = (bg != 0) ? ALL1BITS : ALL0BITS; p = (u_int8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4); align = startx & ALIGNMASK; width = ri->ri_font->fontwidth + align; lmask = ALL1BITS >> align; rmask = ALL1BITS << (-width & ALIGNMASK); if (width <= BLITWIDTH) { lmask &= rmask; while (height > 0) { glyph = 0; for (i = ri->ri_font->stride; i != 0; i--) glyph = (glyph << 8) | *fb++; glyph <<= (4 - ri->ri_font->stride) * NBBY; glyph = (glyph >> align) ^ inverse; *W(p) = (*R(p) & ~lmask) | (glyph & lmask); p += scanspan; height--; } } else { u_int8_t *q = p; u_int32_t lhalf, rhalf; while (height > 0) { glyph = 0; for (i = ri->ri_font->stride; i != 0; i--) glyph = (glyph << 8) | *fb++; glyph <<= (4 - ri->ri_font->stride) * NBBY; lhalf = (glyph >> align) ^ inverse; *W(p) = (*R(p) & ~lmask) | (lhalf & lmask); p += BYTESDONE; rhalf = (glyph << (BLITWIDTH - align)) ^ inverse; *W(p) = (rhalf & rmask) | (*R(p) & ~rmask); p = (q += scanspan); height--; } } return 0; } /* * Blit a character at the specified co-ordinates * - 4bpp version - */ int om4_putchar(void *cookie, int row, int startcol, u_int uc, uint32_t attr) { struct rasops_info *ri = cookie; u_int8_t *p; int scanspan, startx, height, width, align, y; u_int32_t lmask, rmask, glyph, glyphbg, fgpat, bgpat; u_int32_t fgmask0, fgmask1, fgmask2, fgmask3; u_int32_t bgmask0, bgmask1, bgmask2, bgmask3; int i, fg, bg; u_int8_t *fb; scanspan = ri->ri_stride; y = ri->ri_font->fontheight * row; startx = ri->ri_font->fontwidth * startcol; height = ri->ri_font->fontheight; fb = (u_int8_t *)ri->ri_font->data + (uc - ri->ri_font->firstchar) * ri->ri_fontscale; ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); fgmask0 = (fg & 0x01) ? ALL1BITS : ALL0BITS; fgmask1 = (fg & 0x02) ? ALL1BITS : ALL0BITS; fgmask2 = (fg & 0x04) ? ALL1BITS : ALL0BITS; fgmask3 = (fg & 0x08) ? ALL1BITS : ALL0BITS; bgmask0 = (bg & 0x01) ? ALL1BITS : ALL0BITS; bgmask1 = (bg & 0x02) ? ALL1BITS : ALL0BITS; bgmask2 = (bg & 0x04) ? ALL1BITS : ALL0BITS; bgmask3 = (bg & 0x08) ? ALL1BITS : ALL0BITS; p = (u_int8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4); align = startx & ALIGNMASK; width = ri->ri_font->fontwidth + align; lmask = ALL1BITS >> align; rmask = ALL1BITS << (-width & ALIGNMASK); /* select all planes for later ROP function target */ *(volatile u_int32_t *)OMFB_PLANEMASK = 0xff; if (width <= BLITWIDTH) { lmask &= rmask; /* set lmask as ROP mask value, with THROUGH mode */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_THROUGH] = lmask; while (height > 0) { glyph = 0; for (i = ri->ri_font->stride; i != 0; i--) glyph = (glyph << 8) | *fb++; glyph <<= (4 - ri->ri_font->stride) * NBBY; glyph = (glyph >> align); glyphbg = glyph ^ ALL1BITS; fgpat = glyph & fgmask0; bgpat = glyphbg & bgmask0; *P0(p) = (fgpat | bgpat); fgpat = glyph & fgmask1; bgpat = glyphbg & bgmask1; *P1(p) = (fgpat | bgpat); fgpat = glyph & fgmask2; bgpat = glyphbg & bgmask2; *P2(p) = (fgpat | bgpat); fgpat = glyph & fgmask3; bgpat = glyphbg & bgmask3; *P3(p) = (fgpat | bgpat); p += scanspan; height--; } /* reset mask value */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_THROUGH] = ALL1BITS; } else { u_int8_t *q = p; u_int32_t lhalf, rhalf; u_int32_t lhalfbg, rhalfbg; while (height > 0) { glyph = 0; for (i = ri->ri_font->stride; i != 0; i--) glyph = (glyph << 8) | *fb++; glyph <<= (4 - ri->ri_font->stride) * NBBY; lhalf = (glyph >> align); lhalfbg = lhalf ^ ALL1BITS; /* set lmask as ROP mask value, with THROUGH mode */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_THROUGH] = lmask; fgpat = lhalf & fgmask0; bgpat = lhalfbg & bgmask0; *P0(p) = (fgpat | bgpat); fgpat = lhalf & fgmask1; bgpat = lhalfbg & bgmask1; *P1(p) = (fgpat | bgpat); fgpat = lhalf & fgmask2; bgpat = lhalfbg & bgmask2; *P2(p) = (fgpat | bgpat); fgpat = lhalf & fgmask3; bgpat = lhalfbg & bgmask3; *P3(p) = (fgpat | bgpat); p += BYTESDONE; rhalf = (glyph << (BLITWIDTH - align)); rhalfbg = rhalf ^ ALL1BITS; /* set rmask as ROP mask value, with THROUGH mode */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_THROUGH] = rmask; fgpat = rhalf & fgmask0; bgpat = rhalfbg & bgmask0; *P0(p) = (fgpat | bgpat); fgpat = rhalf & fgmask1; bgpat = rhalfbg & bgmask1; *P1(p) = (fgpat | bgpat); fgpat = rhalf & fgmask2; bgpat = rhalfbg & bgmask2; *P2(p) = (fgpat | bgpat); fgpat = rhalf & fgmask3; bgpat = rhalfbg & bgmask3; *P3(p) = (fgpat | bgpat); p = (q += scanspan); height--; } /* reset mask value */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_THROUGH] = ALL1BITS; } /* select plane #0 only; XXX need this ? */ *(volatile u_int32_t *)OMFB_PLANEMASK = 0x01; return 0; } int om_erasecols(void *cookie, int row, int col, int num, uint32_t attr) { struct rasops_info *ri = cookie; int fg, bg; int snum, scol, srow; ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); snum = num * ri->ri_font->fontwidth; scol = col * ri->ri_font->fontwidth + ri->ri_xorigin; srow = row * ri->ri_font->fontheight + ri->ri_yorigin; /* * If this is too tricky for the simple raster ops engine, * pass the fun to rasops. */ if ((*om_windowmove)(ri, scol, srow, scol, srow, snum, ri->ri_font->fontheight, RR_CLEAR, 0xff ^ bg) != 0) rasops_erasecols(cookie, row, col, num, attr); return 0; } int om_eraserows(void *cookie, int row, int num, uint32_t attr) { struct rasops_info *ri = cookie; int fg, bg; int srow, snum; int rc; ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); bg ^= 0xff; if (num == ri->ri_rows && (ri->ri_flg & RI_FULLCLEAR)) { rc = (*om_windowmove)(ri, 0, 0, 0, 0, ri->ri_width, ri->ri_height, RR_CLEAR, bg); } else { srow = row * ri->ri_font->fontheight + ri->ri_yorigin; snum = num * ri->ri_font->fontheight; rc = (*om_windowmove)(ri, ri->ri_xorigin, srow, ri->ri_xorigin, srow, ri->ri_emuwidth, snum, RR_CLEAR, bg); } if (rc != 0) rasops_eraserows(cookie, row, num, attr); return 0; } int om_copyrows(void *cookie, int src, int dst, int n) { struct rasops_info *ri = cookie; n *= ri->ri_font->fontheight; src *= ri->ri_font->fontheight; dst *= ri->ri_font->fontheight; (*om_windowmove)(ri, ri->ri_xorigin, ri->ri_yorigin + src, ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, n, RR_COPY, 0xff); return 0; } int om_copycols(void *cookie, int row, int src, int dst, int n) { struct rasops_info *ri = cookie; n *= ri->ri_font->fontwidth; src *= ri->ri_font->fontwidth; dst *= ri->ri_font->fontwidth; row *= ri->ri_font->fontheight; (*om_windowmove)(ri, ri->ri_xorigin + src, ri->ri_yorigin + row, ri->ri_xorigin + dst, ri->ri_yorigin + row, n, ri->ri_font->fontheight, RR_COPY, 0xff); return 0; } /* * Position|{enable|disable} the cursor at the specified location. * - 1bpp version - */ int om1_cursor(void *cookie, int on, int row, int col) { struct rasops_info *ri = cookie; u_int8_t *p; int scanspan, startx, height, width, align, y; u_int32_t lmask, rmask, image; if (!on) { /* make sure it's on */ if ((ri->ri_flg & RI_CURSOR) == 0) return 0; row = ri->ri_crow; col = ri->ri_ccol; } else { /* unpaint the old copy. */ ri->ri_crow = row; ri->ri_ccol = col; } scanspan = ri->ri_stride; y = ri->ri_font->fontheight * row; startx = ri->ri_font->fontwidth * col; height = ri->ri_font->fontheight; p = (u_int8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4); align = startx & ALIGNMASK; width = ri->ri_font->fontwidth + align; lmask = ALL1BITS >> align; rmask = ALL1BITS << (-width & ALIGNMASK); if (width <= BLITWIDTH) { lmask &= rmask; while (height > 0) { image = *R(p); *W(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask); p += scanspan; height--; } } else { u_int8_t *q = p; while (height > 0) { image = *R(p); *W(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask); p += BYTESDONE; image = *R(p); *W(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask); p = (q += scanspan); height--; } } ri->ri_flg ^= RI_CURSOR; return 0; } /* * Position|{enable|disable} the cursor at the specified location * - 4bpp version - */ int om4_cursor(void *cookie, int on, int row, int col) { struct rasops_info *ri = cookie; u_int8_t *p; int scanspan, startx, height, width, align, y; u_int32_t lmask, rmask; if (!on) { /* make sure it's on */ if ((ri->ri_flg & RI_CURSOR) == 0) return 0; row = ri->ri_crow; col = ri->ri_ccol; } else { /* unpaint the old copy. */ ri->ri_crow = row; ri->ri_ccol = col; } scanspan = ri->ri_stride; y = ri->ri_font->fontheight * row; startx = ri->ri_font->fontwidth * col; height = ri->ri_font->fontheight; p = (u_int8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4); align = startx & ALIGNMASK; width = ri->ri_font->fontwidth + align; lmask = ALL1BITS >> align; rmask = ALL1BITS << (-width & ALIGNMASK); /* select all planes for later ROP function target */ *(volatile u_int32_t *)OMFB_PLANEMASK = 0xff; if (width <= BLITWIDTH) { lmask &= rmask; /* set lmask as ROP mask value, with INV2 mode */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_INV2] = lmask; while (height > 0) { *W(p) = ALL1BITS; p += scanspan; height--; } /* reset mask value */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_THROUGH] = ALL1BITS; } else { u_int8_t *q = p; while (height > 0) { /* set lmask as ROP mask value, with INV2 mode */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_INV2] = lmask; *W(p) = ALL1BITS; p += BYTESDONE; /* set rmask as ROP mask value, with INV2 mode */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_INV2] = rmask; *W(p) = ALL1BITS; p = (q += scanspan); height--; } /* reset mask value */ ((volatile u_int32_t *)OMFB_ROPFUNC)[ROP_THROUGH] = ALL1BITS; } /* select plane #0 only; XXX need this ? */ *(volatile u_int32_t *)OMFB_PLANEMASK = 0x01; ri->ri_flg ^= RI_CURSOR; return 0; } /* * After calling rasops_init(), set up our depth-depend emulops, * block move function and capabilities. */ void setup_omrasops1(struct rasops_info *ri) { om_windowmove = om1_windowmove; ri->ri_ops.cursor = om1_cursor; ri->ri_ops.putchar = om1_putchar; omfb_stdscreen.capabilities = ri->ri_caps & ~WSSCREEN_UNDERLINE; } void setup_omrasops4(struct rasops_info *ri) { om_windowmove = om4_windowmove; ri->ri_ops.cursor = om4_cursor; ri->ri_ops.putchar = om4_putchar; omfb_stdscreen.capabilities = WSSCREEN_HILIT | WSSCREEN_WSCOLORS | WSSCREEN_REVERSE; /* * Since we set ri->ri_depth == 1, rasops_init() set * rasops_pack_mattr for us. But we use the color version, * rasops_pack_cattr, on 4bpp/8bpp frame buffer. */ ri->ri_ops.pack_attr = rasops_pack_cattr; }