1 /* $NetBSD: bicons.c,v 1.13 2007/12/25 18:33:37 perry Exp $ */ 2 3 /*- 4 * Copyright (c) 1999-2001 5 * Shin Takemura and PocketBSD Project. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the PocketBSD project 18 * and its contributors. 19 * 4. Neither the name of the project nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: bicons.c,v 1.13 2007/12/25 18:33:37 perry Exp $"); 39 40 #define HALF_FONT 41 42 #include <sys/param.h> 43 #include <sys/device.h> 44 #include <sys/systm.h> 45 #include <sys/conf.h> 46 #include <dev/cons.h> 47 48 #include <machine/bootinfo.h> 49 #include <sys/bus.h> 50 #include <machine/platid.h> 51 #include <machine/stdarg.h> 52 53 #include <dev/hpc/biconsvar.h> 54 #include <dev/hpc/bicons.h> 55 extern u_int8_t font_clR8x8_data[]; 56 #define FONT_HEIGHT 8 57 #define FONT_WIDTH 1 58 59 static void put_oxel_D2_M2L_3(u_int8_t *, u_int8_t, u_int8_t); 60 static void put_oxel_D2_M2L_3x2(u_int8_t *, u_int8_t, u_int8_t); 61 static void put_oxel_D2_M2L_0(u_int8_t *, u_int8_t, u_int8_t); 62 static void put_oxel_D2_M2L_0x2(u_int8_t *, u_int8_t, u_int8_t); 63 static void put_oxel_D4_M2L_F(u_int8_t *, u_int8_t, u_int8_t); 64 static void put_oxel_D4_M2L_Fx2(u_int8_t *, u_int8_t, u_int8_t); 65 static void put_oxel_D4_M2L_0(u_int8_t *, u_int8_t, u_int8_t); 66 static void put_oxel_D4_M2L_0x2(u_int8_t *, u_int8_t, u_int8_t); 67 static void put_oxel_D8_00(u_int8_t *, u_int8_t, u_int8_t); 68 static void put_oxel_D8_FF(u_int8_t *, u_int8_t, u_int8_t); 69 static void put_oxel_D16_0000(u_int8_t *, u_int8_t, u_int8_t); 70 static void put_oxel_D16_FFFF(u_int8_t *, u_int8_t, u_int8_t); 71 72 static const struct { 73 int type; 74 const char *name; 75 void (*func)(u_int8_t *, u_int8_t, u_int8_t); 76 u_int8_t clear_byte; 77 int16_t oxel_bytes; 78 } fb_table[] = { 79 { BIFB_D2_M2L_3, BIFBN_D2_M2L_3, 80 put_oxel_D2_M2L_3, 0, 2 }, 81 { BIFB_D2_M2L_3x2, BIFBN_D2_M2L_3x2, 82 put_oxel_D2_M2L_3x2, 0, 1 }, 83 { BIFB_D2_M2L_0, BIFBN_D2_M2L_0, 84 put_oxel_D2_M2L_0, 0xff, 2 }, 85 { BIFB_D2_M2L_0x2, BIFBN_D2_M2L_0x2, 86 put_oxel_D2_M2L_0x2, 0xff, 1 }, 87 { BIFB_D4_M2L_F, BIFBN_D4_M2L_F, 88 put_oxel_D4_M2L_F, 0x00, 4 }, 89 { BIFB_D4_M2L_Fx2, BIFBN_D4_M2L_Fx2, 90 put_oxel_D4_M2L_Fx2, 0x00, 2 }, 91 { BIFB_D4_M2L_0, BIFBN_D4_M2L_0, 92 put_oxel_D4_M2L_0, 0xff, 4 }, 93 { BIFB_D4_M2L_0x2, BIFBN_D4_M2L_0x2, 94 put_oxel_D4_M2L_0x2, 0xff, 2 }, 95 { BIFB_D8_00, BIFBN_D8_00, 96 put_oxel_D8_00, 0xff, 8 }, 97 { BIFB_D8_FF, BIFBN_D8_FF, 98 put_oxel_D8_FF, 0x00, 8 }, 99 { BIFB_D16_0000, BIFBN_D16_0000, 100 put_oxel_D16_0000, 0xff, 16 }, 101 { BIFB_D16_FFFF, BIFBN_D16_FFFF, 102 put_oxel_D16_FFFF, 0x00, 16 }, 103 }; 104 #define FB_TABLE_SIZE (sizeof(fb_table) / sizeof(*fb_table)) 105 106 static u_int8_t *fb_vram; 107 static int16_t fb_line_bytes; 108 static u_int8_t fb_clear_byte; 109 int16_t bicons_ypixel; 110 int16_t bicons_xpixel; 111 #ifdef HALF_FONT 112 static int16_t fb_oxel_bytes = 1; 113 int16_t bicons_width = 80; 114 void (*fb_put_oxel)(u_int8_t *, u_int8_t, u_int8_t) = put_oxel_D2_M2L_3x2; 115 #else /* HALF_FONT */ 116 static int16_t fb_oxel_bytes = 2; 117 int16_t bicons_width = 40; 118 void (*fb_put_oxel)(u_int8_t *, u_int8_t, u_int8_t) = put_oxel_D2_M2L_3; 119 #endif /* HALF_FONT */ 120 int16_t bicons_height; 121 static int16_t curs_x; 122 static int16_t curs_y; 123 124 static int bicons_priority; 125 int biconscninit(struct consdev *); 126 void biconscnprobe(struct consdev *); 127 void biconscnputc(dev_t, int); 128 int biconscngetc(dev_t); /* harmless place holder */ 129 130 static void draw_char(int, int, int); 131 static void clear(int, int); 132 static void scroll(int, int, int); 133 static void bicons_puts(const char *); 134 static void bicons_printf(const char *, ...) __unused; 135 136 int 137 bicons_init(struct consdev *cndev) 138 { 139 140 if (biconscninit(cndev) != 0) 141 return (1); 142 143 biconscnprobe(cndev); 144 145 return (0); /* success */ 146 } 147 148 int 149 biconscninit(struct consdev *cndev) 150 { 151 int fb_index = -1; 152 153 if (bootinfo->fb_addr == 0) { 154 /* Bootinfo don't have frame buffer address */ 155 return (1); 156 } 157 158 for (fb_index = 0; fb_index < FB_TABLE_SIZE; fb_index++) 159 if (fb_table[fb_index].type == bootinfo->fb_type) 160 break; 161 162 if (FB_TABLE_SIZE <= fb_index || fb_index == -1) { 163 /* Unknown frame buffer type, don't enable bicons. */ 164 return (1); 165 } 166 167 fb_vram = (u_int8_t *)bootinfo->fb_addr; 168 fb_line_bytes = bootinfo->fb_line_bytes; 169 bicons_xpixel = bootinfo->fb_width; 170 bicons_ypixel = bootinfo->fb_height; 171 172 fb_put_oxel = fb_table[fb_index].func; 173 fb_clear_byte = fb_table[fb_index].clear_byte; 174 fb_oxel_bytes = fb_table[fb_index].oxel_bytes; 175 176 bicons_width = bicons_xpixel / (8 * FONT_WIDTH); 177 bicons_height = bicons_ypixel / FONT_HEIGHT; 178 clear(0, bicons_ypixel); 179 180 curs_x = 0; 181 curs_y = 0; 182 183 bicons_puts("builtin console type = "); 184 bicons_puts(fb_table[fb_index].name); 185 bicons_puts("\n"); 186 187 return (0); 188 } 189 190 void 191 biconscnprobe(struct consdev *cndev) 192 { 193 extern const struct cdevsw biconsdev_cdevsw; 194 int maj; 195 196 /* locate the major number */ 197 maj = cdevsw_lookup_major(&biconsdev_cdevsw); 198 199 cndev->cn_dev = makedev(maj, 0); 200 cndev->cn_pri = bicons_priority; 201 } 202 203 void 204 bicons_set_priority(int priority) 205 { 206 bicons_priority = priority; 207 } 208 209 int 210 biconscngetc(dev_t dev) 211 { 212 printf("no input method. reboot me.\n"); 213 while (1) 214 ; 215 /* NOTREACHED */ 216 return 0; 217 } 218 219 void 220 biconscnputc(dev_t dev, int c) 221 { 222 int line_feed = 0; 223 224 switch (c) { 225 case 0x08: /* back space */ 226 if (--curs_x < 0) { 227 curs_x = 0; 228 } 229 /* erase character ar cursor position */ 230 draw_char(curs_x, curs_y, ' '); 231 break; 232 case '\r': 233 curs_x = 0; 234 break; 235 case '\n': 236 curs_x = 0; 237 line_feed = 1; 238 break; 239 default: 240 draw_char(curs_x, curs_y, c); 241 if (bicons_width <= ++curs_x) { 242 curs_x = 0; 243 line_feed = 1; 244 } 245 } 246 247 if (line_feed) { 248 if (bicons_height <= ++curs_y) { 249 /* scroll up */ 250 scroll(FONT_HEIGHT, (bicons_height - 1) * FONT_HEIGHT, 251 - FONT_HEIGHT); 252 clear((bicons_height - 1) * FONT_HEIGHT, FONT_HEIGHT); 253 curs_y--; 254 } 255 } 256 } 257 258 void 259 bicons_puts(const char *s) 260 { 261 while (*s) 262 biconscnputc(0, *s++); 263 } 264 265 266 void 267 bicons_putn(const char *s, int n) 268 { 269 while (0 < n--) 270 biconscnputc(0, *s++); 271 } 272 273 void 274 #ifdef __STDC__ 275 bicons_printf(const char *fmt, ...) 276 #else 277 bicons_printf(fmt, va_alist) 278 char *fmt; 279 va_dcl 280 #endif 281 { 282 va_list ap; 283 char buf[0x100]; 284 285 va_start(ap, fmt); 286 vsnprintf(buf, sizeof(buf), fmt, ap); 287 va_end(ap); 288 bicons_puts(buf); 289 } 290 291 static void 292 draw_char(int x, int y, int c) 293 { 294 int i; 295 u_int8_t *p; 296 297 if (!fb_vram) 298 return; 299 300 p = &fb_vram[(y * FONT_HEIGHT * fb_line_bytes) + 301 x * FONT_WIDTH * fb_oxel_bytes]; 302 for (i = 0; i < FONT_HEIGHT; i++) { 303 (*fb_put_oxel)(p, font_clR8x8_data 304 [FONT_WIDTH * (FONT_HEIGHT * c + i)], 0xff); 305 p += (fb_line_bytes); 306 } 307 } 308 309 static void 310 clear(int y, int height) 311 { 312 u_int8_t *p; 313 314 if (!fb_vram) 315 return; 316 317 p = &fb_vram[y * fb_line_bytes]; 318 319 while (0 < height--) { 320 memset(p, fb_clear_byte, 321 bicons_width * fb_oxel_bytes * FONT_WIDTH); 322 p += fb_line_bytes; 323 } 324 } 325 326 static void 327 scroll(int y, int height, int d) 328 { 329 u_int8_t *from, *to; 330 331 if (!fb_vram) 332 return; 333 334 if (d < 0) { 335 from = &fb_vram[y * fb_line_bytes]; 336 to = from + d * fb_line_bytes; 337 while (0 < height--) { 338 memcpy(to, from, bicons_width * fb_oxel_bytes); 339 from += fb_line_bytes; 340 to += fb_line_bytes; 341 } 342 } else { 343 from = &fb_vram[(y + height - 1) * fb_line_bytes]; 344 to = from + d * fb_line_bytes; 345 while (0 < height--) { 346 memcpy(to, from, bicons_xpixel * fb_oxel_bytes / 8); 347 from -= fb_line_bytes; 348 to -= fb_line_bytes; 349 } 350 } 351 } 352 353 /*============================================================================= 354 * 355 * D2_M2L_3 356 * 357 */ 358 static void 359 put_oxel_D2_M2L_3(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 360 { 361 #if 1 362 u_int16_t *addr = (u_int16_t *)xaddr; 363 static u_int16_t map0[] = { 364 0x0000, 0x0300, 0x0c00, 0x0f00, 0x3000, 0x3300, 0x3c00, 0x3f00, 365 0xc000, 0xc300, 0xcc00, 0xcf00, 0xf000, 0xf300, 0xfc00, 0xff00, 366 }; 367 static u_int16_t map1[] = { 368 0x0000, 0x0003, 0x000c, 0x000f, 0x0030, 0x0033, 0x003c, 0x003f, 369 0x00c0, 0x00c3, 0x00cc, 0x00cf, 0x00f0, 0x00f3, 0x00fc, 0x00ff, 370 }; 371 *addr = (map1[data >> 4] | map0[data & 0x0f]); 372 #else 373 static u_int8_t map[] = { 374 0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 375 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff, 376 }; 377 u_int8_t *addr = xaddr; 378 379 *addr++ = (map[(data >> 4) & 0x0f] & map[(mask >> 4) & 0x0f]) | 380 (*addr & ~map[(mask >> 4) & 0x0f]); 381 *addr = (map[(data >> 0) & 0x0f] & map[(mask >> 0) & 0x0f]) | 382 (*addr & ~map[(mask >> 0) & 0x0f]); 383 #endif 384 } 385 386 /*============================================================================= 387 * 388 * D2_M2L_3x2 389 * 390 */ 391 static void 392 put_oxel_D2_M2L_3x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 393 { 394 register u_int8_t odd = (data & 0xaa); 395 register u_int8_t even = (data & 0x55); 396 397 *xaddr = (odd | (even << 1)) | ((odd >> 1) & even); 398 } 399 400 /*============================================================================= 401 * 402 * D2_M2L_0 403 * 404 */ 405 static void 406 put_oxel_D2_M2L_0(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 407 { 408 #if 1 409 u_int16_t *addr = (u_int16_t *)xaddr; 410 static u_int16_t map0[] = { 411 0xff00, 0xfc00, 0xf300, 0xf000, 0xcf00, 0xcc00, 0xc300, 0xc000, 412 0x3f00, 0x3c00, 0x3300, 0x3000, 0x0f00, 0x0c00, 0x0300, 0x0000, 413 }; 414 static u_int16_t map1[] = { 415 0x00ff, 0x00fc, 0x00f3, 0x00f0, 0x00cf, 0x00cc, 0x00c3, 0x00c0, 416 0x003f, 0x003c, 0x0033, 0x0030, 0x000f, 0x000c, 0x0003, 0x0000, 417 }; 418 *addr = (map1[data >> 4] | map0[data & 0x0f]); 419 #else 420 static u_int8_t map[] = { 421 0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 422 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff, 423 }; 424 u_int8_t *addr = xaddr; 425 426 *addr++ = (~(map[(data >> 4) & 0x0f] & map[(mask >> 4) & 0x0f])) | 427 (*addr & ~map[(mask >> 4) & 0x0f]); 428 *addr = (~(map[(data >> 0) & 0x0f] & map[(mask >> 0) & 0x0f])) | 429 (*addr & ~map[(mask >> 0) & 0x0f]); 430 #endif 431 } 432 433 /*============================================================================= 434 * 435 * D2_M2L_0x2 436 * 437 */ 438 static void 439 put_oxel_D2_M2L_0x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 440 { 441 register u_int8_t odd = (data & 0xaa); 442 register u_int8_t even = (data & 0x55); 443 444 *xaddr = ~((odd | (even << 1)) | ((odd >> 1) & even)); 445 } 446 447 /*============================================================================= 448 * 449 * D4_M2L_F 450 * 451 */ 452 static void 453 put_oxel_D4_M2L_F(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 454 { 455 u_int32_t *addr = (u_int32_t *)xaddr; 456 static u_int32_t map[] = { 457 0x0000, 0x0f00, 0xf000, 0xff00, 0x000f, 0x0f0f, 0xf00f, 0xff0f, 458 0x00f0, 0x0ff0, 0xf0f0, 0xfff0, 0x00ff, 0x0fff, 0xf0ff, 0xffff, 459 }; 460 *addr = (map[data >> 4] | (map[data & 0x0f] << 16)); 461 } 462 463 /*============================================================================= 464 * 465 * D4_M2L_Fx2 466 * 467 */ 468 static void 469 put_oxel_D4_M2L_Fx2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 470 { 471 u_int16_t *addr = (u_int16_t *)xaddr; 472 static u_int16_t map[] = { 473 0x00, 0x08, 0x08, 0x0f, 0x80, 0x88, 0x88, 0x8f, 474 0x80, 0x88, 0x88, 0x8f, 0xf0, 0xf8, 0xf8, 0xff, 475 }; 476 477 *addr = (map[data >> 4] | (map[data & 0x0f] << 8)); 478 } 479 480 /*============================================================================= 481 * 482 * D4_M2L_0 483 * 484 */ 485 static void 486 put_oxel_D4_M2L_0(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 487 { 488 u_int32_t *addr = (u_int32_t *)xaddr; 489 static u_int32_t map[] = { 490 0xffff, 0xf0ff, 0x0fff, 0x00ff, 0xfff0, 0xf0f0, 0x0ff0, 0x00f0, 491 0xff0f, 0xf00f, 0x0f0f, 0x000f, 0xff00, 0xf000, 0x0f00, 0x0000, 492 }; 493 *addr = (map[data >> 4] | (map[data & 0x0f] << 16)); 494 } 495 496 /*============================================================================= 497 * 498 * D4_M2L_0x2 499 * 500 */ 501 static void 502 put_oxel_D4_M2L_0x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 503 { 504 u_int16_t *addr = (u_int16_t *)xaddr; 505 static u_int16_t map[] = { 506 0xff, 0xf8, 0xf8, 0xf0, 0x8f, 0x88, 0x88, 0x80, 507 0x8f, 0x88, 0x88, 0x80, 0x0f, 0x08, 0x08, 0x00, 508 }; 509 510 *addr = (map[data >> 4] | (map[data & 0x0f] << 8)); 511 } 512 513 /*============================================================================= 514 * 515 * D8_00 516 * 517 */ 518 static void 519 put_oxel_D8_00(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 520 { 521 int i; 522 u_int8_t *addr = xaddr; 523 524 for (i = 0; i < 8; i++) { 525 if (mask & 0x80) { 526 *addr = (data & 0x80) ? 0x00 : 0xFF; 527 } 528 addr++; 529 data <<= 1; 530 mask <<= 1; 531 } 532 } 533 534 /*============================================================================= 535 * 536 * D8_FF 537 * 538 */ 539 static void 540 put_oxel_D8_FF(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 541 { 542 int i; 543 u_int8_t *addr = xaddr; 544 545 for (i = 0; i < 8; i++) { 546 if (mask & 0x80) { 547 *addr = (data & 0x80) ? 0xFF : 0x00; 548 } 549 addr++; 550 data <<= 1; 551 mask <<= 1; 552 } 553 } 554 555 /*============================================================================= 556 * 557 * D16_0000 558 * 559 */ 560 static void 561 put_oxel_D16_0000(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 562 { 563 int i; 564 u_int16_t *addr = (u_int16_t *)xaddr; 565 566 for (i = 0; i < 8; i++) { 567 if (mask & 0x80) { 568 *addr = (data & 0x80) ? 0x0000 : 0xFFFF; 569 } 570 addr++; 571 data <<= 1; 572 mask <<= 1; 573 } 574 } 575 576 /*============================================================================= 577 * 578 * D16_FFFF 579 * 580 */ 581 static void 582 put_oxel_D16_FFFF(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 583 { 584 int i; 585 u_int16_t *addr = (u_int16_t *)xaddr; 586 587 for (i = 0; i < 8; i++) { 588 if (mask & 0x80) { 589 *addr = (data & 0x80) ? 0xFFFF : 0x0000; 590 } 591 addr++; 592 data <<= 1; 593 mask <<= 1; 594 } 595 } 596