vidconsole.c revision 42291
121259Swollman/* 221259Swollman * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) 321259Swollman * Copyright (c) 1997 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp) 421259Swollman * All rights reserved. 521259Swollman * 621259Swollman * Redistribution and use in source and binary forms, with or without 721259Swollman * modification, are permitted provided that the following conditions 821259Swollman * are met: 921259Swollman * 1. Redistributions of source code must retain the above copyright 1021259Swollman * notice, this list of conditions and the following disclaimer. 1121259Swollman * 2. Redistributions in binary form must reproduce the above copyright 1221259Swollman * notice, this list of conditions and the following disclaimer in the 1321259Swollman * documentation and/or other materials provided with the distribution. 1421259Swollman * 1521259Swollman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1621259Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1721259Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1821259Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1921259Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2021259Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2121259Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2221259Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2321259Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2421259Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2521259Swollman * SUCH DAMAGE. 2621259Swollman * 2721259Swollman * From Id: probe_keyboard.c,v 1.13 1997/06/09 05:10:55 bde Exp 2821259Swollman * 2921259Swollman * $Id: vidconsole.c,v 1.10 1998/12/31 13:44:04 abial Exp $ 3021259Swollman */ 3121259Swollman 3221259Swollman#include <stand.h> 3321259Swollman#include <bootstrap.h> 3450477Speter#include <btxv86.h> 3521259Swollman#include <machine/psl.h> 3621259Swollman#include "libi386.h" 3721259Swollman 3821259Swollman#if KEYBOARD_PROBE 3921259Swollman#include <machine/cpufunc.h> 4021259Swollman 4121259Swollmanstatic int probe_keyboard(void); 4221259Swollman#endif 4321259Swollmanstatic void vidc_probe(struct console *cp); 4421259Swollmanstatic int vidc_init(int arg); 4521259Swollmanstatic void vidc_putchar(int c); 4621259Swollmanstatic int vidc_getchar(void); 4721259Swollmanstatic int vidc_ischar(void); 4821259Swollman 4921259Swollmanstatic int vidc_started; 5021259Swollman 5121259Swollman#ifdef TERM_EMU 5221259Swollmanvoid end_term(); 5321259Swollmanvoid bail_out(int c); 5421259Swollmanvoid vidc_term_emu(int c); 5521259Swollmanvoid get_pos(void); 5621259Swollmanvoid curs_move(int x, int y); 5721259Swollmanvoid write_char(int c, int fg, int bg); 5821259Swollmanvoid scroll_up(int rows, int fg, int bg); 5921259Swollmanvoid AB(void); 6021259Swollmanvoid AF(void); 6121259Swollmanvoid CD(void); 6221259Swollmanvoid CM(void); 6321259Swollmanvoid HO(void); 6421259Swollmanvoid ME(void); 6521259Swollman 6621259Swollmanstatic int args[2],argc,br; 6721259Swollmanstatic int fg,bg,dig; 6821259Swollmanstatic int fg_c,bg_c,curx,cury; 6921259Swollmanstatic int esc; 7021259Swollman#endif 7121259Swollman 7221259Swollman 7321259Swollmanstruct console vidconsole = { 7421259Swollman "vidconsole", 7521259Swollman "internal video/keyboard", 7621259Swollman 0, 7721259Swollman vidc_probe, 7869224Sjlemon vidc_init, 7969152Sjlemon vidc_putchar, 8069224Sjlemon vidc_getchar, 8169224Sjlemon vidc_ischar 8269152Sjlemon}; 8360938Sjake 8460938Sjakestatic void 8560938Sjakevidc_probe(struct console *cp) 8672084Sphk{ 8721259Swollman 8821259Swollman /* look for a keyboard */ 8921259Swollman#if KEYBOARD_PROBE 9021259Swollman if (probe_keyboard()) 9121259Swollman#endif 9221259Swollman { 9321259Swollman 9421259Swollman cp->c_flags |= C_PRESENTIN; 9521259Swollman } 9621259Swollman 9769152Sjlemon /* XXX for now, always assume we can do BIOS screen output */ 9821259Swollman cp->c_flags |= C_PRESENTOUT; 9921259Swollman} 10021259Swollman 10121259Swollmanstatic int 10221259Swollmanvidc_init(int arg) 10321259Swollman{ 10421259Swollman int i; 10521259Swollman 10621259Swollman if (vidc_started && arg == 0) 10721259Swollman return; 10860938Sjake vidc_started = 1; 10921259Swollman#ifdef TERM_EMU 11021259Swollman /* Init terminal emulator */ 11121259Swollman end_term(); 11221259Swollman get_pos(); 11321259Swollman curs_move(curx,cury); 11421259Swollman fg_c=7; 11521259Swollman bg_c=0; 11669152Sjlemon#endif 11721259Swollman for(i = 0; i < 10 && vidc_ischar(); i++) 11821259Swollman (void)vidc_getchar(); 11921259Swollman return(0); /* XXX reinit? */ 12021259Swollman} 12121404Swollman 12221404Swollmanstatic void 12321259Swollmanvidc_biosputchar(int c) 12421259Swollman{ 12521259Swollman v86.ctl = 0; 12621259Swollman v86.addr = 0x10; 12721259Swollman v86.eax = 0xe00 | (c & 0xff); 12821259Swollman v86.ebx = 0x7; 12921259Swollman v86int(); 13021259Swollman} 13121259Swollman 13236735Sdfrstatic void 13321259Swollmanvidc_rawputchar(int c) 13421259Swollman{ 13521259Swollman int i; 13621259Swollman 13721259Swollman if(c == '\t') 13821259Swollman /* lame tab expansion */ 13921259Swollman for (i = 0; i < 8; i++) 14021259Swollman vidc_rawputchar(' '); 14121259Swollman else { 14221259Swollman#ifndef TERM_EMU 14321259Swollman vidc_biosputchar(c); 14421259Swollman#else 14521404Swollman /* Emulate AH=0eh (teletype output) */ 14621404Swollman switch(c) { 14721259Swollman case '\a': 14821259Swollman vidc_biosputchar(c); 14952904Sshin return; 15021259Swollman case '\r': 15169152Sjlemon curx=0; 15221259Swollman curs_move(curx,cury); 15321259Swollman return; 15421259Swollman case '\n': 15521259Swollman cury++; 15621259Swollman if(cury>24) { 15721259Swollman scroll_up(1,fg_c,bg_c); 15821259Swollman cury--; 15921259Swollman } else { 16021259Swollman curs_move(curx,cury); 16158698Sjlemon } 16221259Swollman return; 16321259Swollman case '\b': 16421259Swollman if(curx>0) { 16521259Swollman curx--; 16621259Swollman curs_move(curx,cury); 16721259Swollman /* write_char(' ',fg_c,bg_c); XXX destructive(!) */ 16821259Swollman return; 16921259Swollman } 17021259Swollman return; 17121259Swollman default: 17221259Swollman write_char(c,fg_c,bg_c); 17321259Swollman curx++; 17421259Swollman if(curx>79) { 17521259Swollman curx=0; 17621259Swollman cury++; 17721259Swollman } 17853541Sshin if(cury>24) { 17953541Sshin curx=0; 18053541Sshin scroll_up(1,fg_c,bg_c); 18153541Sshin cury--; 18221259Swollman } 18321259Swollman } 18421259Swollman curs_move(curx,cury); 18521259Swollman#endif 18621259Swollman } 18721259Swollman} 18821259Swollman 18921259Swollman#ifdef TERM_EMU 19021259Swollman 19121259Swollman/* Get cursor position on the screen. Result is in edx. Sets 19221259Swollman * curx and cury appropriately. 19321259Swollman */ 19469152Sjlemonvoid 19569152Sjlemonget_pos(void) 19669152Sjlemon{ 19769152Sjlemon v86.ctl = 0; 19869152Sjlemon v86.addr = 0x10; 19921259Swollman v86.eax = 0x0300; 20069152Sjlemon v86.ebx = 0x0; 20169152Sjlemon v86int(); 20269152Sjlemon curx=v86.edx & 0x00ff; 20369152Sjlemon cury=(v86.edx & 0xff00)>>8; 20469152Sjlemon} 20569152Sjlemon 20669152Sjlemon/* Move cursor to x rows and y cols (0-based). */ 20769152Sjlemonvoid 20869152Sjlemoncurs_move(int x, int y) 20969152Sjlemon{ 21069152Sjlemon v86.ctl = 0; 21169152Sjlemon v86.addr = 0x10; 21269152Sjlemon v86.eax = 0x0200; 21369152Sjlemon v86.ebx = 0x0; 21469152Sjlemon v86.edx = ((0x00ff & y)<<8)+(0x00ff & x); 21569152Sjlemon v86int(); 21669152Sjlemon curx=x; 21769152Sjlemon cury=y; 21869152Sjlemon /* If there is ctrl char at this position, cursor would be invisible. 21969152Sjlemon * Make it a space instead. 22069152Sjlemon */ 22169152Sjlemon v86.ctl=0; 22269152Sjlemon v86.addr = 0x10; 22369152Sjlemon v86.eax = 0x0800; 22469152Sjlemon v86.ebx= 0x0; 22569152Sjlemon v86int(); 22669152Sjlemon#define isvisible(c) (((c)>32) && ((c)<255)) 22769152Sjlemon if(!isvisible(v86.eax & 0x00ff)) { 22869152Sjlemon write_char(' ',fg_c,bg_c); 22969152Sjlemon } 23069152Sjlemon} 23169152Sjlemon 23269152Sjlemon/* Scroll up the whole window by a number of rows. If rows==0, 23369152Sjlemon * clear the window. fg and bg are attributes for the new lines 23469152Sjlemon * inserted in the window. 23569152Sjlemon */ 23669152Sjlemonvoid 23769152Sjlemonscroll_up(int rows, int fg, int bg) 23869152Sjlemon{ 23969152Sjlemon if(rows==0) rows=25; 24069152Sjlemon v86.ctl = 0; 24169152Sjlemon v86.addr = 0x10; 24269152Sjlemon v86.eax = 0x0600+(0x00ff & rows); 24369152Sjlemon v86.ebx = (bg<<12)+(fg<<8); 24469152Sjlemon v86.ecx = 0x0; 24569152Sjlemon v86.edx = 0x184f; 24669152Sjlemon v86int(); 24769152Sjlemon} 24869152Sjlemon 24969152Sjlemon/* Write character and attribute at cursor position. */ 25069152Sjlemonvoid 25169152Sjlemonwrite_char(int c, int fg, int bg) 25269152Sjlemon{ 25369152Sjlemon v86.ctl=0; 25469152Sjlemon v86.addr = 0x10; 25569152Sjlemon v86.eax = 0x0900+(0x00ff & c); 25669152Sjlemon v86.ebx = (bg<<4)+fg; 25769152Sjlemon v86.ecx = 0x1; 25855205Speter v86int(); 25969152Sjlemon} 26069152Sjlemon 26121259Swollman/* Calculate power of 10 */ 26235210Sbdeint 26369152Sjlemonpow10(int i) 26421259Swollman{ 26569152Sjlemon int res=1; 26621259Swollman 26769152Sjlemon while(i-->0) { 26869152Sjlemon res*=10; 26969152Sjlemon } 27069152Sjlemon return res; 27169152Sjlemon} 27269152Sjlemon 27369152Sjlemon/**************************************************************/ 27469152Sjlemon/* 27569152Sjlemon * Screen manipulation functions. They use accumulated data in 27669152Sjlemon * args[] and argc variables. 27769152Sjlemon * 27869152Sjlemon */ 27969152Sjlemon 28069152Sjlemon/* Set background color */ 28169152Sjlemonvoid 28269152SjlemonAB(void){ 28369152Sjlemon bg_c=args[0]; 28469152Sjlemon end_term(); 28569152Sjlemon} 28669152Sjlemon 28769152Sjlemon/* Set foreground color */ 28869152Sjlemonvoid 28969152SjlemonAF(void) 29069152Sjlemon{ 29169152Sjlemon fg_c=args[0]; 29221259Swollman end_term(); 29321259Swollman} 29449459Sbrian 29549459Sbrian/* Clear display from current position to end of screen */ 29649459Sbrianvoid 29749459SbrianCD(void) 29849459Sbrian{ 29949459Sbrian get_pos(); 30049459Sbrian v86.ctl = 0; 30155205Speter v86.addr = 0x10; 30221259Swollman v86.eax = 0x0600; 30321259Swollman v86.ebx = (bg_c<<4)+fg_c; 30421259Swollman v86.ecx = v86.edx; 30521259Swollman v86.edx = 0x184f; 30621259Swollman v86int(); 30721259Swollman curx=0; 30821259Swollman curs_move(curx,cury); 30921259Swollman end_term(); 31021259Swollman} 31121259Swollman 31221259Swollman/* Absolute cursor move to args[0] rows and args[1] columns 31321259Swollman * (the coordinates are 1-based). 31467334Sjoe */ 31521259Swollmanvoid 31660938SjakeCM(void) 31721259Swollman{ 31821259Swollman if(args[0]>0) args[0]--; 31921259Swollman if(args[1]>0) args[1]--; 32047254Spb curs_move(args[1],args[0]); 32121259Swollman end_term(); 32221259Swollman} 32321259Swollman 32421259Swollman/* Home cursor (left top corner) */ 32528845Sjulianvoid 32628845SjulianHO(void) 32728845Sjulian{ 32821259Swollman argc=1; 32921259Swollman args[0]=args[1]=1; 33021259Swollman CM(); 33153541Sshin} 33253541Sshin 33353541Sshin/* Exit attribute mode (reset fore/back-ground colors to defaults) */ 33421404Swollmanvoid 33552904SshinME(void) 33652904Sshin{ 33752904Sshin fg_c=7; 33853541Sshin bg_c=0; 33952904Sshin end_term(); 34052904Sshin} 34152904Sshin 34252904Sshin/* Clear internal state of the terminal emulation code */ 34360938Sjakevoid 34452904Sshinend_term(void) 34552904Sshin{ 34652904Sshin esc=0; 34752904Sshin argc=-1; 34852904Sshin fg=bg=br=0; 34921404Swollman args[0]=args[1]=0; 35021404Swollman dig=0; 35121404Swollman} 35221404Swollman 35321404Swollman/* Gracefully exit ESC-sequence processing in case of misunderstanding */ 35421404Swollmanvoid 35572084Sphkbail_out(int c) 35621434Swollman{ 35721434Swollman char buf[6],*ch; 35821434Swollman 35921434Swollman if(esc) vidc_rawputchar('\033'); 36021434Swollman if(br) vidc_rawputchar('['); 36121404Swollman if(argc>-1) { 36221404Swollman sprintf(buf,"%d",args[0]); 36355205Speter ch=buf; 36421259Swollman while(*ch) vidc_rawputchar(*ch++); 36546568Speter 36646568Speter if(argc>0) { 36746568Speter vidc_rawputchar(';'); 36846568Speter sprintf(buf,"%d",args[1]); 36946568Speter ch=buf; 37046568Speter while(*ch) vidc_rawputchar(*ch++); 37121259Swollman } 37221259Swollman } 37352904Sshin vidc_rawputchar(c); 37421259Swollman end_term(); 37571791Speter} 37621259Swollman 37721259Swollman/* Emulate basic capabilities of cons25 terminal */ 37821259Swollmanvoid 37963090Sarchievidc_term_emu(int c) 38063090Sarchie{ 38121259Swollman 38262143Sarchie if(!esc) { 38321259Swollman if(c=='\033') { 38421259Swollman esc=1; 38562143Sarchie } else { 38621259Swollman vidc_rawputchar(c); 38721259Swollman } 38853541Sshin return; 38921434Swollman } 39021404Swollman 39121259Swollman /* Do ESC sequences processing */ 39221404Swollman switch(c) { 39345720Speter case '\033': 39421259Swollman /* ESC in ESC sequence - error */ 39541879Sphk bail_out(c); 39664651Sarchie break; 39741879Sphk case '[': 39821259Swollman /* Check if it's first char after ESC */ 39921259Swollman if(argc<0) { 40036735Sdfr br=1; 40121259Swollman } else { 40221259Swollman bail_out(c); 40352904Sshin } 40421259Swollman break; 40521259Swollman case 'H': 40621259Swollman /* Emulate \E[H (cursor home) and 40721259Swollman * \E%d;%dH (cursor absolute move) */ 40821259Swollman if(br) { 40921259Swollman switch(argc) { 41021259Swollman case -1: 41121259Swollman HO(); 41221259Swollman break; 41321259Swollman case 1: 41421259Swollman if(fg) args[0]+=pow10(dig)*3; 41521259Swollman if(bg) args[0]+=pow10(dig)*4; 41621259Swollman CM(); 41721259Swollman break; 41821259Swollman default: 41921259Swollman bail_out(c); 42053541Sshin } 42121434Swollman } else bail_out(c); 42260889Sarchie break; 42321434Swollman case 'J': 42455205Speter /* Emulate \EJ (clear to end of screen) */ 42521259Swollman if(br && argc<0) { 42621259Swollman CD(); 427 } else bail_out(c); 428 break; 429 case ';': 430 /* perhaps args separator */ 431 if(br && (argc>-1)) { 432 argc++; 433 } else bail_out(c); 434 break; 435 case 'm': 436 /* Change char attributes */ 437 if(br) { 438 switch(argc) { 439 case -1: 440 ME(); 441 break; 442 case 0: 443 if(fg) AF(); 444 else AB(); 445 break; 446 default: 447 bail_out(c); 448 } 449 } else bail_out(c); 450 break; 451 default: 452 if(isdigit(c)) { 453 /* Carefully collect numeric arguments */ 454 /* XXX this is ugly. */ 455 if(br) { 456 if(argc==-1) { 457 argc=0; 458 args[argc]=0; 459 dig=0; 460 /* in case we're in error... */ 461 if(c=='3') { 462 fg=1; 463 return; 464 } 465 if(c=='4') { 466 bg=1; 467 return; 468 } 469 args[argc]=(int)(c-'0'); 470 dig=1; 471 args[argc+1]=0; 472 } else { 473 args[argc]=args[argc]*10+(int)(c-'0'); 474 if(argc==0) dig++; 475 } 476 } else bail_out(c); 477 } else bail_out(c); 478 break; 479 } 480} 481#endif 482 483static void 484vidc_putchar(int c) 485{ 486#ifdef TERM_EMU 487 vidc_term_emu(c); 488#else 489 vidc_rawputchar(c); 490#endif 491} 492 493static int 494vidc_getchar(void) 495{ 496 if (vidc_ischar()) { 497 v86.ctl = 0; 498 v86.addr = 0x16; 499 v86.eax = 0x0; 500 v86int(); 501 return(v86.eax & 0xff); 502 } else { 503 return(-1); 504 } 505} 506 507static int 508vidc_ischar(void) 509{ 510 v86.ctl = V86_FLAGS; 511 v86.addr = 0x16; 512 v86.eax = 0x100; 513 v86int(); 514 return(!(v86.efl & PSL_Z)); 515} 516 517#if KEYBOARD_PROBE 518 519#define PROBE_MAXRETRY 5 520#define PROBE_MAXWAIT 400 521#define IO_DUMMY 0x84 522#define IO_KBD 0x060 /* 8042 Keyboard */ 523 524/* selected defines from kbdio.h */ 525#define KBD_STATUS_PORT 4 /* status port, read */ 526#define KBD_DATA_PORT 0 /* data port, read/write 527 * also used as keyboard command 528 * and mouse command port 529 */ 530#define KBDC_ECHO 0x00ee 531#define KBDS_ANY_BUFFER_FULL 0x0001 532#define KBDS_INPUT_BUFFER_FULL 0x0002 533#define KBD_ECHO 0x00ee 534 535/* 7 microsec delay necessary for some keyboard controllers */ 536static void 537delay7(void) 538{ 539 /* 540 * I know this is broken, but no timer is available yet at this stage... 541 * See also comments in `delay1ms()'. 542 */ 543 inb(IO_DUMMY); inb(IO_DUMMY); 544 inb(IO_DUMMY); inb(IO_DUMMY); 545 inb(IO_DUMMY); inb(IO_DUMMY); 546} 547 548/* 549 * This routine uses an inb to an unused port, the time to execute that 550 * inb is approximately 1.25uS. This value is pretty constant across 551 * all CPU's and all buses, with the exception of some PCI implentations 552 * that do not forward this I/O adress to the ISA bus as they know it 553 * is not a valid ISA bus address, those machines execute this inb in 554 * 60 nS :-(. 555 * 556 */ 557static void 558delay1ms(void) 559{ 560 int i = 800; 561 while (--i >= 0) 562 (void)inb(0x84); 563} 564 565/* 566 * We use the presence/absence of a keyboard to determine whether the internal 567 * console can be used for input. 568 * 569 * Perform a simple test on the keyboard; issue the ECHO command and see 570 * if the right answer is returned. We don't do anything as drastic as 571 * full keyboard reset; it will be too troublesome and take too much time. 572 */ 573static int 574probe_keyboard(void) 575{ 576 int retry = PROBE_MAXRETRY; 577 int wait; 578 int i; 579 580 while (--retry >= 0) { 581 /* flush any noise */ 582 while (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) { 583 delay7(); 584 inb(IO_KBD + KBD_DATA_PORT); 585 delay1ms(); 586 } 587 588 /* wait until the controller can accept a command */ 589 for (wait = PROBE_MAXWAIT; wait > 0; --wait) { 590 if (((i = inb(IO_KBD + KBD_STATUS_PORT)) 591 & (KBDS_INPUT_BUFFER_FULL | KBDS_ANY_BUFFER_FULL)) == 0) 592 break; 593 if (i & KBDS_ANY_BUFFER_FULL) { 594 delay7(); 595 inb(IO_KBD + KBD_DATA_PORT); 596 } 597 delay1ms(); 598 } 599 if (wait <= 0) 600 continue; 601 602 /* send the ECHO command */ 603 outb(IO_KBD + KBD_DATA_PORT, KBDC_ECHO); 604 605 /* wait for a response */ 606 for (wait = PROBE_MAXWAIT; wait > 0; --wait) { 607 if (inb(IO_KBD + KBD_STATUS_PORT) & KBDS_ANY_BUFFER_FULL) 608 break; 609 delay1ms(); 610 } 611 if (wait <= 0) 612 continue; 613 614 delay7(); 615 i = inb(IO_KBD + KBD_DATA_PORT); 616#ifdef PROBE_KBD_BEBUG 617 printf("probe_keyboard: got 0x%x.\n", i); 618#endif 619 if (i == KBD_ECHO) { 620 /* got the right answer */ 621 return (0); 622 } 623 } 624 625 return (1); 626} 627#endif /* KEYBOARD_PROBE */ 628