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