[comp.os.minix] tty-serial driver experience

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