Path: tut!enea!mcvax!uunet!husc6!bloom-beacon!tut.cis.ohio-state.edu!rutgers!aramis.rutgers.edu!athos.rutgers.edu!hedrick From: hedrick@athos.rutgers.edu (Charles Hedrick) Newsgroups: comp.os.minix Subject: ega fixes Message-ID: Date: 16 Aug 88 16:43:28 GMT Organization: Rutgers Univ., New Brunswick, N.J. Lines: 574 OK, I've had enough requests. This set of diffs is a mixed bag. It's all for support of the EGA card, in one way or another. One scrolling thing is in tty.c, and is commented in a fairly obvious way. In order to make it work automatically, I have to know whether you are using an EGA. The test is done in main.c, but requires a subroutine in klib88.s. (It uses a BIOS call. Apparently those have to be done early in main. When I tried it from tty.c, I got an error message. It appears that once minix is up, it's not valid to talk to the BIOS anymore.) In addition, there are the following changes: - don't wait for retrace to put data on the screen for an EGA. It's not needed. This is in klib88. - add an option to the startup menu (a space) specifying that you want special handling for the "extended" keyboard. Turns caps lock into control, reverses ESC and `, turns backspace into rubout. This is in fsck and tty - provide ESC codes to set colors. ESC [ 3x m and ESC [ 4 m set background and foreground colors (don't remember which is which). x is the usual IBM PC color code. - on color monitor, make more use of color. various of the codes that were there before now produce color changes. Also, normal text is now black on which instead of white on black. This is really a matter of personal taste. If you don't like it, don't use it. Changes are in tty.c and also klib88. The klib changes are needed because vid_copy has an option that says "clear this region to spaces". I have to choose the right kind of spaces. The patch to make hardware scrolling work for EGA has a slight sideeffect. Now and then there is a brief glitch on the screen. I suspect that the two register changes should be made during vertical retrace. This would mean adding somthing to klib88 that just waits for vertical retrace. I haven't had a chance to do it because I haven't figured out how to handle interrupts. In theory you'd like to disable interrupts, so that you don't wait for vertical retrace and get descheduled before you get a chance to do anything. But we certainly don't want to disable interrupts for that long. Chances are it would be OK just to do it with interrupts enabled. I think things are particularly bad because of the black on white. My suspicion is that for one refresh cycle part of the screen is being mapped to an area of the screen that is black. I suspect that this could be fixed by initializing the next page of the screen memory to white. I haven't had a chance to look at the code yet, but suspect that the line that does if (ega) vid_mask = .... could be changed to use C_VID_MASK rather than M_VID_MASK and that might be enough. My ega code doesn't use vid_mask at all, but I think it determines how much of the screen gets initialized. *** klib88.s.ORIG Thu Jan 1 00:10:10 1970 --- klib88.s Sat Aug 13 23:44:13 1988 *************** *** 25,36 **** .globl _phys_copy, _cp_mess, _port_out, _port_in, _lock, _restore .globl _build_sig, csv, cret, _get_chrome, _vid_copy, _get_byte, _reboot .globl _wreboot, _dma_read, _dma_write, _em_xfer, _scr_up, _scr_down | The following external procedure is called in this file. .globl _panic | Variables and data structures ! .globl _color, _cur_proc, _proc_ptr, splimit, _vec_table, _vid_mask |*===========================================================================* --- 25,37 ---- .globl _phys_copy, _cp_mess, _port_out, _port_in, _lock, _restore .globl _build_sig, csv, cret, _get_chrome, _vid_copy, _get_byte, _reboot .globl _wreboot, _dma_read, _dma_write, _em_xfer, _scr_up, _scr_down + .globl _get_ega | The following external procedure is called in this file. .globl _panic | Variables and data structures ! .globl _color, _cur_proc, _proc_ptr, splimit, _vec_table, _vid_mask, _ega |*===========================================================================* *************** *** 332,337 **** --- 333,355 ---- ret | monochrome return |*===========================================================================* + |* get_ega * + |*===========================================================================* + | This routine calls the BIOS to find out if the display is ega. This + | is needed because scrolling is different. + _get_ega: + movb bl,*0x10 + movb ah,*0x12 + int 0x10 | call the BIOS to get equipment type + + cmpb bl,*0x10 | if reg is unchanged, it failed + je notega + mov ax,#1 | color = 1 + ret | color return + notega: xor ax,ax | mono = 0 + ret | monochrome return + + |*===========================================================================* |* dma_read * |*===========================================================================* _dma_read: *************** *** 423,428 **** --- 441,448 ---- vid.1: test _color,*1 | skip vertical retrace test if display is mono jz vid.4 | if monochrome then go to vid.2 + test _ega,*1 | if ega also don't need to wait + jnz vid.4 |vid.2: in | with a color display, you can only copy to | test al,*010 | the video ram during vertical retrace, so *************** *** 465,470 **** --- 485,494 ---- ret | return to caller vid.7: mov ax,#BLANK | ax = blanking character + test _color,*1 | if color, use reverse vid + jz vid.8 | if monochrome then go to vid.8 + mov ax,#0x7000 + vid.8: rep | copy loop stow | blank screen jmp vid.5 | done *** main.c.ORIG Thu Jan 1 00:36:07 1970 --- main.c Sat Aug 13 22:00:27 1988 *************** *** 54,60 **** int stack_size; int * ktsb; /* kernel task stack base */ extern unsigned sizes[8]; /* table filled in by build */ ! extern int color, vec_table[], get_chrome(); extern int s_call(), disk_int(), tty_int(), clock_int(), disk_int(); extern int wini_int(), lpr_int(), trp(), rs232_int(), secondary_int(); extern phys_bytes umap(); --- 54,60 ---- int stack_size; int * ktsb; /* kernel task stack base */ extern unsigned sizes[8]; /* table filled in by build */ ! extern int color, ega, vec_table[], get_chrome(), get_ega(); extern int s_call(), disk_int(), tty_int(), clock_int(), disk_int(); extern int wini_int(), lpr_int(), trp(), rs232_int(), secondary_int(); extern phys_bytes umap(); *************** *** 141,146 **** --- 141,147 ---- /* Determine if display is color or monochrome and CPU type (from BIOS). */ color = get_chrome(); /* 0 = mono, 1 = color */ + ega = get_ega(); t = (int)get_byte(CPU_TY1, CPU_TY2) & 0xFF; /* is this PC, XT, AT ... ? */ if (t == PC_AT) pc_at = TRUE; *** tty.c.ORIG Thu Jan 1 00:36:21 1970 --- tty.c Sat Aug 13 21:20:41 1988 *************** *** 171,178 **** PRIVATE int softscroll = 0; /* 1 = software scrolling, 0 = hardware */ PRIVATE int output_done; /* number of RS232 output messages to be sent*/ PUBLIC int color; /* 1 if console is color, 0 if it is mono */ ! PUBLIC int scan_code; /* scan code for '=' saved by bootstrap */ ! /* Scan codes to ASCII for unshifted keys */ PRIVATE char unsh[] = { --- 171,179 ---- PRIVATE int softscroll = 0; /* 1 = software scrolling, 0 = hardware */ PRIVATE int output_done; /* number of RS232 output messages to be sent*/ PUBLIC int color; /* 1 if console is color, 0 if it is mono */ ! PUBLIC int ega; /* 1 if console is EGA, 0 if not */ ! PUBLIC int scan_code; /* scan code for '=' saved by bootstrap */ ! PUBLIC int ext_kbd = FALSE; /* TRUE if user wants fixups for ext kbd */ /* Scan codes to ASCII for unshifted keys */ PRIVATE char unsh[] = { *************** *** 194,199 **** --- 195,220 ---- '2','3','0','.' }; + /* Unshifted extended kbd */ + PRIVATE char unshx[] = { + 0,'`','1','2','3','4','5','6', '7','8','9','0','-','=',0177,'\t', + 'q','w','e','r','t','y','u','i', 'o','p','[',']',015,0202,'a','s', + 'd','f','g','h','j','k','l',';', 047,033,0200,0134,'z','x','c','v', + 'b','n','m',',','.','/',0201,'*', 0203,' ',0202,0241,0242,0243,0244,0245, + 0246,0247,0250,0251,0252,0205,0210,0267, 0270,0271,0211,0264,0265,0266,0214 + ,0261,0262,0263,'0',0177 + }; + + /* Shifted extended kbd */ + PRIVATE char shx[] = { + 0,033,'!','@','#','$','%','^', '&','*','(',')','_','+','\b','\t', + 'Q','W','E','R','T','Y','U','I', 'O','P','{','}',015,0202,'A','S', + 'D','F','G','H','J','K','L',':', 042,'~',0200,'|','Z','X','C','V', + 'B','N','M','<','>','?',0201,'*', 0203,' ',0202,0221,0222,0223,0224,0225, + 0226,0227,0230,0231,0232,0204,0213,'7', '8','9',0211,'4','5','6',0214,'1', + '2','3','0','.' + }; + /* Scan codes to ASCII for Olivetti M24 for unshifted keys. */ PRIVATE char unm24[] = { *************** *** 504,510 **** c = ch & 0177; /* high-order bit set on key release */ make = (ch & 0200 ? 0 : 1); /* 1 when key depressed, 0 when key released */ ! if (olivetti == FALSE) { /* Standard IBM keyboard. */ code = (shift1 || shift2 ? sh[c] : unsh[c]); if (control && c < TOP_ROW) code = sh[c]; /* CTRL-(top row) */ --- 525,538 ---- c = ch & 0177; /* high-order bit set on key release */ make = (ch & 0200 ? 0 : 1); /* 1 when key depressed, 0 when key released */ ! if (ext_kbd) { ! /* IBM "extended" kbd with ctrl and esc hard to find */ ! /* Standard IBM keyboard. */ ! code = (shift1 || shift2 ? shx[c] : unshx[c]); ! if (control && c < TOP_ROW) code = shx[c]; /* CTRL-(top row) */ ! if (c > 70 && numlock) /* numlock depressed */ ! code = (shift1 || shift2 ? unshx[c] : shx[c]); ! } else if (olivetti == FALSE) { /* Standard IBM keyboard. */ code = (shift1 || shift2 ? sh[c] : unsh[c]); if (control && c < TOP_ROW) code = sh[c]; /* CTRL-(top row) */ *************** *** 961,966 **** --- 989,995 ---- #define BLANK 0x0700 /* determines cursor color on blank screen */ #define LINE_WIDTH 80 /* # characters on a line */ #define SCR_LINES 25 /* # lines on the screen */ + #define SCR_BYTES 4000 /* # of bytes in RAM: LINE_WIDTH*SCR_LINES*2 */ #define CTRL_S 31 /* scan code for letter S (for CRTL-S) */ #define MONOCHROME 1 /* value for tty_ioport tells color vs. mono */ #define CONSOLE 0 /* line number for console */ *************** *** 980,988 **** --- 1009,1019 ---- #define EGA 0x3C0 /* port for EGA card */ #define INDEX 4 /* 6845's index register */ #define DATA 5 /* 6845's data register */ + #define OVRFL_REG 7 /* EGA overflow register */ #define CUR_SIZE 10 /* 6845's cursor size register */ #define VID_ORG 12 /* 6845's origin register */ #define CURSOR 14 /* 6845's cursor register */ + #define LINE_CMP 0x18 /* EGA line compare register */ /* Definitions used for determining if the keyboard is IBM or Olivetti type. */ #define KB_STATUS 0x64 /* Olivetti keyboard status port */ *************** *** 991,996 **** --- 1022,1028 ---- #define DELUXE 0x01 /* this bit is set up iff deluxe keyboard */ #define GET_TYPE 5 /* command to get keyboard type */ #define OLIVETTI_EQUAL 12 /* the '=' key is 12 on olivetti, 13 on IBM */ + #define SPACE_SCAN 57 /* a space */ /* Global variables used by the console driver. */ PUBLIC message keybd_mess; /* message used for console input chars */ *************** *** 1150,1155 **** --- 1182,1188 ---- scroll_screen(tp, GO_FORWARD); else tp->tty_row++; + move_to(tp, tp->tty_column, tp->tty_row); return; *************** *** 1205,1221 **** scr_down(vid_base); vid_copy(NIL_PTR, vid_base, tp->tty_org, LINE_WIDTH); } ! } else { ! /* Normal scrolling using the 6845 registers. */ ! amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH); ! tp->tty_org = (tp->tty_org + amount) & vid_mask; ! if (dir == GO_FORWARD) ! offset = (tp->tty_org + bytes) & vid_mask; else offset = tp->tty_org; /* Blank the new line at top or bottom. */ vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH); set_6845(VID_ORG, tp->tty_org >> 1); /* 6845 thinks in words */ } } --- 1238,1306 ---- scr_down(vid_base); vid_copy(NIL_PTR, vid_base, tp->tty_org, LINE_WIDTH); } ! } else if (ega) { ! int lines; ! /* ! * EGA scrolling. CGA and MDA scrolling is based on the fact ! * fact that the older adapters wrap around at 4K or whatever. ! * not all EGA's do. So instead we use the line compare ! * register. This is a scan line. Everything after this ! * line is displayed starting at the beginning of the display ! * RAM, ignoring the display start. So the top of the screen ! * starts whereover tty_org says it should in RAM. We compute ! * the scan line where the first page of RAM ends, and force ! * wraparound to the top using line compare. Since this uses ! * nothing beyond the first page of display RAM, and line ! * compare is a documented feature, it should work on all EGA ! * emulators. To keep arithmetic easier, we use a "page size" ! * of SCR_BYTES, which is exactly one screen full. ! */ ! ! amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH); ! tp->tty_org = (tp->tty_org + amount); /* top of screen in buffer */ ! if (tp->tty_org >= SCR_BYTES) /* see if we wrapped around */ ! tp->tty_org -= SCR_BYTES; ! else if (tp->tty_org < 0) /* wrap around the other way */ ! tp->tty_org += SCR_BYTES; ! if (dir == GO_FORWARD) { /* compute line to clear */ ! offset = tp->tty_org + bytes; ! if (offset >= SCR_BYTES) ! offset -= SCR_BYTES; ! } else offset = tp->tty_org; /* Blank the new line at top or bottom. */ vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH); + /* Tell the EGA what display memory to put at top of screen */ + set_6845(VID_ORG, tp->tty_org >> 1); /* 6845 thinks in words */ + /* Figure out where to wrap around to top of display mem */ + lines = tp->tty_org / (LINE_WIDTH * 2); /* convert to lines */ + lines = 14 * (SCR_LINES - lines) - 1; /* now to scan lines */ + /* 14 is scan lines per line of text. Ideally we should find + * a way to ask the display controller or the BIOS about this, */ + /* Now for the fun. Set the wraparound line. This is one of + * the wierd registers where the high-order bit is in the + * overflow register. Note that we're hardcoding the other bits + * in it. This is another potential problem if a new model needs + * extra bits. Unfortunately I couldn't figure out any way to + * read this register. */ + if (lines > 255) + setb6845(OVRFL_REG, 0x1f); /* high order bit is in overflow reg */ + else + setb6845(OVRFL_REG, 0x0f); /* high order bit 0 */ + setb6845(LINE_CMP, lines & 0xff); /* now set line compare reg */ + } else { + /* Normal scrolling using the 6845 registers. */ + amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH); + tp->tty_org = (tp->tty_org + amount) & vid_mask; + if (dir == GO_FORWARD) + offset = (tp->tty_org + bytes) & vid_mask; + else + offset = tp->tty_org; + + /* Blank the new line at top or bottom. */ + vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH); set_6845(VID_ORG, tp->tty_org >> 1); /* 6845 thinks in words */ } } *************** *** 1234,1239 **** --- 1319,1326 ---- /* Update the video parameters and cursor. */ tp->tty_vid = (tp->tty_vid + 2 * tp->tty_rwords); + if ((! softscroll) && ega && (tp->tty_vid >= SCR_BYTES)) + tp->tty_vid -= SCR_BYTES; set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */ tp->tty_rwords = 0; } *************** *** 1254,1259 **** --- 1341,1349 ---- tp->tty_column = x; /* set x co-ordinate */ tp->tty_row = y; /* set y co-ordinate */ tp->tty_vid = (tp->tty_org + 2*y*LINE_WIDTH + 2*x); + if ((! softscroll) && ega && (tp->tty_vid >= SCR_BYTES)) + tp->tty_vid -= SCR_BYTES; + set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */ } *************** *** 1364,1387 **** break; case 'm': /* Set graphic rendition */ switch (tp->tty_esc_parmv[0]) { ! case 1: /* BOLD (light green on black) */ ! tp->tty_attribute = 0x0A << 8; ! break; ! ! case 4: /* UNDERLINE (blue on red) */ ! tp->tty_attribute = 0x41 << 8; ! break; ! ! case 5: /* BLINKING (light grey on black) */ ! tp->tty_attribute = 0x87 << 8; break; case 7: /* REVERSE (black on light grey) */ ! tp->tty_attribute = 0x70 << 8; ! break; ! ! default: tp->tty_attribute = 0007 << 8; ! break; } break; default: --- 1454,1502 ---- break; case 'm': /* Set graphic rendition */ switch (tp->tty_esc_parmv[0]) { ! case 1: /* BOLD (red on white) */ ! if (color) ! tp->tty_attribute = 0x74 << 8; ! else ! tp->tty_attribute = 0x0f << 8; ! break; ! ! case 4: /* UNDERLINE (blue on white) */ ! if (color) ! tp->tty_attribute = 0x71 << 8; ! else ! tp->tty_attribute = 0x01 << 8; ! break; ! ! case 5: /* BLINKING */ ! if (color) ! tp->tty_attribute = 0xf0 << 8; ! else ! tp->tty_attribute = 0x87 << 8; break; case 7: /* REVERSE (black on light grey) */ ! if (color) ! tp->tty_attribute = 0x07 << 8; ! else ! tp->tty_attribute = 0x70 << 8; ! break; ! ! default: if (tp->tty_esc_parmv[0] >= 40 && ! tp->tty_esc_parmv[0] <= 47) ! tp->tty_attribute = ! (tp->tty_attribute & 0xf0ff) | ! ((tp->tty_esc_parmv[0] - 40) << 8); ! else if (tp->tty_esc_parmv[0] >= 30 && ! tp->tty_esc_parmv[0] <= 37) ! tp->tty_attribute = ! (tp->tty_attribute & 0x0fff) | ! ((tp->tty_esc_parmv[0] - 30) << 12); ! else if (color) ! tp->tty_attribute = 0x70 << 8; ! else ! tp->tty_attribute = 0x07 << 8; ! break; } break; default: *************** *** 1415,1421 **** port_out(vid_port + DATA, val&BYTE); /* output low byte */ } ! /*===========================================================================* * beep * *===========================================================================*/ --- 1530,1544 ---- port_out(vid_port + DATA, val&BYTE); /* output low byte */ } ! /* Similar, but used for registers where we only want to set one byte */ ! ! PRIVATE setb6845(reg, val) ! int reg; /* which register pair to set */ ! int val; /* 16-bit value to set it to */ ! { ! port_out(vid_port + INDEX, reg); /* set the index register */ ! port_out(vid_port + DATA, val); /* output high byte */ ! } /*===========================================================================* * beep * *===========================================================================*/ *************** *** 1480,1486 **** tp->tty_mode = CRMOD | XTABS | ECHO; tp->tty_devstart = console; tp->tty_makebreak = TWO_INTS; ! tp->tty_attribute = BLANK; tp->tty_erase = ERASE_CHAR; tp->tty_kill = KILL_CHAR; tp->tty_intr = INTR_CHAR; --- 1603,1612 ---- tp->tty_mode = CRMOD | XTABS | ECHO; tp->tty_devstart = console; tp->tty_makebreak = TWO_INTS; ! if (color) ! tp->tty_attribute = 0x7000; ! else ! tp->tty_attribute = BLANK; tp->tty_erase = ERASE_CHAR; tp->tty_kill = KILL_CHAR; tp->tty_intr = INTR_CHAR; *************** *** 1501,1506 **** --- 1627,1635 ---- vid_port = M_6845; vid_retrace = M_RETRACE; } + + if (ega) + vid_mask = M_VID_MASK; tty_driver_buf[1] = MAX_OVERRUN; /* set up limit on keyboard buffering*/ set_6845(CUR_SIZE, 31); /* set cursor shape */ set_6845(VID_ORG, 0); /* use page 0 of video ram */ *************** *** 1511,1516 **** --- 1640,1646 ---- * keyboard in use. */ if (scan_code == OLIVETTI_EQUAL) olivetti = TRUE; + if (scan_code == SPACE_SCAN) ext_kbd = TRUE; } *************** *** 1547,1552 **** --- 1677,1689 ---- tty_struct[0].tty_org = 0; move_to(&tty_struct[0], 0, SCR_LINES-1); /* cursor to lower left */ set_6845(VID_ORG, 0); + if (ega) { + /* If EGA, we use the funny line compare reg for scrolling. Reinit it. + * see comments in scroll code. */ + setb6845(OVRFL_REG, 0x1f); + setb6845(LINE_CMP, 0xff); + } + if (softscroll) printf("\033[H\033[JSoftware scrolling enabled.\n"); else *** fsck.c.ORIG Thu Jan 1 00:43:32 1970 --- fsck.c Sat Aug 13 20:36:39 1988 *************** *** 1851,1856 **** --- 1851,1857 ---- printf(" l check and list file system (first insert any file system diskette)\n"); printf(" m make an (empty) file system (first insert blank, formatted diskette)\n"); printf(" h check hard disk file system\n"); + printf(" to start MINIX with extended keyboard\n"); printf("\n# "); c = getc(); command = c & 0xFF; *************** *** 1895,1900 **** --- 1896,1902 ---- } break; + case ' ': case '=': return((c >> 8) & 0xFF); default: printf("Illegal command\n");