1 /* $NetBSD: bicons.c,v 1.3 2001/09/15 15:27:59 uch 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 #define HALF_FONT 38 39 #include <sys/param.h> 40 #include <sys/device.h> 41 #include <sys/systm.h> 42 #include <sys/conf.h> 43 #include <dev/cons.h> 44 45 #include <machine/bootinfo.h> 46 #include <machine/bus.h> 47 #include <machine/platid.h> 48 #include <machine/stdarg.h> 49 50 #include <dev/hpc/biconsvar.h> 51 #include <dev/hpc/bicons.h> 52 extern u_int8_t font_clR8x8_data[]; 53 #define FONT_HEIGHT 8 54 #define FONT_WIDTH 1 55 56 static void put_oxel_D2_M2L_3(u_int8_t *, u_int8_t, u_int8_t); 57 static void put_oxel_D2_M2L_3x2(u_int8_t *, u_int8_t, u_int8_t); 58 static void put_oxel_D2_M2L_0(u_int8_t *, u_int8_t, u_int8_t); 59 static void put_oxel_D2_M2L_0x2(u_int8_t *, u_int8_t, u_int8_t); 60 static void put_oxel_D4_M2L_F(u_int8_t *, u_int8_t, u_int8_t); 61 static void put_oxel_D4_M2L_Fx2(u_int8_t *, u_int8_t, u_int8_t); 62 static void put_oxel_D4_M2L_0(u_int8_t *, u_int8_t, u_int8_t); 63 static void put_oxel_D4_M2L_0x2(u_int8_t *, u_int8_t, u_int8_t); 64 static void put_oxel_D8_00(u_int8_t *, u_int8_t, u_int8_t); 65 static void put_oxel_D8_FF(u_int8_t *, u_int8_t, u_int8_t); 66 static void put_oxel_D16_0000(u_int8_t *, u_int8_t, u_int8_t); 67 static void put_oxel_D16_FFFF(u_int8_t *, u_int8_t, u_int8_t); 68 69 struct { 70 int type; 71 char *name; 72 void (*func)(u_int8_t *, u_int8_t, u_int8_t); 73 u_int8_t clear_byte; 74 int16_t oxel_bytes; 75 } fb_table[] = { 76 { BIFB_D2_M2L_3, BIFBN_D2_M2L_3, 77 put_oxel_D2_M2L_3, 0, 2 }, 78 { BIFB_D2_M2L_3x2, BIFBN_D2_M2L_3x2, 79 put_oxel_D2_M2L_3x2, 0, 1 }, 80 { BIFB_D2_M2L_0, BIFBN_D2_M2L_0, 81 put_oxel_D2_M2L_0, 0xff, 2 }, 82 { BIFB_D2_M2L_0x2, BIFBN_D2_M2L_0x2, 83 put_oxel_D2_M2L_0x2, 0xff, 1 }, 84 { BIFB_D4_M2L_F, BIFBN_D4_M2L_F, 85 put_oxel_D4_M2L_F, 0x00, 4 }, 86 { BIFB_D4_M2L_Fx2, BIFBN_D4_M2L_Fx2, 87 put_oxel_D4_M2L_Fx2, 0x00, 2 }, 88 { BIFB_D4_M2L_0, BIFBN_D4_M2L_0, 89 put_oxel_D4_M2L_0, 0xff, 4 }, 90 { BIFB_D4_M2L_0x2, BIFBN_D4_M2L_0x2, 91 put_oxel_D4_M2L_0x2, 0xff, 2 }, 92 { BIFB_D8_00, BIFBN_D8_00, 93 put_oxel_D8_00, 0xff, 8 }, 94 { BIFB_D8_FF, BIFBN_D8_FF, 95 put_oxel_D8_FF, 0x00, 8 }, 96 { BIFB_D16_0000, BIFBN_D16_0000, 97 put_oxel_D16_0000, 0xff, 16 }, 98 { BIFB_D16_FFFF, BIFBN_D16_FFFF, 99 put_oxel_D16_FFFF, 0x00, 16 }, 100 }; 101 #define FB_TABLE_SIZE (sizeof(fb_table)/sizeof(*fb_table)) 102 103 static u_int8_t *fb_vram; 104 static int16_t fb_line_bytes; 105 static u_int8_t fb_clear_byte; 106 int16_t bicons_ypixel; 107 int16_t bicons_xpixel; 108 #ifdef HALF_FONT 109 static int16_t fb_oxel_bytes = 1; 110 int16_t bicons_width = 80; 111 void (*fb_put_oxel)(u_int8_t *, u_int8_t, u_int8_t) = put_oxel_D2_M2L_3x2; 112 #else /* HALF_FONT */ 113 static int16_t fb_oxel_bytes = 2; 114 int16_t bicons_width = 40; 115 void (*fb_put_oxel)(u_int8_t *, u_int8_t, u_int8_t) = put_oxel_D2_M2L_3; 116 #endif /* HALF_FONT */ 117 int16_t bicons_height; 118 static int16_t curs_x; 119 static int16_t curs_y; 120 121 cdev_decl(biconsdev); 122 123 static int bicons_priority; 124 void biconscninit(struct consdev *); 125 void biconscnprobe(struct consdev *); 126 void biconscnputc(dev_t, int); 127 int biconscngetc(dev_t); /* harmless place holder */ 128 129 static void draw_char(int, int, int); 130 static void clear(int, int); 131 static void scroll(int, int, int); 132 static void bicons_puts(char *); 133 static void bicons_printf(const char *, ...) __attribute__((__unused__)); 134 135 void 136 bicons_init(struct consdev *cndev) 137 { 138 biconscninit(cndev); 139 biconscnprobe(cndev); 140 } 141 142 void 143 biconscninit(struct consdev *cndev) 144 { 145 int fb_index = -1; 146 147 for (fb_index = 0; fb_index < FB_TABLE_SIZE; fb_index++) 148 if (fb_table[fb_index].type == bootinfo->fb_type) 149 break; 150 151 if (FB_TABLE_SIZE <= fb_index || fb_index == -1) { 152 /* 153 * Unknown frame buffer type, but what can I do ? 154 */ 155 fb_index = 0; 156 } 157 158 fb_vram = (u_int8_t *)bootinfo->fb_addr; 159 fb_line_bytes = bootinfo->fb_line_bytes; 160 bicons_xpixel = bootinfo->fb_width; 161 bicons_ypixel = bootinfo->fb_height; 162 163 fb_put_oxel = fb_table[fb_index].func; 164 fb_clear_byte = fb_table[fb_index].clear_byte; 165 fb_oxel_bytes = fb_table[fb_index].oxel_bytes; 166 167 bicons_width = bicons_xpixel / (8 * FONT_WIDTH); 168 bicons_height = bicons_ypixel / FONT_HEIGHT; 169 clear(0, bicons_ypixel); 170 171 curs_x = 0; 172 curs_y = 0; 173 174 bicons_puts("builtin console type = "); 175 bicons_puts(fb_table[fb_index].name); 176 bicons_puts("\n"); 177 } 178 179 void 180 biconscnprobe(struct consdev *cndev) 181 { 182 int maj; 183 184 /* locate the major number */ 185 for (maj = 0; maj < nchrdev; maj++) 186 if (cdevsw[maj].d_open == biconsdevopen) 187 break; 188 189 cndev->cn_dev = makedev(maj, 0); 190 cndev->cn_pri = bicons_priority; 191 } 192 193 void 194 bicons_set_priority(int priority) 195 { 196 bicons_priority = priority; 197 } 198 199 int 200 biconscngetc(dev_t dev) 201 { 202 printf("no input method. reboot me.\n"); 203 while (1) 204 ; 205 /* NOTREACHED */ 206 } 207 208 void 209 biconscnputc(dev_t dev, int c) 210 { 211 int line_feed = 0; 212 213 switch (c) { 214 case 0x08: /* back space */ 215 if (--curs_x < 0) { 216 curs_x = 0; 217 } 218 /* erase character ar cursor position */ 219 draw_char(curs_x, curs_y, ' '); 220 break; 221 case '\r': 222 curs_x = 0; 223 break; 224 case '\n': 225 curs_x = 0; 226 line_feed = 1; 227 break; 228 default: 229 draw_char(curs_x, curs_y, c); 230 if (bicons_width <= ++curs_x) { 231 curs_x = 0; 232 line_feed = 1; 233 } 234 } 235 236 if (line_feed) { 237 if (bicons_height <= ++curs_y) { 238 /* scroll up */ 239 scroll(FONT_HEIGHT, (bicons_height - 1) * FONT_HEIGHT, 240 - FONT_HEIGHT); 241 clear((bicons_height - 1) * FONT_HEIGHT, FONT_HEIGHT); 242 curs_y--; 243 } 244 } 245 } 246 247 void 248 bicons_puts(char *s) 249 { 250 while (*s) 251 biconscnputc(NULL, *s++); 252 } 253 254 255 void 256 bicons_putn(const char *s, int n) 257 { 258 while (0 < n--) 259 biconscnputc(NULL, *s++); 260 } 261 262 void 263 #ifdef __STDC__ 264 bicons_printf(const char *fmt, ...) 265 #else 266 bicons_printf(fmt, va_alist) 267 char *fmt; 268 va_dcl 269 #endif 270 { 271 va_list ap; 272 char buf[0x100]; 273 274 va_start(ap, fmt); 275 vsnprintf(buf, sizeof(buf), fmt, ap); 276 va_end(ap); 277 bicons_puts(buf); 278 } 279 280 static void 281 draw_char(int x, int y, int c) 282 { 283 int i; 284 u_int8_t *p; 285 286 if (!fb_vram) 287 return; 288 289 p = &fb_vram[(y * FONT_HEIGHT * fb_line_bytes) + 290 x * FONT_WIDTH * fb_oxel_bytes]; 291 for (i = 0; i < FONT_HEIGHT; i++) { 292 (*fb_put_oxel)(p, font_clR8x8_data 293 [FONT_WIDTH * (FONT_HEIGHT * c + i)], 0xff); 294 p += (fb_line_bytes); 295 } 296 } 297 298 static void 299 clear(int y, int height) 300 { 301 u_int8_t *p; 302 303 if (!fb_vram) 304 return; 305 306 p = &fb_vram[y * fb_line_bytes]; 307 308 while (0 < height--) { 309 memset(p, fb_clear_byte, 310 bicons_width * fb_oxel_bytes * FONT_WIDTH); 311 p += fb_line_bytes; 312 } 313 } 314 315 static void 316 scroll(int y, int height, int d) 317 { 318 u_int8_t *from, *to; 319 320 if (!fb_vram) 321 return; 322 323 if (d < 0) { 324 from = &fb_vram[y * fb_line_bytes]; 325 to = from + d * fb_line_bytes; 326 while (0 < height--) { 327 memcpy(to, from, bicons_width * fb_oxel_bytes); 328 from += fb_line_bytes; 329 to += fb_line_bytes; 330 } 331 } else { 332 from = &fb_vram[(y + height - 1) * fb_line_bytes]; 333 to = from + d * fb_line_bytes; 334 while (0 < height--) { 335 memcpy(to, from, bicons_xpixel * fb_oxel_bytes / 8); 336 from -= fb_line_bytes; 337 to -= fb_line_bytes; 338 } 339 } 340 } 341 342 /*============================================================================= 343 * 344 * D2_M2L_3 345 * 346 */ 347 static void 348 put_oxel_D2_M2L_3(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 349 { 350 #if 1 351 u_int16_t *addr = (u_int16_t *)xaddr; 352 static u_int16_t map0[] = { 353 0x0000, 0x0300, 0x0c00, 0x0f00, 0x3000, 0x3300, 0x3c00, 0x3f00, 354 0xc000, 0xc300, 0xcc00, 0xcf00, 0xf000, 0xf300, 0xfc00, 0xff00, 355 }; 356 static u_int16_t map1[] = { 357 0x0000, 0x0003, 0x000c, 0x000f, 0x0030, 0x0033, 0x003c, 0x003f, 358 0x00c0, 0x00c3, 0x00cc, 0x00cf, 0x00f0, 0x00f3, 0x00fc, 0x00ff, 359 }; 360 *addr = (map1[data >> 4] | map0[data & 0x0f]); 361 #else 362 static u_int8_t map[] = { 363 0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 364 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff, 365 }; 366 u_int8_t *addr = xaddr; 367 368 *addr++ = (map[(data >> 4) & 0x0f] & map[(mask >> 4) & 0x0f]) | 369 (*addr & ~map[(mask >> 4) & 0x0f]); 370 *addr = (map[(data >> 0) & 0x0f] & map[(mask >> 0) & 0x0f]) | 371 (*addr & ~map[(mask >> 0) & 0x0f]); 372 #endif 373 } 374 375 /*============================================================================= 376 * 377 * D2_M2L_3x2 378 * 379 */ 380 static void 381 put_oxel_D2_M2L_3x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 382 { 383 register u_int8_t odd = (data & 0xaa); 384 register u_int8_t even = (data & 0x55); 385 386 *xaddr = (odd | (even << 1)) | ((odd >> 1) & even); 387 } 388 389 /*============================================================================= 390 * 391 * D2_M2L_0 392 * 393 */ 394 static void 395 put_oxel_D2_M2L_0(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 396 { 397 #if 1 398 u_int16_t *addr = (u_int16_t *)xaddr; 399 static u_int16_t map0[] = { 400 0xff00, 0xfc00, 0xf300, 0xf000, 0xcf00, 0xcc00, 0xc300, 0xc000, 401 0x3f00, 0x3c00, 0x3300, 0x3000, 0x0f00, 0x0c00, 0x0300, 0x0000, 402 }; 403 static u_int16_t map1[] = { 404 0x00ff, 0x00fc, 0x00f3, 0x00f0, 0x00cf, 0x00cc, 0x00c3, 0x00c0, 405 0x003f, 0x003c, 0x0033, 0x0030, 0x000f, 0x000c, 0x0003, 0x0000, 406 }; 407 *addr = (map1[data >> 4] | map0[data & 0x0f]); 408 #else 409 static u_int8_t map[] = { 410 0x00, 0x03, 0x0c, 0x0f, 0x30, 0x33, 0x3c, 0x3f, 411 0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff, 412 }; 413 u_int8_t *addr = xaddr; 414 415 *addr++ = (~(map[(data >> 4) & 0x0f] & map[(mask >> 4) & 0x0f])) | 416 (*addr & ~map[(mask >> 4) & 0x0f]); 417 *addr = (~(map[(data >> 0) & 0x0f] & map[(mask >> 0) & 0x0f])) | 418 (*addr & ~map[(mask >> 0) & 0x0f]); 419 #endif 420 } 421 422 /*============================================================================= 423 * 424 * D2_M2L_0x2 425 * 426 */ 427 static void 428 put_oxel_D2_M2L_0x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 429 { 430 register u_int8_t odd = (data & 0xaa); 431 register u_int8_t even = (data & 0x55); 432 433 *xaddr = ~((odd | (even << 1)) | ((odd >> 1) & even)); 434 } 435 436 /*============================================================================= 437 * 438 * D4_M2L_F 439 * 440 */ 441 static void 442 put_oxel_D4_M2L_F(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 443 { 444 u_int32_t *addr = (u_int32_t *)xaddr; 445 static u_int32_t map[] = { 446 0x0000, 0x0f00, 0xf000, 0xff00, 0x000f, 0x0f0f, 0xf00f, 0xff0f, 447 0x00f0, 0x0ff0, 0xf0f0, 0xfff0, 0x00ff, 0x0fff, 0xf0ff, 0xffff, 448 }; 449 *addr = (map[data >> 4] | (map[data & 0x0f] << 16)); 450 } 451 452 /*============================================================================= 453 * 454 * D4_M2L_Fx2 455 * 456 */ 457 static void 458 put_oxel_D4_M2L_Fx2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 459 { 460 u_int16_t *addr = (u_int16_t *)xaddr; 461 static u_int16_t map[] = { 462 0x00, 0x08, 0x08, 0x0f, 0x80, 0x88, 0x88, 0x8f, 463 0x80, 0x88, 0x88, 0x8f, 0xf0, 0xf8, 0xf8, 0xff, 464 }; 465 466 *addr = (map[data >> 4] | (map[data & 0x0f] << 8)); 467 } 468 469 /*============================================================================= 470 * 471 * D4_M2L_0 472 * 473 */ 474 static void 475 put_oxel_D4_M2L_0(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 476 { 477 u_int32_t *addr = (u_int32_t *)xaddr; 478 static u_int32_t map[] = { 479 0xffff, 0xf0ff, 0x0fff, 0x00ff, 0xfff0, 0xf0f0, 0x0ff0, 0x00f0, 480 0xff0f, 0xf00f, 0x0f0f, 0x000f, 0xff00, 0xf000, 0x0f00, 0x0000, 481 }; 482 *addr = (map[data >> 4] | (map[data & 0x0f] << 16)); 483 } 484 485 /*============================================================================= 486 * 487 * D4_M2L_0x2 488 * 489 */ 490 static void 491 put_oxel_D4_M2L_0x2(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 492 { 493 u_int16_t *addr = (u_int16_t *)xaddr; 494 static u_int16_t map[] = { 495 0xff, 0xf8, 0xf8, 0xf0, 0x8f, 0x88, 0x88, 0x80, 496 0x8f, 0x88, 0x88, 0x80, 0x0f, 0x08, 0x08, 0x00, 497 }; 498 499 *addr = (map[data >> 4] | (map[data & 0x0f] << 8)); 500 } 501 502 /*============================================================================= 503 * 504 * D8_00 505 * 506 */ 507 static void 508 put_oxel_D8_00(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 509 { 510 int i; 511 u_int8_t *addr = xaddr; 512 513 for (i = 0; i < 8; i++) { 514 if (mask & 0x80) { 515 *addr = (data & 0x80) ? 0x00 : 0xFF; 516 } 517 addr++; 518 data <<= 1; 519 mask <<= 1; 520 } 521 } 522 523 /*============================================================================= 524 * 525 * D8_FF 526 * 527 */ 528 static void 529 put_oxel_D8_FF(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 530 { 531 int i; 532 u_int8_t *addr = xaddr; 533 534 for (i = 0; i < 8; i++) { 535 if (mask & 0x80) { 536 *addr = (data & 0x80) ? 0xFF : 0x00; 537 } 538 addr++; 539 data <<= 1; 540 mask <<= 1; 541 } 542 } 543 544 /*============================================================================= 545 * 546 * D16_0000 547 * 548 */ 549 static void 550 put_oxel_D16_0000(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 551 { 552 int i; 553 u_int16_t *addr = (u_int16_t *)xaddr; 554 555 for (i = 0; i < 8; i++) { 556 if (mask & 0x80) { 557 *addr = (data & 0x80) ? 0x0000 : 0xFFFF; 558 } 559 addr++; 560 data <<= 1; 561 mask <<= 1; 562 } 563 } 564 565 /*============================================================================= 566 * 567 * D16_FFFF 568 * 569 */ 570 static void 571 put_oxel_D16_FFFF(u_int8_t *xaddr, u_int8_t data, u_int8_t mask) 572 { 573 int i; 574 u_int16_t *addr = (u_int16_t *)xaddr; 575 576 for (i = 0; i < 8; i++) { 577 if (mask & 0x80) { 578 *addr = (data & 0x80) ? 0xFFFF : 0x0000; 579 } 580 addr++; 581 data <<= 1; 582 mask <<= 1; 583 } 584 } 585