1 /* $NetBSD: omrasops.c,v 1.13 2012/07/20 19:31:53 tsutsui Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Tohru Nishimura. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 33 34 __KERNEL_RCSID(0, "$NetBSD: omrasops.c,v 1.13 2012/07/20 19:31:53 tsutsui Exp $"); 35 36 /* 37 * Designed speficically for 'm68k bitorder'; 38 * - most significant byte is stored at lower address, 39 * - most significant bit is displayed at left most on screen. 40 * Implementation relies on; 41 * - every memory references is done in aligned 32bit chunk, 42 * - font glyphs are stored in 32bit padded. 43 */ 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/device.h> 48 49 #include <dev/wscons/wsconsio.h> 50 #include <dev/wscons/wsdisplayvar.h> 51 #include <dev/rasops/rasops.h> 52 53 #include <arch/luna68k/dev/omrasopsvar.h> 54 55 /* wscons emulator operations */ 56 static void om_cursor(void *, int, int, int); 57 static int om_mapchar(void *, int, unsigned int *); 58 static void om_putchar(void *, int, int, u_int, long); 59 static void om_copycols(void *, int, int, int, int); 60 static void om_copyrows(void *, int, int, int num); 61 static void om_erasecols(void *, int, int, int, long); 62 static void om_eraserows(void *, int, int, long); 63 static int om_allocattr(void *, int, int, int, long *); 64 65 #define ALL1BITS (~0U) 66 #define ALL0BITS (0U) 67 #define BLITWIDTH (32) 68 #define ALIGNMASK (0x1f) 69 #define BYTESDONE (4) 70 71 #define W(p) (*(uint32_t *)(p)) 72 #define R(p) (*(uint32_t *)((uint8_t *)(p) + 0x40000)) 73 74 /* 75 * Blit a character at the specified co-ordinates. 76 */ 77 static void 78 om_putchar(void *cookie, int row, int startcol, u_int uc, long attr) 79 { 80 struct rasops_info *ri = cookie; 81 uint8_t *p; 82 int scanspan, startx, height, width, align, y; 83 uint32_t lmask, rmask, glyph, inverse; 84 int i; 85 uint8_t *fb; 86 87 scanspan = ri->ri_stride; 88 y = ri->ri_font->fontheight * row; 89 startx = ri->ri_font->fontwidth * startcol; 90 height = ri->ri_font->fontheight; 91 fb = (uint8_t *)ri->ri_font->data + 92 (uc - ri->ri_font->firstchar) * ri->ri_fontscale; 93 inverse = (attr != 0) ? ALL1BITS : ALL0BITS; 94 95 p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4); 96 align = startx & ALIGNMASK; 97 width = ri->ri_font->fontwidth + align; 98 lmask = ALL1BITS >> align; 99 rmask = ALL1BITS << (-width & ALIGNMASK); 100 if (width <= BLITWIDTH) { 101 lmask &= rmask; 102 while (height > 0) { 103 glyph = 0; 104 for (i = ri->ri_font->stride; i != 0; i--) 105 glyph = (glyph << 8) | *fb++; 106 glyph <<= (4 - ri->ri_font->stride) * NBBY; 107 glyph = (glyph >> align) ^ inverse; 108 W(p) = (R(p) & ~lmask) | (glyph & lmask); 109 p += scanspan; 110 height--; 111 } 112 } else { 113 uint8_t *q = p; 114 uint32_t lhalf, rhalf; 115 116 while (height > 0) { 117 glyph = 0; 118 for (i = ri->ri_font->stride; i != 0; i--) 119 glyph = (glyph << 8) | *fb++; 120 glyph <<= (4 - ri->ri_font->stride) * NBBY; 121 lhalf = (glyph >> align) ^ inverse; 122 W(p) = (R(p) & ~lmask) | (lhalf & lmask); 123 p += BYTESDONE; 124 rhalf = (glyph << (BLITWIDTH - align)) ^ inverse; 125 W(p) = (rhalf & rmask) | (R(p) & ~rmask); 126 127 p = (q += scanspan); 128 height--; 129 } 130 } 131 } 132 133 static void 134 om_erasecols(void *cookie, int row, int startcol, int ncols, long attr) 135 { 136 struct rasops_info *ri = cookie; 137 uint8_t *p; 138 int scanspan, startx, height, width, align, w, y; 139 uint32_t lmask, rmask, fill; 140 141 scanspan = ri->ri_stride;; 142 fill = (attr != 0) ? ALL1BITS : ALL0BITS; 143 y = ri->ri_font->fontheight * row; 144 startx = ri->ri_font->fontwidth * startcol; 145 height = ri->ri_font->fontheight; 146 w = ri->ri_font->fontwidth * ncols; 147 fill = (attr != 0) ? ALL1BITS : ALL0BITS; 148 149 p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4); 150 align = startx & ALIGNMASK; 151 width = w + align; 152 lmask = ALL1BITS >> align; 153 rmask = ALL1BITS << (-width & ALIGNMASK); 154 if (width <= BLITWIDTH) { 155 lmask &= rmask; 156 fill &= lmask; 157 while (height > 0) { 158 W(p) = (R(p) & ~lmask) | fill; 159 p += scanspan; 160 height--; 161 } 162 } else { 163 uint8_t *q = p; 164 while (height > 0) { 165 W(p) = (R(p) & ~lmask) | (fill & lmask); 166 width -= 2 * BLITWIDTH; 167 while (width > 0) { 168 p += BYTESDONE; 169 W(p) = fill; 170 width -= BLITWIDTH; 171 } 172 p += BYTESDONE; 173 W(p) = (fill & rmask) | (R(p) & ~rmask); 174 175 p = (q += scanspan); 176 width = w + align; 177 height--; 178 } 179 } 180 } 181 182 static void 183 om_eraserows(void *cookie, int startrow, int nrows, long attr) 184 { 185 struct rasops_info *ri = cookie; 186 uint8_t *p, *q; 187 int scanspan, starty, height, width, w; 188 uint32_t rmask, fill; 189 190 scanspan = ri->ri_stride; 191 starty = ri->ri_font->fontheight * startrow; 192 height = ri->ri_font->fontheight * nrows; 193 w = ri->ri_emuwidth; 194 fill = (attr != 0) ? ALL1BITS : ALL0BITS; 195 196 p = (uint8_t *)ri->ri_bits + starty * scanspan; 197 width = w; 198 rmask = ALL1BITS << (-width & ALIGNMASK); 199 q = p; 200 while (height > 0) { 201 W(p) = fill; /* always aligned */ 202 width -= 2 * BLITWIDTH; 203 while (width > 0) { 204 p += BYTESDONE; 205 W(p) = fill; 206 width -= BLITWIDTH; 207 } 208 p += BYTESDONE; 209 W(p) = (fill & rmask) | (R(p) & ~rmask); 210 p = (q += scanspan); 211 width = w; 212 height--; 213 } 214 } 215 216 static void 217 om_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 218 { 219 struct rasops_info *ri = cookie; 220 uint8_t *p, *q; 221 int scanspan, offset, srcy, height, width, w; 222 uint32_t rmask; 223 224 scanspan = ri->ri_stride; 225 height = ri->ri_font->fontheight * nrows; 226 offset = (dstrow - srcrow) * scanspan * ri->ri_font->fontheight; 227 srcy = ri->ri_font->fontheight * srcrow; 228 if (srcrow < dstrow && srcrow + nrows > dstrow) { 229 scanspan = -scanspan; 230 srcy += height; 231 } 232 233 p = (uint8_t *)ri->ri_bits + srcy * ri->ri_stride; 234 w = ri->ri_emuwidth; 235 width = w; 236 rmask = ALL1BITS << (-width & ALIGNMASK); 237 q = p; 238 while (height > 0) { 239 W(p + offset) = R(p); /* always aligned */ 240 width -= 2 * BLITWIDTH; 241 while (width > 0) { 242 p += BYTESDONE; 243 W(p + offset) = R(p); 244 width -= BLITWIDTH; 245 } 246 p += BYTESDONE; 247 W(p + offset) = (R(p) & rmask) | (R(p + offset) & ~rmask); 248 249 p = (q += scanspan); 250 width = w; 251 height--; 252 } 253 } 254 255 static void 256 om_copycols(void *cookie, int startrow, int srccol, int dstcol, int ncols) 257 { 258 struct rasops_info *ri = cookie; 259 uint8_t *sp, *dp, *basep; 260 int scanspan, height, width, align, shift, w, y, srcx, dstx; 261 uint32_t lmask, rmask; 262 263 scanspan = ri->ri_stride; 264 y = ri->ri_font->fontheight * startrow; 265 srcx = ri->ri_font->fontwidth * srccol; 266 dstx = ri->ri_font->fontwidth * dstcol; 267 height = ri->ri_font->fontheight; 268 w = ri->ri_font->fontwidth * ncols; 269 basep = (uint8_t *)ri->ri_bits + y * scanspan; 270 271 align = shift = srcx & ALIGNMASK; 272 width = w + align; 273 align = dstx & ALIGNMASK; 274 lmask = ALL1BITS >> align; 275 rmask = ALL1BITS << (-(w + align) & ALIGNMASK); 276 shift = align - shift; 277 sp = basep + (srcx / 32) * 4; 278 dp = basep + (dstx / 32) * 4; 279 280 if (shift != 0) 281 goto hardluckalignment; 282 283 /* alignments comfortably match */ 284 if (width <= BLITWIDTH) { 285 lmask &= rmask; 286 while (height > 0) { 287 W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask); 288 dp += scanspan; 289 sp += scanspan; 290 height--; 291 } 292 } 293 /* copy forward (left-to-right) */ 294 else if (dstcol < srccol || srccol + ncols < dstcol) { 295 uint8_t *sq = sp, *dq = dp; 296 297 w = width; 298 while (height > 0) { 299 W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask); 300 width -= 2 * BLITWIDTH; 301 while (width > 0) { 302 sp += BYTESDONE; 303 dp += BYTESDONE; 304 W(dp) = R(sp); 305 width -= BLITWIDTH; 306 } 307 sp += BYTESDONE; 308 dp += BYTESDONE; 309 W(dp) = (R(sp) & rmask) | (R(dp) & ~rmask); 310 sp = (sq += scanspan); 311 dp = (dq += scanspan); 312 width = w; 313 height--; 314 } 315 } 316 /* copy backward (right-to-left) */ 317 else { 318 uint8_t *sq, *dq; 319 320 sq = (sp += width / 32 * 4); 321 dq = (dp += width / 32 * 4); 322 w = width; 323 while (height > 0) { 324 W(dp) = (R(sp) & rmask) | (R(dp) & ~rmask); 325 width -= 2 * BLITWIDTH; 326 while (width > 0) { 327 sp -= BYTESDONE; 328 dp -= BYTESDONE; 329 W(dp) = R(sp); 330 width -= BLITWIDTH; 331 } 332 sp -= BYTESDONE; 333 dp -= BYTESDONE; 334 W(dp) = (R(dp) & ~lmask) | (R(sp) & lmask); 335 336 sp = (sq += scanspan); 337 dp = (dq += scanspan); 338 width = w; 339 height--; 340 } 341 } 342 return; 343 344 hardluckalignment: 345 /* alignments painfully disagree */ 346 return; 347 } 348 349 /* 350 * Map a character. 351 */ 352 static int 353 om_mapchar(void *cookie, int c, u_int *cp) 354 { 355 struct rasops_info *ri = cookie; 356 struct wsdisplay_font *wf = ri->ri_font; 357 358 if (wf->encoding != WSDISPLAY_FONTENC_ISO) { 359 c = wsfont_map_unichar(wf, c); 360 361 if (c < 0) 362 goto fail; 363 } 364 if (c < wf->firstchar || c >= (wf->firstchar + wf->numchars)) 365 goto fail; 366 367 *cp = c; 368 return 5; 369 370 fail: 371 *cp = ' '; 372 return 0; 373 } 374 375 /* 376 * Position|{enable|disable} the cursor at the specified location. 377 */ 378 static void 379 om_cursor(void *cookie, int on, int row, int col) 380 { 381 struct rasops_info *ri = cookie; 382 uint8_t *p; 383 int scanspan, startx, height, width, align, y; 384 uint32_t lmask, rmask, image; 385 386 if (!on) { 387 /* make sure it's on */ 388 if ((ri->ri_flg & RI_CURSOR) == 0) 389 return; 390 391 row = ri->ri_crow; 392 col = ri->ri_ccol; 393 } else { 394 /* unpaint the old copy. */ 395 ri->ri_crow = row; 396 ri->ri_ccol = col; 397 } 398 399 scanspan = ri->ri_stride; 400 y = ri->ri_font->fontheight * row; 401 startx = ri->ri_font->fontwidth * col; 402 height = ri->ri_font->fontheight; 403 404 p = (uint8_t *)ri->ri_bits + y * scanspan + ((startx / 32) * 4); 405 align = startx & ALIGNMASK; 406 width = ri->ri_font->fontwidth + align; 407 lmask = ALL1BITS >> align; 408 rmask = ALL1BITS << (-width & ALIGNMASK); 409 if (width <= BLITWIDTH) { 410 lmask &= rmask; 411 while (height > 0) { 412 image = R(p); 413 W(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask); 414 p += scanspan; 415 height--; 416 } 417 } else { 418 uint8_t *q = p; 419 420 while (height > 0) { 421 image = R(p); 422 W(p) = (image & ~lmask) | ((image ^ ALL1BITS) & lmask); 423 p += BYTESDONE; 424 image = R(p); 425 W(p) = ((image ^ ALL1BITS) & rmask) | (image & ~rmask); 426 427 p = (q += scanspan); 428 height--; 429 } 430 } 431 ri->ri_flg ^= RI_CURSOR; 432 } 433 434 /* 435 * Allocate attribute. We just pack these into an integer. 436 */ 437 static int 438 om_allocattr(void *id, int fg, int bg, int flags, long *attrp) 439 { 440 441 if (flags & (WSATTR_HILIT | WSATTR_BLINK | 442 WSATTR_UNDERLINE | WSATTR_WSCOLORS)) 443 return EINVAL; 444 if (flags & WSATTR_REVERSE) 445 *attrp = 1; 446 else 447 *attrp = 0; 448 return 0; 449 } 450 451 /* 452 * Init subset of rasops(9) for omrasops. 453 */ 454 int 455 omrasops_init(struct rasops_info *ri, int wantrows, int wantcols) 456 { 457 int wsfcookie, bpp; 458 459 if (wantrows == 0) 460 wantrows = 34; 461 if (wantrows < 10) 462 wantrows = 10; 463 if (wantcols == 0) 464 wantcols = 80; 465 if (wantcols < 20) 466 wantcols = 20; 467 468 /* Use default font */ 469 wsfont_init(); 470 wsfcookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 471 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 472 if (wsfcookie < 0) 473 panic("%s: no font available", __func__); 474 if (wsfont_lock(wsfcookie, &ri->ri_font)) 475 panic("%s: unable to lock font", __func__); 476 ri->ri_wsfcookie = wsfcookie; 477 478 KASSERT(ri->ri_font->fontwidth > 4 && ri->ri_font->fontwidth <= 32); 479 480 bpp = ri->ri_depth; 481 482 /* Now constrain what they get */ 483 ri->ri_emuwidth = ri->ri_font->fontwidth * wantcols; 484 ri->ri_emuheight = ri->ri_font->fontheight * wantrows; 485 if (ri->ri_emuwidth > ri->ri_width) 486 ri->ri_emuwidth = ri->ri_width; 487 if (ri->ri_emuheight > ri->ri_height) 488 ri->ri_emuheight = ri->ri_height; 489 490 /* Reduce width until aligned on a 32-bit boundary */ 491 while ((ri->ri_emuwidth * bpp & 31) != 0) 492 ri->ri_emuwidth--; 493 494 ri->ri_cols = ri->ri_emuwidth / ri->ri_font->fontwidth; 495 ri->ri_rows = ri->ri_emuheight / ri->ri_font->fontheight; 496 ri->ri_emustride = ri->ri_emuwidth * bpp >> 3; 497 ri->ri_delta = ri->ri_stride - ri->ri_emustride; 498 ri->ri_ccol = 0; 499 ri->ri_crow = 0; 500 ri->ri_pelbytes = bpp >> 3; 501 502 ri->ri_xscale = (ri->ri_font->fontwidth * bpp) >> 3; 503 ri->ri_yscale = ri->ri_font->fontheight * ri->ri_stride; 504 ri->ri_fontscale = ri->ri_font->fontheight * ri->ri_font->stride; 505 506 /* Clear the entire display */ 507 if ((ri->ri_flg & RI_CLEAR) != 0) 508 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 509 510 /* Now centre our window if needs be */ 511 ri->ri_origbits = ri->ri_bits; 512 513 if ((ri->ri_flg & RI_CENTER) != 0) { 514 ri->ri_bits += (((ri->ri_width * bpp >> 3) - 515 ri->ri_emustride) >> 1) & ~3; 516 ri->ri_bits += ((ri->ri_height - ri->ri_emuheight) >> 1) * 517 ri->ri_stride; 518 ri->ri_yorigin = (int)(ri->ri_bits - ri->ri_origbits) 519 / ri->ri_stride; 520 ri->ri_xorigin = (((int)(ri->ri_bits - ri->ri_origbits) 521 % ri->ri_stride) * 8 / bpp); 522 } else 523 ri->ri_xorigin = ri->ri_yorigin = 0; 524 525 /* fill our own emulops */ 526 ri->ri_ops.cursor = om_cursor; 527 ri->ri_ops.mapchar = om_mapchar; 528 ri->ri_ops.putchar = om_putchar; 529 ri->ri_ops.copycols = om_copycols; 530 ri->ri_ops.erasecols = om_erasecols; 531 ri->ri_ops.copyrows = om_copyrows; 532 ri->ri_ops.eraserows = om_eraserows; 533 ri->ri_ops.allocattr = om_allocattr; 534 ri->ri_caps = WSSCREEN_REVERSE; 535 536 ri->ri_flg |= RI_CFGDONE; 537 538 return 0; 539 } 540