johnc@rtmvax.UUCP (John Connin) (01/20/88)
;> From: ast@cs.vu.nl (Andy Tanenbaum) ;> Newsgroups: comp.os.minix ;> Subject: Problems with Jim Paradis' tty driver ;> Date: 15 Jan 88 14:33:17 GMT ;> ;> "If any one has any observations, comments etc., please post them." For openers, I am relatively new (thus unexperienced) to usenet and real *nix in general. However, I am posting the enclosed fragments in the hope that it will contribute to a "definitive" version of Jim Paradis' tty driver. The components of this document are: serial2.jlc this document scrblank.asm a klib88 function scrmove.asm another klib88 function ttyv2.c lower half of a tty driver Because of time, both mine and the urgency I perceived expressed in the above request, I have not included a full and clean driver. Rather, I have enclosed some code fragments which I have incorporated into my tty driver to support MicroEmacs V3.9e. John L. Connin UUCP: codas!alxfin!rtmvax!johnc - - - - - - - - The following is a shar archive - - - - - - - - - - - - #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # serial.jlc # scrblank.asm # scrmove.asm # ttyv2.c # This archive created: Sun Jan 17 15:29:18 1988 export PATH; PATH=/bin:$PATH if test -f 'serial.jlc' then echo shar: will not over-write existing file "'serial.jlc'" else sed 's/^X//' << \SHAR_EOF > 'serial.jlc' X XThis note is in response to the following AST - comp.os.minix request: X X ;> From: ast@cs.vu.nl (Andy Tanenbaum) X ;> Newsgroups: comp.os.minix X ;> Subject: Problems with Jim Paradis' tty driver X ;> Date: 15 Jan 88 14:33:17 GMT X ;> X ;> "If any one has any observations, comments etc., please post them." X XFor openers, I am relatively new (thus unexperienced) to usenet and Xreal *nix in general. However, I am posting the enclosed fragments in Xthe hope that it will contribute to a "definitive" version of Jim Paradis' Xtty driver. X XThe components of this document are: X X serial2.jlc this document X scrblank.asm a klib88 function X scrmove.asm another klib88 function X ttyv2.c lower half of a tty driver X X XBecause of time, both mine and the urgency I perceived expressed in Xthe above request, I have not included a full and clean driver. Rather, XI have enclosed some code fragments which I have incorporated into Xmy tty driver to support MicroEmacs V3.9e. X X XStarting at the bottom, the function scr_move() and scr_blank() generally Xreplace the klib88.asm functions scr_up() and scr_down(). X X scr_move move a region of the screen X X scr_move(base,rct,cct,rinc,to,fr,base) X int base, address of display page X rct, row count X cct, character count X rinc; row increment X char *to, *fr; from-to address within screen page X X X 'rct' rows of 'cct' characters are scrolled. 'to' and 'fr' are the X initial source and destination pointers respectively. 'rinc' is added X to the updated values of 'to' and 'fr' after each 'cct' characters. X Nothing is returned. X X X X scr_blank blank a region of the screen X X scr_blank(base,rct,cct,rinc,s,a) X int base, address of display page X rct, row count X cct, character count X rinc; row increment X char *s, start address within screen page X a; blanking attribute. X X 'rct' rows of 'cct' characters are blanked. 'a' is non-zero for an X attribute display, in which case it is the attribute. 's' is the X initial address. 'rinc' is added to the updated 's' after every X 'cct' characters. Nothing is returned. X X XThe next level up is scroll_window() which generally replaces the function Xscroll_screen(). Perhaps a more descriptive name would be scroll_region(). XThe C source for scroll_window is contained in ttyv2.c.. X X X scroll_window() scroll window X X scroll_window(tp,rs,cs,re,ce,lc,dr) X struct tty_struct *tp; active tty console X int rs,cs, north-west corner scroll region X re,ce; south-east corner scroll region X int lc; number of lines to scroll X int dr; direction to scroll X X A region in the tty display 'tp' is scrolled. 'rs' and 'cs' is the X starting row and column (nw). 're' and 'ce' is the ending (se) row X and column. 'lc' is the number of lines to scroll. 'dr' is the X direction, which is either SCROLL_UP or SCROLL_DOWN. If lc is 0 X clear (blank) the entire window. X X Calls upon scr_bank() and scr_move() for support which are written X in ASM. X X XThe balance of the code included (ie. ttyv2.c ) generally relates to Xchanges in escape() and do_escape() to incorporate the above functions Xand expand the ansi escape sequences to approximately those of ANSI.SYS Xunder MSDOS including color screen rendition. NB. If any of the ttyv2 Xcode is used, it will need to be cleaned up.. X XBefore I mention some additional thoughts on the tty implementation, Xperhaps it would be best to articulate my idea of a feature set Xfor the 'definitive' tty-serial driver -- in which features could Xobviously be controlled by #ifdefs': X X o a robust subset of ANSI including color rendition, X screen only (see comment below re: keyboard). X o multiple virtual terminals ( 4 is my preference ).. X o multiple display terminals ( 2 ) selected via alt key sequence X o multiple rs232 ports ( 2 - 4), MUST support least 2400 baud X o view / set rs232 parameters via alt key sequence X o a status line X o mini-debugger with screen window, access via alt key sequence X o ... X XOf course it is probably not feasible to incorporate all the above Xthe first time out of the box, however, it is nice to know where you Xare headed before you embark on a trip. In any event, in my view of XMinix and by default the tty-serial driver is that it should be Xpositioned as a single-user screen oriented system, with Version 7 Xcompatibility. Off the soap-box and back to matters at hand. X XConcerning virtual terminal implementation, it appears to me that the Xcleanest implementation uses one display page per virtual screen Xas follows: X X X +----------------+ <-- tty_org virtual screen 0 X | | X | display | X | page 0 | X +----------------+ <-- tty_org virtual screen 1 X | | X | display | X | page 1 | X +----------------+ X .... X +----------------+ <-- tty_org virtual screen n X | | X | display | X | page n | X +----------------+ X X 1. Initialization stores base address of display page assigned to X each tty structure. X X 2. To switch virtual screens, set the 6845 controller base to X the display page base address contained in the corresponding X tty structure. X X 3. Require that all screen write functions be relative the the X display page base address. X XThis scheme results in compact clean code with or without virtual Xterminals and multiple displays. Off hand I see no reason why the above Xmethodology should not work well with any MONO, CGA, EGA or other cards X-- I know it works well with my Hercules and EGA clone, but have no Xexperience with CGA. X XNow for a related but different subject -- which my background may be Xa little thin. It seems to me that the ansi keyboard escape sequences Xmake both the tty driver and application code overly complex. Rather Xwhy not use an implementation similar to that employed in MicroSoft C. XIf the keystroke is a regular key (ie. scan == 0), merely return the Xcharacter. if the keystroke is an extended key (ie scan != 0), on the Xfirst read return NULL and then return the scan code on the next read. XThis leads to clean code in both the driver and application: X X getkey() X { X int c; X X c = getch(); /* read keyboard */ X X if (c == 0) /* check for extended key */ X c = getch() | SPEC; /* get scan code */ X return( c ); X } X X XLastly on an entirely different subject. My memory may be a little dim Xon the details, since it has been some time since I discovered this bug, Xbut the function set_name() can cause a segment limit to be violated. XIn the protected mode, the bug is very apparent since it causes a general Xprotection exception. X XThe function do_exec() calls set_name() to establish the physical address Xof the command line for display purposes by the process dump. It is Xpossible that the physical addr of vargv + NSIZE may exceed the segment limit. XThe solution I implemented within set_name() is: X X from: X X dst = umap(proc_addr(SYSTASK), D, &vargv, 2); X phys_copy(src, dst, 2L); X X aout[ proc_nr] = umap(proc_addr(proc_nr), D, vargv, NSIZE); X X to: X X dst = umap(proc_addr(SYSTASK), D, (vir_bytes) &vargv, 2); X phys_copy(src, dst, 2L); X X limit = get_limit(proc_addr(proc_nr), S); /* to avoid seg violation */ X nsize = MIN( (limit - vargv),NSIZE ); X X aout[ proc_nr] = umap(proc_addr(proc_nr), S, vargv, nsize); X Xwhere get_limit() returns the segment limit for the designated segment Xand task. There may be more to it. As I indicated, it has been a long Xtime since I worked over this area, and the above code was all that I could Xfind which contained a mention to the problem/fix. In any event, I can Xassure you the bug is real, but apparently benign in the real mode. X X XI trust the above is responsive to the request and helpful in establishing Xa "definitive" new tty-serial driver. X X John L. Connin 01/16/88 X X XPS. X I have just recently been look at simulating 'expanded memory' X with 'extended memory' under MSDOS. It occurred to me that it X should be reasonable to incorporate mechanisms within the kernel X for managing expanded memory and / or the simulation of expanded X memory with extended memory. X XPASS. X Are there any plans for, or has anyone implemented, other memory X models. A compact and large memory model would sure open up many X doors. In any event, it would be helpful if a target executable X binary file format could be defined (standardized) at this time. X X X X SHAR_EOF fi # end of overwriting check if test -f 'scrblank.asm' then echo shar: will not over-write existing file "'scrblank.asm'" else sed 's/^X//' << \SHAR_EOF > 'scrblank.asm' X X; @ab equ 4 ; Small memory model X X;-------------------------------------------------------------------- X; X; scr_blank blank display area X; X; scr_blank(base,rct,cct,rinc,s,a) X; int base,rct,cct,rinc; X; char *s, a; X; X; rct rows of cct characters are blanked. 'a' is non-zero for an attribute X; display, in which case it is the attribute. s is the initial address. X; rinc is added to the updated s after every cct characters. X; Nothing is returned. X; X X_scr_blank: X ; X enter 0, 0 ; X pusha ; X push es ; X push ds ; X pushf ; copying may now start; save flags X cli ; interrupts just get in the way: disable them X ; X#ifdef REAL_MODE X X mov ax, GDT_SEL ; Address video GDT segment descriptor X mov es, ax ; es:di X mov di, VIDEO1SEL ; X ; X mov ax, @ab[bp] ; video base (clicks) X mov cx, 16 ; convert to phys_bytes X mul cx ; X ; X mov es:[di].sd_lowbase, ax ; Set descriptor to video buffer segment X mov es:[di].sd_hibase, dl ; X mov es:[di].sd_limit, VIO_BUF_SZ ; X mov es:[di].sd_access, ACC_KDATA ; X X mov ax, VIDEO1SEL ; Address video buffer segment X mov es, ax ; X mov ds, ax ; X#else X ; X mov ax, @ab[bp] ; video base X mov ds, ax ; X mov es, ax ; X#endif X ; X mov di, @ab[bp + 8] ; set destination address X mov ah, @ab[bp + 10] ; set attribute X mov al,' ' ; set blank X mov bx, @ab[bp + 2] ; set row count X mov dx, @ab[bp + 6] ; set address increment X ; X cld ; Xscrbl1: ; X dec bx ; * test for blanking complete X jl scrbl4 ; * X mov cx,@ab[bp + 4] ; set character count X test ah,ah ; ** test for attribute display X jnz scrbl2 ; ** X rep stosb ; blank non-attribute row al -> es:[di] X jmp short scrbl3 ; continue Xscrbl2: ; X rep stosw ; blank attribute row ax -> es:[di] Xscrbl3: ; X add di,dx ; advance destination address X jmp scrbl1 ; continue X ; Xscrbl4: ; X popf ; restore flags X pop ds ; restore ds X pop es ; restore es X popa ; X leave ; X ret ; return to caller X SHAR_EOF fi # end of overwriting check if test -f 'scrmove.asm' then echo shar: will not over-write existing file "'scrmove.asm'" else sed 's/^X//' << \SHAR_EOF > 'scrmove.asm' X X; @ab equ 4 ; Small memory model X X;-------------------------------------------------------------------- X; scr_move move display area X; X; scr_move(base,rct,cct,rinc,to,fr,base) X; int base,rct,cct,rinc; X; char *to, *fr; X; X; rct rows of cct characters are scrolled. to and fr are the initial X; source and destination pointers respectively. rinc is added to X; the updated values of to and fr after each cct characters. X; Nothing is returned. X; X X_scr_move: X ; X enter 0, 0 ; X pusha ; X push es ; X push ds ; X pushf ; copying may now start; save flags X cli ; interrupts just get in the way: disable them X X#ifdef REAL_MODE X ; X mov ax, @ab[bp] ; video base X mov ds, ax ; X mov es, ax ; X#else X X mov ax, GDT_SEL ; Address video GDT segment descriptor X mov es, ax ; es:di X mov di, VIDEO1SEL ; X ; X mov ax, @ab[bp] ; video base (clicks) X mov cx, 16 ; convert to phys_bytes X mul cx ; X X mov es:[di].sd_lowbase, ax ; Set descriptor to video buffer segment X mov es:[di].sd_hibase, dl ; X mov es:[di].sd_limit, VIO_BUF_SZ ; X mov es:[di].sd_access, ACC_KDATA ; X X mov ax, VIDEO1SEL ; Address video buffer segment X mov es, ax ; X mov ds, ax ; X#endif X ; X mov si, @ab[bp + 10] ; set source address X mov di, @ab[bp + 8] ; set destination address X mov bx, @ab[bp + 2] ; set row count X mov dx, @ab[bp + 6] ; set address increment X ; X cld ; Xscrmv1: ; X dec bx ; * test for transfer complete X jl scrmv2 ; * X mov cx, @ab[bp + 4] ; set character count X rep movsb ; move row ds:[si] -> es:[di] X add si,dx ; advance source address X add di,dx ; advance destination address X jmp scrmv1 ; continue X ; Xscrmv2: ; X ; X popf ; restore flags X pop ds ; restore ds X pop es ; restore es X popa ; X leave ; X ret ; return to caller X X SHAR_EOF fi # end of overwriting check if test -f 'ttyv2.c' then echo shar: will not over-write existing file "'ttyv2.c'" else sed 's/^X//' << \SHAR_EOF > 'ttyv2.c' X X X#ifdef i8088 X/* Now begins the code and data for the device-dependent tty drivers. */ X X /* Definitions used by the console driver. */ X X#define NROWS 25 /* Number or row on system console */ X#define NCOLS 80 /* Number of cols on system console */ X#define COLOR_BASE 0xB800 /* video ram paragraph for color display */ X#define MONO_BASE 0xB000 /* video ram address for mono display */ X#define C_VID_MASK 0x7FFF /* mask for 16K video RAM */ X#define M_VID_MASK 0x0FFF /* mask for 4K video RAM */ X#define C_RETRACE 0x0300 /* how many characters to display at once */ X#define M_RETRACE 0x7000 /* how many characters to display at once */ X#define WORD_MASK 0xFFFF /* mask for 16 bits */ X#define OFF_MASK 0x000F /* mask for 4 bits */ X#define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */ X#define B_TIME 0x2000 /* how long to sound the CTRL-G beep tone */ X#define BLANK 0x0007 /* screen blanking attribute */ X#define LINE_WIDTH 80 /* # characters on a line */ X#define SCR_LINES 25 /* # lines on the screen */ X#define CTRL_S 31 /* scan code for letter S (for CRTL-S) */ X#define MONOCHROME 1 /* value for tty_ioport tells color vs. mono */ X#define CONSOLE 0 /* line number for console */ X#define GO_FORWARD 0 /* scroll forward */ X#define GO_BACKWARD 1 /* scroll backward */ X#define SCROLL_UP GO_FORWARD /* */ X#define SCROLL_DW GO_BACKWARD /* */ X#define TIMER2 0x42 /* I/O port for timer channel 2 */ X#define TIMER3 0x43 /* I/O port for timer channel 3 */ X#define KEYBD 0x60 /* I/O port for keyboard data */ X#define PORT_B 0x61 /* I/O port for 8255 port B */ X#define KBIT 0x80 /* bit used to ack characters to keyboard */ X X /* Constants relating to the video RAM and 6845. */ X X#define M_6845 0x3B0 /* port for 6845 mono */ X#define C_6845 0x3D0 /* port for 6845 color */ X#define EGA 0x3C0 /* port for EGA card */ X#define INDEX 4 /* 6845's index register */ X#define DATA 5 /* 6845's data register */ X#define CUR_SIZE 10 /* 6845's cursor size register */ X#define VID_ORG 12 /* 6845's origin register */ X#define CURSOR 14 /* 6845's cursor register */ X X/* Definitions used for determining if the keyboard is IBM or Olivetti type. */ X X#define KB_STATUS 0x64 /* Olivetti keyboard status port */ X#define BYTE_AVAIL 0x01 /* there is something in KEYBD port */ X#define KB_BUSY 0x02 /* KEYBD port ready to accept a command */ X#define DELUXE 0x01 /* this bit is set up iff deluxe keyboard */ X#define GET_TYPE 5 /* command to get keyboard type */ X#define OLIVETTI_EQUAL 12 /* the '=' key is 12 on olivetti, 13 on IBM */ X X /* Global variables used by the console driver. */ X XPUBLIC message keybd_mess; /* message used for console input chars */ XPRIVATE vid_retrace; /* how many characters to display per burst */ XPRIVATE unsigned vid_base; /* base of video ram (0xB000 or 0xB800) */ XPUBLIC int vid_mask; /* 037777 for color (16K) or 07777 for mono */ XPRIVATE int vid_port; /* I/O port for accessing 6845 */ X X X/*===================================================================== X keyboard() X X A keyboard interrupt has occurred. Process it. X=====================================================================*/ X XPUBLIC keyboard() X{ X int val, code, k, raw_bit; X char stopc; X X /* Fetch the character from the keyboard hardware and acknowledge it. */ X X port_in(KEYBD, &code); /* get the scan code for the key struck */ X port_in(PORT_B, &val); /* strobe the keyboard to ack the char */ X port_out(PORT_B, val | KBIT); /* strobe the bit high */ X port_out(PORT_B, val); /* now strobe it low */ X X /* The IBM keyboard interrupts twice per key, once when depressed, once when X * released. Filter out the latter, ignoring all but the shift-type keys. X * The shift-type keys, 29, 42, 54, 56, 58, and 69 must be processed normally. X */ X X k = code - 0200; /* codes > 0200 mean key release */ X if (k > 0) X { /* A key has been released. */ X X if (k != 29 && k != 42 && k != 54 && k != 56 && k != 58 && k != 69) X { X port_out(INT_CTL, ENABLE); /* re-enable interrupts */ X return; /* don't call tty_task() */ X } X } X else X { X /* Check to see if character is CTRL-S, to stop output. Setting xoff X * to anything other than CTRL-S will not be detected here, but will X * be detected later, in the driver. A general routine to detect any X * xoff character here would be complicated since we only have the X * scan code here, not the ASCII character. X */ X X raw_bit = tty_struct[ tty_line].tty_mode & RAW; X stopc = tty_struct[ tty_line].tty_xoff; X X if (raw_bit == 0 && control && code == CTRL_S && stopc == XOFF_CHAR) X { X tty_struct[ tty_line].tty_inhibited = STOPPED; X port_out(INT_CTL, ENABLE); X return; X } X } X X /* X * Check for CTRL-ALT-DEL, and if found, reboot the computer. X */ X X if (control && alt && code == DEL_CODE) reboot(); /* CTRL-ALT-DEL */ X X /* X * Store the character in memory so the task can get at it later. X */ X X if ( (k = tty_driver_buf[ 0]) < tty_driver_buf[ 1]) X { X /* There is room to store this character; do it. */ X k = k + k; /* each entry contains two bytes */ X tty_driver_buf[ k+2] = code; /* store the scan code */ X tty_driver_buf[ k+3] = tty_line; X tty_driver_buf[ 0]++; /* increment counter */ X X /* Build and send the interrupt message. */ X X keybd_mess.m_type = TTY_CHAR_INT; X keybd_mess.ADDRESS = tty_driver_buf; X interrupt(TTY, &keybd_mess); /* send a message to the tty task */ X } X else X { X /* Too many characters have been buffered. Discard excess. */ X X port_out(INT_CTL, ENABLE); /* re-enable 8259A controller */ X } X} X X X/*========================================================================== X console() X X Copy as much data as possible to the output queue, then start I/O. X On memory-mapped terminals, such as the IBM console, the I/O will X also be finished, and the counts updated. Keep repeating until all X I/O done. X===========================================================================*/ X XPRIVATE console(tp) Xregister struct tty_struct *tp; /* tells which terminal is to be used */ X{ X int count; X char c; X#ifdef REAL_MODE X unsigned segment, offset, offset1; X#else X seg_desc far *copy_dsc; X vir_bytes limit, offset, offset1; X phys_bytes base; X unsigned segment; X extern seg_desc far *gdt; X#endif X X /* -- Loop over the user bytes one at a time, outputting each one. -- */ X X#ifdef REAL_MODE X segment = (tp->tty_phys >> 4) & WORD_MASK; X offset = tp->tty_phys & OFF_MASK; X#else X base = tp->tty_phys & 0x00FFFFF0L; X offset = (vir_bytes) *((unsigned *) &(tp->tty_phys)) & OFF_MASK; X limit = offset + tp->tty_outleft; X X copy_dsc = gdt + COPYIN_SLOT; X lock(); /* lock out another proc from changing copyin descriptor */ X open_seg(copy_dsc,base,limit,ACC_KDATA); X segment = COPYIN_SEL; X X#endif X X offset1 = offset; X count = 0; X X while (tp->tty_outleft > 0 && tp->tty_inhibited == RUNNING) X { X c = get_byte(segment, offset); /* fetch 1 byte from user space */ X out_char(tp, c); /* write 1 byte to terminal */ X offset++; /* advance one char in user buffer */ X tp->tty_outleft--; /* decrement count */ X } X#ifndef REAL_MODE X restore(); X#endif X X flush(tp); /* clear out the pending characters */ X X /* -- Update terminal data structure. -- */ X X count = offset - offset1; /* # characters printed */ X tp->tty_phys += count; /* advance physical data pointer */ X tp->tty_cum += count; /* number of characters printed */ X X /* -- If all data has been copied to the terminal, send the reply. -- */ X X if (tp->tty_outleft == 0) finish(tp, tp->tty_cum); X} X X X/*========================================================================== X out_char() X X Output a character on the console. Check for escape sequences first. X===========================================================================*/ X XPRIVATE out_char(tp, c) Xregister struct tty_struct *tp; /* pointer to tty struct */ Xchar c; /* character to be output */ X{ X int attr; X X /* Check to see if we are part way through an escape sequence. */ X X if (tp->tty_esc_state > 0) X { parse_escape(tp, c); return; } X X switch (c) X { X case 007: /* ring the bell */ X flush(tp); /* print any chars queued for output */ X beep(BEEP_FREQ); /* BEEP_FREQ gives bell tone */ X return; X X case 013: /* CTRL-K */ X move_to(tp, tp->tty_column, tp->tty_row - 1); X return; X X case 014: /* CTRL-L */ X move_to(tp, tp->tty_column + 1, tp->tty_row); X return; X X case 016: /* CTRL-N */ X move_to(tp, tp->tty_column + 1, tp->tty_row); X return; X X case '\b': /* backspace */ X move_to(tp, tp->tty_column - 1, tp->tty_row); X return; X X case '\n': /* line feed */ X if (tp->tty_mode & CRMOD) out_char(tp, '\r'); X if (tp->tty_row == SCR_LINES-1) X scroll_window(tp,0,0,tp->tty_nrow-1,tp->tty_ncol-1,1,SCROLL_UP); X else X tp->tty_row++; X move_to(tp, tp->tty_column, tp->tty_row); X return; X X case '\r': /* carriage return */ X move_to(tp, 0, tp->tty_row); X return; X X case '\t': /* tab */ X if ( (tp->tty_mode & XTABS) == XTABS) X { X do X { X out_char(tp, ' '); X } X while (tp->tty_column & TAB_MASK); X return; X } X X /* Ignore tab if XTABS is off--video RAM has no hardware tab */ X X return; X X case 033: /* ESC - start of an escape sequence */ X flush(tp); /* print any chars queued for output */ X tp->tty_esc_state = 1; /* mark ESC as seen */ X return; X X default: /* printable chars are stored in ramqueue */ X attr = (tp->tty_attribute << 8); X if (tp->tty_column >= LINE_WIDTH) return; /* long line */ X if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp); X tp->tty_ramqueue[ tp->tty_rwords++] = attr | (c & BYTE); X tp->tty_column++; /* next column */ X X return; X } X} X X X/*------------------------------------------------------------------- X X scroll_window scroll window X X The tty display 'tp' is scrolled. rs and cs is the starting X row and column (ne). re and ce is the ending (sw) row and column. X lc is the number of lines to scroll. dr is the direction, which is X either SCROLL_UP or SCROLL_DOWN. X X <----- rsz --------------> X +---------------------------+ X | | <- rinc -> | X | +----------+ | X | | region | | X | | | | X | +----------+ | X | screen | X +---------------------------+ X X Calls upon scr_bank() and scr_move() with are written in ASM. X-------------------------------------------------------------------*/ X Xscroll_window(tp,rs,cs,re,ce,lc,dr) Xstruct tty_struct *tp; Xint rs,cs,re,ce; Xint lc; Xint dr; X{ X int wcs,wcl; /* adjusted column start, column length */ X int rl, cl; /* row and col limits */ X int rsz,rinc; /* row size, increment */ X char a; /* attribute byte */ X int af; /* attribute flag */ X uint f, t; /* character offsets */ X uint vbase; /* video base */ X X af = TRUE; /* set attribute flag - keep for generality */ X vbase = vid_base + (tp->tty_org >> 4); X X rl = re + 1; /* compute row/col limits */ X cl = ce + 1; X X if (lc >= rl) lc = 0; /* test for entire screen scroll (clear) */ X X if (af) /* test for attribute display */ X { X rsz = 2*tp->tty_ncol; /* set row size */ X wcs = 2*cs; /* adjust column start */ X wcl = 2*cl; /* adjust column limit */ X a = tp->tty_attribute; /* set attrubute */ X } X else /* not attribute display */ X { X rsz = tp->tty_ncol; /* set row size */ X wcs = cs; /* set column start */ X wcl = cl; /* set column limit */ X a = 0x07; X } X X rinc = rsz - (wcl - wcs); /* set row increment, case SUP and CLR */ X X if (lc > 0) /* test for transfer required */ X { X if (dr == SCROLL_UP) /* test for scroll up */ X { X t = rs*rsz + wcs; /* set "to" address */ X f = t + (lc*rsz); /* set "from" address */ X X scr_move(vbase, (rl-rs)-lc, (wcl-wcs), rinc, t, f); X rs = rl - lc; /* adj row start for blanking */ X } X else /* scroll down */ X { X rinc = -(rsz +(wcl-wcs)); /* set NEGATIVE row increment */ X t = (re * rsz) + wcs; /* set "to" address */ X f = t - (lc * rsz); /* set "from" address */ X scr_move(vbase, (rl-rs)-lc, (wcl-wcs), rinc, t, f ); X X rl = rs + lc; /* adjust row limit for blanking */ X rinc = rsz - (wcl - wcs); /* blank from top down */ X } X } X X f = (rs*rsz) + wcs; /* set character address */ X /* blank display, NB char */ X scr_blank(vbase,(rl-rs),(cl-cs),rinc,f,a); /* count w/o attribute */ X X} X X X/*========================================================================== X flush() X X Have the characters in 'ramqueue' transferred to the screen. X===========================================================================*/ X XPRIVATE flush(tp) Xregister struct tty_struct *tp; /* pointer to tty struct */ X{ X unsigned int video_base; X X if (tp->tty_rwords == 0) return; X X video_base = vid_base + (tp->tty_org >> 4); X X vid_copy(tp->tty_ramqueue, video_base, tp->tty_vid, tp->tty_rwords); X X /* -- Update the video parameters and cursor. -- */ X X tp->tty_vid = (tp->tty_vid + 2 * tp->tty_rwords); X X if (tp == current_tp) X set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */ X X tp->tty_rwords = 0; X} X X X/*===================================================================== X move_to() X X Move the cursor to (x, y). X=====================================================================*/ X XPRIVATE move_to(tp, x, y) Xstruct tty_struct *tp; /* pointer to tty struct */ Xint x; /* column (0 <= x <= 79) */ Xint y; /* row (0 <= y <= 24, 0 at top) */ X{ X flush(tp); /* flush any pending characters */ X X if (x < 0 || x >= LINE_WIDTH || y < 0 || y >= SCR_LINES) return; X X tp->tty_column = x; /* set x co-ordinate */ X tp->tty_row = y; /* set y co-ordinate */ X tp->tty_vid = (tp->tty_org + 2*y*LINE_WIDTH + 2*x); X X if (tp == current_tp) X set_6845(CURSOR, tp->tty_vid >> 1); /* cursor counts in words */ X} X X X/*===================================================================== X escape() X X Handle an escape sequence. X X The following ANSI escape sequences are currently supported: X ESC M to reverse index the screen X ESC [ y ; x H to move cursor to (x, y) [default (1,1)] X ESC [ 0 J to clear from cursor to end of screen X ESC [ n m to set the screen rendition X n: 0 = normal [default] X 7 = reverse X X ANSI standard escape sequences are: X <ESC> [ <n> Z -Backtab - Move left n tabstops (default 1) X <ESC> [ <n> } -Change window (range 0-15, default 0) X <ESC> c -Clear all, reset terminal X <ESC> [ <n> B -Cursor down n lines (default 1) X <ESC> [ <n> G -Move cursor to column n (default 1) of line X <ESC> [ <n> D -Move cursor left n colums (default 1) X <ESC> [ <n> E -Move cursor to first column, down n lines(1) X <ESC> [ <n> F -Move cursor to first column, up n lines (1) X <ESC> [ <n> C -Move cursor right n columns (default 1) X <ESC> [ <n> A -Move cursor up n lines (default 1) X <ESC> [ <n> P -Deletes n characters (1) starting from current X <ESC> [ <n> M -Deletes n lines (1) from current & scrolls blanks X into bottom of screen X <ESC> [ c -Send terminal identification string X <ESC> [ <n> X -Erase n character positions (1) starting at current X <ESC> [ <n> K -Erase to end of line (n=0, default), from beginnning X (n=1), or entire line if n=2. X <ESC> [ <n> J -Erase to end of window (n=0), from beginning of X window (n=1), and entire window if n=2. X <ESC> [<font><blank> D -Change font (see documentation for font. X <ESC> o -Graphics shift (see documentation) X <ESC> [ <n> I -Move n tabstops to right (default 1). X <ESC> [ <n> L -Insert n blank lines (default 1) before current X <ESC> [ <n> @ -Insert n spaces (default 1) at current position X <ESC> ' -Keyboard lock X <ESC> b -Keyboard unlock X <ESC> [ <n>;<m>; ...u -Remote configuration X <ESC> [ <n>;<m> H -Position cursor to line n, column m X <ESC> [ <n> T -Scroll current window down n lines (default 1) X <ESC> [ <n><blank> @ -Scroll current window left n columns X <ESC> [ <n><blank> A -Scroll current window right n columns X <ESC> [ <n> S -Scroll current window up n lines X <ESC> [ <n> W -Set tabstop in current column if n=0. X If n=2, any tabstop at current column is cleared. X If n=4, all tabstops are cleared. X <ESC> [ <m>;<n>;<o> ~ -Define window m, top left at n line, o column. X X=====================================================================*/ X X X/* -------- Color table -------------------------------------*/ X X Xstruct attr_entry X{ X int id; X uchar mask; X uchar attr; X}; X Xstruct attr_entry color_table[ ] = X{ X 0, 0x00, 0x07, /* all attribs off; normal. */ X 1, 0xff, 0x08, /* Increase intensity */ X 2, 0xf7, 0x00, /* Decrease intensity */ X /* Italics */ X/* 4, 0xf8, 0x01, */ /* underline */ X 5, 0xff, 0x80, /* slow blink */ X 6, 0xff, 0x80, /* rapid blink */ X 7, 0xf8, 0x70, /* reverse */ X 8, 0x88, 0x00, /* invisible */ X X 30, 0xf8, 0x00, /* black foreground */ X 31, 0xf8, 0x04, /* red */ X 32, 0xf8, 0x02, /* green */ X 33, 0xf8, 0x06, /* yellow */ X 34, 0xf8, 0x01, /* blue */ X 35, 0xf8, 0x05, /* magenta */ X 36, 0xf8, 0x03, /* cyan */ X 37, 0xf8, 0x07, /* white */ X X 40, 0x8f, 0x00, /* black background */ X 41, 0x8f, 0x40, /* red */ X 42, 0x8f, 0x20, /* green */ X 43, 0x8f, 0x60, /* yellow */ X 44, 0x8f, 0x10, /* blue */ X 45, 0x8f, 0x50, /* magenta */ X 46, 0x8f, 0x30, /* cyan */ X 47, 0x8f, 0x70, /* white */ X -1, 0, 0 X}; X X XPRIVATE parse_escape(tp, c) Xregister struct tty_struct *tp; /* pointer to tty struct */ Xchar c; /* next character in escape sequence */ X{ X X switch (tp->tty_esc_state) X { X case 1: /* ESC seen */ X tp->tty_esc_intro = '\0'; X tp->tty_esc_parmp = tp->tty_esc_parmv; X tp->tty_esc_parmv[ 0] = tp->tty_esc_parmv[ 1] = 0; X X switch (c) X { X case '[': /* Control Sequence Introducer */ X tp->tty_esc_intro = c; X tp->tty_esc_state = 2; X break; X X case 'c': /* reset terminal */ X case 'M': /* Reverse Index */ X do_escape(tp, c); X break; X default: X tp->tty_esc_state = 0; X break; X } X break; X X case 2: /* ESC [ seen */ X if (c >= '0' && c <= '9') X { X if (tp->tty_esc_parmp < tp->tty_esc_parmv + MAX_ESC_PARMS) X *tp->tty_esc_parmp = *tp->tty_esc_parmp * 10 + (c - '0'); X break; X } X else if (c == ';') X { X if (++tp->tty_esc_parmp < tp->tty_esc_parmv + MAX_ESC_PARMS) X *tp->tty_esc_parmp = 0; X break; X } X else X { X do_escape(tp, c); X } X break; X X default: /* illegal state */ X tp->tty_esc_state = 0; X break; X } X} X X/*------------------------------------------------------------------- X do_escape() X X Handle a sequence beginning with just ESC X-------------------------------------------------------------------*/ X XPRIVATE do_escape(tp, c) Xregister struct tty_struct *tp; /* pointer to tty struct */ Xchar c; /* next character in escape sequence */ X{ X int n, ct, vx; X int *ep; X struct attr_entry *cp; X X if (tp->tty_esc_intro == '\0') X { X switch (c) X { X case 'M': /* Reverse Index */ X if (tp->tty_row == 0) X scroll_window(tp,0,0,tp->tty_nrow-1,tp->tty_ncol-1,1, X SCROLL_DW); X else X tp->tty_row--; X move_to(tp, tp->tty_column, tp->tty_row); X break; X X case 'c': X init_tty_struct(tty_line); X break; X X default: X break; X } X } X else /* handle escape sequences of form: */ X { /* X ESC [ <letter> X ESC [ <n> <letter> X ESC [ <n> ; <m> .... <letter> X ESC [ <n> ; <m> .... <blank> <letter> X */ X X if (tp->tty_esc_intro == '[') X { X switch (c) X { X case 'A': /* ESC [ <n> A --cursor up */ X move_to(tp, tp->tty_column, X MIN(SCR_LINES,tp->tty_row-MAX(1,tp->tty_esc_parmv[0])) ); X break; X X case 'B': /* ESC [ <n> B -- cursor down */ X move_to(tp, tp->tty_column, X MIN(SCR_LINES,tp->tty_row+MAX(1,tp->tty_esc_parmv[0])) ); X break; X X case 'D': /* ESC [ <n> D -- cursor left */ X move_to(tp, tp->tty_column-MAX(1,tp->tty_esc_parmv[0]), X tp->tty_row); X break; X X case 'C': /* ESC [ <n> C -- cursor right */ X move_to(tp, tp->tty_column+MAX(1,tp->tty_esc_parmv[0]), X tp->tty_row); X break; X X case 'H': /* Position cursor, esc [ y ; x H */ X X move_to(tp,MAX(1, MIN(LINE_WIDTH, tp->tty_esc_parmv[1])) - 1, X MAX(1, MIN(SCR_LINES, tp->tty_esc_parmv[0])) - 1 ); X break; X X case 'J': /* Clear part of window */ X switch( tp->tty_esc_parmv[ 0]) { X case 0: /* from the beginning */ X scroll_window(tp,tp->tty_row,0, X tp->tty_row,tp->tty_column,0,0); X if (tp->tty_row > 0) X scroll_window(tp,0,0, X tp->tty_row-1,tp->tty_ncol-1,0,0); X break; X case 1: /* to the end */ X scroll_window(tp,tp->tty_row,tp->tty_column, X tp->tty_row,tp->tty_ncol-1,0,0); X if (tp->tty_row < tp->tty_nrow - 1) X scroll_window(tp,tp->tty_row+1,0, X tp->tty_row-1,tp->tty_ncol-1,0,0); X break; X X default: /* the whole window */ X scroll_window(tp, 0,0, tp->tty_nrow-1,tp->tty_ncol-1, 0,0); X break; X } X break; X X case 'K': /* ESC [ <n> K --delete part of line */ X switch (tp->tty_esc_parmv[ 0]) { X case 0: /* erase to end of line */ X X scroll_window(tp,tp->tty_row,tp->tty_column, X tp->tty_row,tp->tty_ncol-1,0,0); X break; X X case 1: /* erase from start of line */ X scroll_window(tp,tp->tty_row,0, X tp->tty_row,tp->tty_column,0,0); X break; X X default: /* erase whole line */ X scroll_window(tp,tp->tty_row,0, X tp->tty_row,tp->tty_ncol-1,0,0); X break; X } X break; X X case 'M': /* ESC [ <n> M --delete n lines */ X scroll_window(tp,tp->tty_row,0,tp->tty_nrow-1,tp->tty_ncol-1, X MAX(1,tp->tty_esc_parmv[0]), X SCROLL_UP); X break; X X case 'L': /* ESC [ <n> L --open n lines */ X scroll_window(tp,tp->tty_row,0,tp->tty_nrow-1,tp->tty_ncol-1, X MAX(1,tp->tty_esc_parmv[0]), X SCROLL_DW); X break; X X case 'm': /* Set graphic rendition, esc [ n m */ X ep = &tp->tty_esc_parmv[0]; X for ( ; ep <= tp->tty_esc_parmp; ep++) X { X n = *ep; /* tp->tty_esc_parmv[0]; */ X for (cp = &color_table[0]; cp->id != -1; cp++) X { X if (cp->id == n) X { X tp->tty_attribute &= cp->mask; X tp->tty_attribute |= cp->attr; X break; X } X } X } X break; X X case 'S': /* ESC [ <n> S scroll up */ X scroll_window(tp,0,0,tp->tty_nrow-1,tp->tty_ncol-1, X MAX(1,tp->tty_esc_parmv[0]), X GO_FORWARD); X break; X X case 'T': /* ESC [ <n> S scroll down */ X scroll_window(tp,0,0,tp->tty_nrow-1,tp->tty_ncol-1, X MAX(1,tp->tty_esc_parmv[0]), X GO_BACKWARD); X break; X X default: X printf("Received unsupported escape sequence (ESC 0x%x)\n",c); X printf("parse returns parms=(%d,%d),letter=%c\n", X tp->tty_esc_parmv[0], X tp->tty_esc_parmv[1],c); X break; X } X } X } X tp->tty_esc_state = 0; X} X X X/*===================================================================== X set_6845() X X Set a register pair inside the 6845. X Registers 10-11 control the format of the cursor (how high it is, etc). X Registers 12-13 tell the 6845 where in video ram to start (in WORDS) X Registers 14-15 tell the 6845 where to put the cursor (in WORDS) X X Note that registers 12-15 work in words, i.e. 0x0000 is the top left X character, but 0x0001 (not 0x0002) is the next character. This addressing X is different from the way the 8088 addresses the video ram, where 0x0002 X is the address of the next character. X=====================================================================*/ X X XPRIVATE set_6845(reg, val) Xint reg; /* which register pair to set */ Xint val; /* 16-bit value to set it to */ X{ X port_out(vid_port + INDEX, reg); /* set the index register */ X port_out(vid_port + DATA, (val>>8) & BYTE); /* output high byte */ X port_out(vid_port + INDEX, reg + 1); /* again */ X port_out(vid_port + DATA, val&BYTE); /* output low byte */ X} X X X/*=================================================================== X beep() X X Making a beeping sound on the speaker (output for CRTL-G). The X beep is kept short, because interrupts must be disabled during X beeping, and it is undesirable to keep them off too long. This X routine works by turning on the bits in port B of the 8255 chip X that drive the speaker. X===================================================================*/ X XPRIVATE beep(f) Xint f; /* this value determines beep frequency */ X{ X int x, k; X X lock(); /* disable interrupts */ X X port_out(TIMER3,0xB6); /* set up timer channel 2 mode */ X port_out(TIMER2, f&BYTE); /* load low-order bits of frequency in timer */ X port_out(TIMER2,(f>>8)&BYTE); /* now high-order bits of frequency in timer */ X port_in(PORT_B,&x); /* acquire status of port B */ X port_out(PORT_B, x|3); /* turn bits 0 and 1 on to beep */ X for (k = 0; k < B_TIME; k++); /* delay loop while beeper sounding */ X port_out(PORT_B, x); /* restore port B the way it was */ X X unlock(); /* re-enable interrupts */ X} X X X/*========================================================================== X tty_init() X X Initialize the tty tables. X X===========================================================================*/ X XPRIVATE tty_init() X{ X int i; X X /* -- Tell the EGA card, if any, to simulate a 16K CGA card. V1.2 -- */ X X port_out(EGA + INDEX, 4); /* register select */ X port_out(EGA + DATA, 1); /* no extended memory to be used */ X X if (color) X { X vid_base = COLOR_BASE; X vid_mask = C_VID_MASK; X vid_port = C_6845; X vid_retrace = C_RETRACE; X } X else X { X vid_base = MONO_BASE; X vid_mask = M_VID_MASK; X vid_port = M_6845; X vid_retrace = M_RETRACE; X } X X for (i = 0; i < NR_TTYS; i++) X init_tty_struct(i); X X tty_driver_buf[ 1] = MAX_OVERRUN; /* set up limit on keyboard buffering */ X X set_6845(CUR_SIZE, 31); /* set cursor shape */ X set_6845(VID_ORG, 0); /* use page 0 of video ram */ X X tty_line = 0; /* force to first virtual screen */ X current_tp = &tty_struct[0]; /* remember current tty pointer */ X move_to(current_tp, 0, 0); /* move cursor to lower left corner */ X X X /* ---------------------------------------------------------------- X Determine which keyboard type is attached. The bootstrap program X asks the user to type an '='. The scan codes for '=' differ X depending on the keyboard in use. X ---------------------------------------------------------------- */ X/*----------------- X if (scan_code == OLIVETTI_EQUAL) olivetti = TRUE; X-----------------*/ X} X X X Xinit_tty_struct( line ) Xint line; X{ X struct tty_struct *tp; X X if (line < 0 || line > NR_TTYS-1) return; X X tp = &tty_struct[ line]; X X tp->tty_inhead = tp->tty_inqueue; X tp->tty_intail = tp->tty_inqueue; X tp->tty_mode = CRMOD | XTABS | ECHO; X tp->tty_devstart = console; X tp->tty_erase = ERASE_CHAR; X tp->tty_kill = KILL_CHAR; X tp->tty_intr = INTR_CHAR; X tp->tty_quit = QUIT_CHAR; X tp->tty_xon = XON_CHAR; X tp->tty_xoff = XOFF_CHAR; X tp->tty_eof = EOT_CHAR; X tp->tty_org = line * 4096; X tp->tty_makebreak = TWO_INTS; X tp->tty_attribute = BLANK; X tp->tty_nrow = NROWS; X tp->tty_ncol = NCOLS; X scroll_window(tp,0,0,tp->tty_nrow-1,tp->tty_ncol-1,0,0); /* clear scr */ X move_to(tp, 0, 0); X} X X X/*===================================================================== X putc() X X This procedure is used by the version of printf() that is linked X with the kernel itself. The one in the library sends a message to X FS, which is not what is needed for printing within the kernel. X This version just queues the character and starts the output. X=====================================================================*/ X XPUBLIC putc(c) Xchar c; /* character to print */ X{ X out_char(&tty_struct[ 0], c); X} X X X/*==================================================================== X func_key() X X This procedure traps function keys for debugging purposes. X When MINIX is fully debugged, it should be removed. X====================================================================*/ X XPRIVATE func_key(ch) Xchar ch; /* scan code for a function key */ X{ X X if (ch == F1) p_dmp(); /* print process table */ X if (ch == F2) map_dmp(); /* print memory map */ X if (ch == F3) tss_dmp(); X if (ch == F4) ldt_dmp(); X if (ch == F5) pkt_dmp(); X if (ch == F6) reg_dmp(); X X if (ch == F9) sigchar(&tty_struct[0], 0, SIGKILL); /* issue SIGKILL V1.2 */ X} X#endif X X X/*========================================================================== X vir_screen_change() X===========================================================================*/ X XPRIVATE vir_screen_change(screen_number) Xint screen_number; /* Virtual screen number to select for i/o */ X{ X /* -- Remember the screen number to keep input characters straight -- */ X X tty_line = screen_number; X current_tp = &tty_struct[ screen_number]; X X /* -- Select appropriate page of video memory -- */ X X set_6845(VID_ORG, current_tp->tty_org >> 1); X X /* -- Update cursor -- */ X X set_6845(CURSOR, current_tp->tty_vid >> 1); X} X X SHAR_EOF fi # end of overwriting check # End of shell archive exit 0