[comp.os.minix] V1.3c posting #11 kernel

ast@cs.vu.nl (Andy Tanenbaum) (09/28/88)

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting 'at_makefile'
sed 's/^X//' > 'at_makefile' << '+ END-OF-FILE ''at_makefile'
X# The kernel dir contains xt_wini.c and at_wini.c.  Before running make
X# you must copy one of these to wini.c, depending on which controller you
X# have.  If you do not have a hard disk, you MUST choose one of them at random.
X# On a PC, cpp and cem are in /lib and will be removed to make space while
X# linking the kernel.  On an AT, they are in /usr/lib are are not removed.
X# This is because they have to be in /lib on a PC; the diskette is too small
X# for them to be in /usr/lib.  You can change this by editing commands/cc.c.
X#
X# The CFLAGS values are:
X#  -Di8088	- required on an 8088/80286/80386 CPU; forbidden on a 68000
X#  -F		- run cpp and cem sequentially (used when memory is tight)
X#  -T.		- put temporaries in working directory (when RAM disk is small)
X#
XCFLAGS= -Di8088 -F -T.
Xh=../h
Xl=/usr/lib
X
Xobj =	mpx88.s main.s tty.s floppy.s wini.s system.s proc.s clock.s memory.s \
X	console.s rs232.s printer.s table.s klib88.s dmp.s
X
Xcobjs =	main.s tty.s floppy.s wini.s system.s proc.s clock.s memory.s \
X	console.s rs232.s printer.s table.s dmp.s
X
Xkernel:	makefile $(obj) $l/libc.a
X	@echo "Start linking Kernel."
X	@asld -o kernel -T. $(obj) $l/libc.a $l/end.s
X	@echo "Kernel done.  "
X
Xclean:
X	rm -f $(cobjs)
X
Xclock.s:	const.h type.h $h/const.h $h/type.h
Xclock.s:	$h/callnr.h
Xclock.s:	$h/com.h
Xclock.s:	$h/error.h
Xclock.s:	$h/signal.h
Xclock.s:	glo.h
Xclock.s:	proc.h
X
Xconsole.s:	const.h type.h $h/const.h $h/type.h
Xconsole.s:	$h/callnr.h
Xconsole.s:	$h/com.h
Xconsole.s:	$h/error.h
Xconsole.s:	$h/sgtty.h
Xconsole.s:	$h/signal.h
Xconsole.s:	glo.h
Xconsole.s:	proc.h
Xconsole.s:	tty.h
Xconsole.s:	ttymaps.h
X
Xfloppy.s:	const.h type.h $h/const.h $h/type.h
Xfloppy.s:	$h/callnr.h
Xfloppy.s:	$h/com.h
Xfloppy.s:	$h/error.h
Xfloppy.s:	glo.h
Xfloppy.s:	proc.h
X
X
Xdmp.s:		const.h type.h $h/const.h $h/type.h
Xdmp.s:		$h/callnr.h
Xdmp.s:		$h/com.h
Xdmp.s:		$h/error.h
Xdmp.s:		glo.h
Xdmp.s:		proc.h
X
Xmain.s:		const.h type.h $h/const.h $h/type.h
Xmain.s:		$h/callnr.h
Xmain.s:		$h/com.h
Xmain.s:		$h/error.h
Xmain.s:		glo.h
Xmain.s:		proc.h
X
Xmemory.s:	const.h type.h $h/const.h $h/type.h
Xmemory.s:	$h/callnr.h
Xmemory.s:	$h/com.h
Xmemory.s:	$h/error.h
Xmemory.s:	proc.h
X
Xprinter.s:	const.h type.h $h/const.h $h/type.h
Xprinter.s:	$h/callnr.h
Xprinter.s:	$h/com.h
Xprinter.s:	$h/error.h
Xprinter.s:	proc.h
Xprinter.s:	glo.h
X
Xproc.s:		const.h type.h $h/const.h $h/type.h
Xproc.s:		$h/callnr.h
Xproc.s:		$h/com.h
Xproc.s:		$h/error.h
Xproc.s:		glo.h
Xproc.s:		proc.h
X
Xsystem.s:	const.h type.h $h/const.h $h/type.h
Xsystem.s:	$h/callnr.h
Xsystem.s:	$h/com.h
Xsystem.s:	$h/error.h
Xsystem.s:	$h/signal.h
Xsystem.s:	glo.h
Xsystem.s:	proc.h
X
Xtable.s:	const.h type.h $h/const.h $h/type.h $h/com.h
Xtable.s:	glo.h
Xtable.s:	proc.h
Xtable.s:	tty.h
X
Xtty.s:	const.h type.h $h/const.h $h/type.h
Xtty.s:	$h/callnr.h
Xtty.s:	$h/com.h
Xtty.s:	$h/error.h
Xtty.s:	$h/sgtty.h
Xtty.s:	$h/signal.h
Xtty.s:	glo.h
Xtty.s:	proc.h
Xtty.s:	tty.h
Xtty.s:	ttymaps.h
Xtty.s:	tty.h
Xtty.s:	ttymaps.h
X
Xwini.s:	const.h type.h $h/const.h $h/type.h
Xwini.s:	$h/callnr.h
Xwini.s:	$h/com.h
Xwini.s:	$h/error.h
Xwini.s:	proc.h
+ END-OF-FILE at_makefile
chmod 'u=rw,g=r,o=r' 'at_makefile'
set `wc -c 'at_makefile'`
count=$1
case $count in
3026)	:;;
*)	echo 'Bad character count in ''at_makefile' >&2
		echo 'Count should be 3026' >&2
esac
echo Extracting 'at_wini.c.cdif'
sed 's/^X//' > 'at_wini.c.cdif' << '+ END-OF-FILE ''at_wini.c.cdif'
X*** /local/ast/minix/tape3b/kernel/at_wini.c	Wed Jul 13 16:59:17 1988
X--- at_wini.c	Mon Sep 26 23:34:01 1988
X***************
X*** 188,199 ****
X  register struct wini *wn;	/* pointer to the drive struct */
X  {
X    extern phys_bytes umap();
X!   phys_bytes usr_buf = umap(proc_addr(wn->wn_procnr), D, wn->wn_address, BLOCK_SIZE);
X    register int i, old_state;
X    int r = 0;
X  
X    /* The command is issued by outputing 7 bytes to the controller chip. */
X  
X    if (usr_buf == (phys_bytes)0)
X  	return(ERR);
X    command[0] = wn->wn_ctlbyte;
X--- 188,200 ----
X  register struct wini *wn;	/* pointer to the drive struct */
X  {
X    extern phys_bytes umap();
X!   phys_bytes usr_buf;
X    register int i, old_state;
X    int r = 0;
X  
X    /* The command is issued by outputing 7 bytes to the controller chip. */
X  
X+   usr_buf = umap(proc_addr(wn->wn_procnr), D, wn->wn_address, BLOCK_SIZE);
X    if (usr_buf == (phys_bytes)0)
X  	return(ERR);
X    command[0] = wn->wn_ctlbyte;
X***************
X*** 212,220 ****
X    if (wn->wn_opcode == DISK_READ) {
X  	for (i=0; i<BLOCK_SIZE/SECTOR_SIZE; i++) {
X  		receive(HARDWARE, &w_mess);
X! 		old_state = lock();
X  		dma_read((unsigned)(usr_buf >> 4), (unsigned)(usr_buf & 0x0F));
X! 		restore(old_state);
X  		usr_buf += 0x200;
X  		if (win_results() != OK) {
X  			w_need_reset = TRUE;
X--- 213,221 ----
X    if (wn->wn_opcode == DISK_READ) {
X  	for (i=0; i<BLOCK_SIZE/SECTOR_SIZE; i++) {
X  		receive(HARDWARE, &w_mess);
X! /*		old_state = lock(); */
X  		dma_read((unsigned)(usr_buf >> 4), (unsigned)(usr_buf & 0x0F));
X! /*		restore(old_state); */
X  		usr_buf += 0x200;
X  		if (win_results() != OK) {
X  			w_need_reset = TRUE;
X***************
X*** 230,238 ****
X  		return(ERR);
X  	}
X  	for (i=0; i<BLOCK_SIZE/SECTOR_SIZE; i++) {
X! 		old_state = lock();
X  		dma_write((unsigned)(usr_buf >> 4), (unsigned)(usr_buf&0x0F));
X! 		restore(old_state);
X  		usr_buf += 0x200;
X  		receive(HARDWARE, &w_mess);
X  		if (win_results() != OK) {
X--- 231,239 ----
X  		return(ERR);
X  	}
X  	for (i=0; i<BLOCK_SIZE/SECTOR_SIZE; i++) {
X! /*		old_state = lock(); */
X  		dma_write((unsigned)(usr_buf >> 4), (unsigned)(usr_buf&0x0F));
X! /*		restore(old_state); */
X  		usr_buf += 0x200;
X  		receive(HARDWARE, &w_mess);
X  		if (win_results() != OK) {
+ END-OF-FILE at_wini.c.cdif
chmod 'u=rw,g=r,o=r' 'at_wini.c.cdif'
set `wc -c 'at_wini.c.cdif'`
count=$1
case $count in
2242)	:;;
*)	echo 'Bad character count in ''at_wini.c.cdif' >&2
		echo 'Count should be 2242' >&2
esac
echo Extracting 'clock.c.cdif'
sed 's/^X//' > 'clock.c.cdif' << '+ END-OF-FILE ''clock.c.cdif'
X*** /local/ast/minix/tape3b/kernel/clock.c	Sat Jul 16 23:59:22 1988
X--- clock.c	Mon Sep 26 23:34:02 1988
X***************
X*** 39,44 ****
X--- 39,45 ----
X  /* Constant definitions. */
X  #define MILLISEC         100	/* how often to call the scheduler (msec) */
X  #define SCHED_RATE (MILLISEC*HZ/1000)	/* number of ticks per schedule */
X+ #define FLUSH_MASK        07	/* bit mask used for flushing RS232 input */
X  
X  /* Clock parameters. */
X  #define TIMER0          0x40	/* port address for timer channel 0 */
X***************
X*** 54,59 ****
X--- 55,61 ----
X  PRIVATE message mc;		/* message buffer for both input and output */
X  PRIVATE int (*watch_dog[NR_TASKS+1])();	/* watch_dog functions to call */
X  extern int flush_flag;		/* tells clock when to flush the tty buf */
X+ extern int need_ega_int;	/* tells clock to do ega adjust */
X  
X  /*===========================================================================*
X   *				clock_task				     *
X***************
X*** 191,204 ****
X  
X    accounting();			/* keep track of who is using the cpu */
X  
X    /* If a user process has been running too long, pick another one. */
X    if (--sched_ticks == 0) {
X  	if (bill_ptr == prev_ptr) sched();	/* process has run too long */
X  	sched_ticks = SCHED_RATE;		/* reset quantum */
X  	prev_ptr = bill_ptr;			/* new previous process */
X  
X! 	/* If characters are accumulating, call the TTY task. */
X! 	if (flush_flag) rs_flush();	/* flush accumulated tty input */
X  
X  	/* Check if printer is hung up, and if so, restart it. */
X  	if (pr_busy && pcount > 0 && cum_count == prev_ct) pr_char(); 
X--- 193,212 ----
X  
X    accounting();			/* keep track of who is using the cpu */
X  
X+   /* If input characters are accumulating on an RS232 line, process them. */
X+   if (flush_flag) {
X+ 	t = (int) realtime;		/* only low-order bits matter */
X+ 	if ( (t & FLUSH_MASK) == 0) rs_flush();	/* flush tty input */
X+   }
X+ 
X    /* If a user process has been running too long, pick another one. */
X    if (--sched_ticks == 0) {
X  	if (bill_ptr == prev_ptr) sched();	/* process has run too long */
X  	sched_ticks = SCHED_RATE;		/* reset quantum */
X  	prev_ptr = bill_ptr;			/* new previous process */
X  
X! 	/* Does ega need adjustment? */
X! 	if (need_ega_int) ega_int();  
X  
X  	/* Check if printer is hung up, and if so, restart it. */
X  	if (pr_busy && pcount > 0 && cum_count == prev_ct) pr_char(); 
+ END-OF-FILE clock.c.cdif
chmod 'u=rw,g=r,o=r' 'clock.c.cdif'
set `wc -c 'clock.c.cdif'`
count=$1
case $count in
2370)	:;;
*)	echo 'Bad character count in ''clock.c.cdif' >&2
		echo 'Count should be 2370' >&2
esac
echo Extracting 'console.c.new'
sed 's/^X//' > 'console.c.new' << '+ END-OF-FILE ''console.c.new'
X
X/* Code and data for the IBM console driver. */
X
X#include "../h/const.h"
X#include "../h/type.h"
X#include "../h/callnr.h"
X#include "../h/com.h"
X#include "../h/error.h"
X#include "../h/sgtty.h"
X#include "../h/signal.h"
X#include "const.h"
X#include "type.h"
X#include "glo.h"
X#include "proc.h"
X#include "tty.h"
X
Xextern char alt_c[], unsh[], sh[], unm24[], m24[];
Xextern char dutch_unsh[], dutch_sh[], dutch_alt[];
Xextern char unsh_usx[], sh_usx[], scode_map[];
X
X/* Definitions used by the console driver. */
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    0x3FFF	/* 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 BEEP_FREQ     0x0533	/* value to put into timer to set beep freq */
X#define B_TIME		   3	/* length of CTRL-G beep is ticks */
X#define BLANK         0x0700	/* determines  cursor color on blank screen */
X#define LINE_WIDTH        80	/* # characters on a line */
X#define SCR_LINES         25	/* # lines on the screen */
X#define SCR_BYTES	8000	/* size video RAM. multiple of 2*LINE_WIDTH */
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 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#define LED_CODE        0xED	/* command to keyboard to set LEDs */
X#define LED_DELAY       0x80	/* device dependent delay needed */
X
X/* Constants relating to the video RAM and 6845. */
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 OVRFL_REG	   7    /* EGA overflow 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#define LINE_CMP	0x18	/* EGA line compare register */
X
X/* Definitions used for determining if the keyboard is IBM or Olivetti type. */
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 STANDARD_SCAN	  13
X#define OLIVETTI_SCAN     12	/* the '=' key is 12 on olivetti, 13 on IBM */
X#define DUTCH_EXT_SCAN	  32	/* scan code of 'd' */
X#define US_EXT_SCAN	  22	/* scan code of 'u' */
X#define SPACE_SCAN	  57	/* a space */
X#define PS_LED_DELAY    1200	/* delay for PS/2 */
X#define PS_KEYBD	0x68	/* I/O port for data on ps/2 */
X
X/* Scan codes to ASCII for IBM DUTCH extended keyboard */
X#define MINUS_DU      0x0035	/* scan code of '-' on Dutch extended keybd */
X#define NUM_SLASH_DU  0x0057	/* scan code of numeric keypad slash */
X
X#define ESCAPE_CODE   0x00E0	/* escape scan code */
X
X/* Global variables used by the console driver. */
XPUBLIC  message keybd_mess;	/* message used for console input chars */
XPUBLIC int vid_mask;		/* 037777 for color (16K) or 07777 for mono */
XPUBLIC int vid_port;		/* I/O port for accessing 6845 */
XPUBLIC int blank_color = 0x0700; /* display code for blank */
XPRIVATE vid_retrace;		/* how many characters to display per burst */
XPRIVATE unsigned vid_base;	/* base of video ram (0xB000 or 0xB800) */
XPRIVATE int esc;		/* escape scan code detected? */
X
X/* Map from ANSI colors to the attributes used by the PC */
XPRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
X
X/*===========================================================================*
X *				keyboard				     *
X *===========================================================================*/
XPUBLIC keyboard()
X{
X/* A keyboard interrupt has occurred.  Process it. */
X
X  int val, code, k, raw_bit;
X  char stopc;
X
X  /* Fetch the character from the keyboard hardware and acknowledge it. */
X  if (ps) {
X	port_in(PS_KEYBD, &code);	/* get the scan code for key struck */
X	ack_char();			/* acknowledge the character */
X  } else {
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
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  if (keyb_type == DUTCH_EXT)
X	if (esc) {
X		/* Numeric slash gives scan codes 0xE0 0x35. */
X		if (code == minus_code) code = num_slash;
X		esc = FALSE;
X	} else 
X		esc = (code == ESCAPE_CODE);
X
X  k = code - 0200;		/* codes > 0200 mean key release */
X  if (k > 0) {
X	/* A key has been released. */
X	if (k != 29 && k != 42 && k != 54 && k != 56 && k != 58 && k != 69) {
X		port_out(INT_CTL, ENABLE);	/* re-enable interrupts */
X	 	return;		/* don't call tty_task() */
X	}
X  } else {
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	raw_bit = tty_struct[CONSOLE].tty_mode & RAW;
X	stopc = tty_struct[CONSOLE].tty_xoff;
X	if (raw_bit == 0 && control && code == CTRL_S && stopc == XOFF_CHAR) {
X		tty_struct[CONSOLE].tty_inhibited = STOPPED;
X		port_out(INT_CTL, ENABLE);
X		return;
X	}
X  }
X
X  /* Check for CTRL-ALT-DEL, and if found, reboot the computer. */
X  if (control && alt && code == DEL_CODE) reboot();	/* CTRL-ALT-DEL */
X
X  /* Store the character in memory so the task can get at it later.
X   * tty_driver_buf[0] is the current count, and tty_driver_buf[1] is the
X   * maximum allowed to be stored.
X   */
X  if ( (k = tty_driver_buf[0]) < tty_driver_buf[1]) {
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] = CONSOLE;	/* tell which line it came from */
X	tty_driver_buf[0]++;		/* increment counter */
X
X	/* Build and send the interrupt message. */
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  } else {
X	/* Too many characters have been buffered.  Discard excess. */
X	port_out(INT_CTL, ENABLE);	/* re-enable 8259A controller */
X  }
X}
X
X
X/*===========================================================================*
X *				console					     *
X *===========================================================================*/
XPRIVATE console(tp)
Xregister struct tty_struct *tp;	/* tells which terminal is to be used */
X{
X/* Copy as much data as possible to the output queue, then start I/O.  On
X * memory-mapped terminals, such as the IBM console, the I/O will also be
X * finished, and the counts updated.  Keep repeating until all I/O done.
X */
X
X  extern char get_byte();
X  int count;
X  char c;
X  unsigned segment, offset, offset1;
X
X  /* Loop over the user bytes one at a time, outputting each one. */
X  segment = (tp->tty_phys >> 4) & WORD_MASK;
X  offset = tp->tty_phys & OFF_MASK;
X  offset1 = offset;
X  count = 0;
X
X  while (tp->tty_outleft > 0 && tp->tty_inhibited == RUNNING) {
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 character in user buffer */
X	tp->tty_outleft--;	/* decrement count */
X  }
X  flush(tp);			/* clear out the pending characters */
X
X  /* Update terminal data structure. */
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  if (tp->tty_outleft == 0) finish(tp, tp->tty_cum);
X}
X
X
X/*===========================================================================*
X *				out_char				     *
X *===========================================================================*/
XPRIVATE out_char(tp, c)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xchar c;				/* character to be output */
X{
X/* Output a character on the console.  Check for escape sequences first. */
X
X  if (tp->tty_esc_state > 0) {
X	parse_escape(tp, c);
X	return;
X  }
X
X  switch(c) {
X	case 000:		/* null is typically used for padding */
X		return;		/* better not do anything */
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_screen(tp, GO_FORWARD);
X		else
X			tp->tty_row++;
X
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			do {
X				out_char(tp, ' ');
X			} while (tp->tty_column & TAB_MASK);
X			return;
X		}
X		/* Ignore tab if XTABS is off--video RAM has no hardware tab */
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#ifndef LINEWRAP
X		if (tp->tty_column >= LINE_WIDTH) return;	/* long line */
X#endif
X		if (tp->tty_rwords == TTY_RAM_WORDS) flush(tp);
X		tp->tty_ramqueue[tp->tty_rwords++]=tp->tty_attribute|(c&BYTE);
X		tp->tty_column++;	/* next column */
X#ifdef LINEWRAP
X 		if (tp->tty_column >= LINE_WIDTH) {
X 			flush(tp);
X 			if (tp->tty_row == SCR_LINES-1)
X 				scroll_screen(tp, GO_FORWARD);
X 			else
X 				tp->tty_row++;
X 			move_to(tp, 0, tp->tty_row);
X 		}
X#endif /* LINEWRAP */
X		return;
X  }
X}
X
X/*===========================================================================*
X *				scroll_screen				     *
X *===========================================================================*/
XPRIVATE scroll_screen(tp, dir)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xint dir;			/* GO_FORWARD or GO_BACKWARD */
X{
X  int amount, offset, bytes, old_state;
X
X  flush(tp);
X  bytes = 2 * (SCR_LINES - 1) * LINE_WIDTH;	/* 2 * 24 * 80 bytes */
X
X  /* Scrolling the screen is a real nuisance due to the various incompatible
X   * video cards.  This driver supports hardware scrolling (mono and CGA cards)
X   * and software scrolling (EGA cards).
X   */
X  if (softscroll) {
X	/* Software scrolling for non-IBM compatible EGA cards. */
X	if (dir == GO_FORWARD) {
X		scr_up(vid_base, LINE_WIDTH * 2, 0,
X		       (SCR_LINES - 1) * LINE_WIDTH);
X		vid_copy(NIL_PTR, vid_base, tp->tty_org+bytes, LINE_WIDTH);
X	} else {
X		scr_down(vid_base,
X			 (SCR_LINES - 1) * LINE_WIDTH * 2 - 2,
X			 SCR_LINES * LINE_WIDTH * 2 - 2,
X			 (SCR_LINES - 1) * LINE_WIDTH);
X		vid_copy(NIL_PTR, vid_base, tp->tty_org, LINE_WIDTH);
X	}
X  } else if (ega) {
X	int lines;
X	/* 
X	 * EGA scrolling.  CGA and MDA scrolling is based on the fact
X	 * fact that the older adapters wrap around at 4K or whatever.
X	 * not all EGA's do.  So instead we use the line compare
X	 * register.  This is a scan line.  Everything after this 
X	 * line is displayed starting at the beginning of the display
X	 * RAM, ignoring the display start.  So the top of the screen
X	 * starts whereover tty_org says it should in RAM.  We compute
X	 * the scan line where the first page of RAM ends, and force
X	 * wraparound to the top using line compare.  Since this uses
X	 * nothing beyond the first page of display RAM, and line
X	 * compare is a documented feature, it should work on all EGA
X	 * emulators.  To keep arithmetic easier, we use a "page size"
X	 * of SCR_BYTES, which is exactly one screen full.
X	 */	 
X
X	amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH);
X	tp->tty_org = (tp->tty_org + amount);  /* top of screen in buffer */
X	if (tp->tty_org >= SCR_BYTES)  /* see if we wrapped around */
X	  tp->tty_org -= SCR_BYTES;
X	else if (tp->tty_org < 0)   /* wrap around the other way */
X	  tp->tty_org += SCR_BYTES;
X	if (dir == GO_FORWARD) {  /* compute line to clear */
X		offset = tp->tty_org + bytes;
X		if (offset >= SCR_BYTES)
X		  offset -= SCR_BYTES;
X        }
X	else
X		offset = tp->tty_org;
X
X	/* Blank the new line at top or bottom. */
X	vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH);
X	
X	/* Figure out where to wrap around to top of display mem */
X	lines = SCR_BYTES - tp->tty_org;
X	lines = char_height * (lines / (LINE_WIDTH * 2)) - 1;
X	if (lines >= (char_height * SCR_LINES))
X	   lines = 0x7fff;   /* disable line compare */
X	/* Now for the fun.  Set the wraparound line.  This is one of
X	 * the wierd registers where the high-order bit is in the
X	 * overflow register.  Note that we're hardcoding the other bits
X	 * in it.  This is another potential problem if a new model needs
X	 * extra bits.  Unfortunately I couldn't figure out any way to
X	 * read this register. */
X
X	ega_line = lines;
X	ega_origin = tp->tty_org;
X
X	/* 
X	 * We now have the settings for the EGA registers.  However
X	 * we don't want to do them now.  The problem is that in
X	 * order to avoid flicker we have to wait for vertical
X	 * retrace.  We don't want to do that for every line, because
X	 * it slows things like "more" down to the point where they
X	 * are about as slow as with software scrolling.  So we
X	 * do the actual register update in ega_int, which is called
X	 * from the clock when need_ega_int is non-zero.  If you
X	 * just increment need_ega_int in the next line, but don't
X	 * call ega_int, when you're cating to the terminal, you'll
X	 * get a whole screen at once.  We choose to do it every
X	 * 8 lines in order to give some visual impression of
X	 * scrolling.  So this is a compromise between a pure
X	 * clock driven approach, which is too fast, and updating
X	 * for each line, which is too slow.
X	 */
X
X	if (need_ega_int++ > 8) ega_int();
X  } else {
X	/* Normal scrolling using the 6845 registers. */
X	amount = (dir == GO_FORWARD ? 2 * LINE_WIDTH : -2 * LINE_WIDTH);
X	tp->tty_org = (tp->tty_org + amount) & vid_mask;
X	if (dir == GO_FORWARD)
X		offset = (tp->tty_org + bytes) & vid_mask;
X	else
X		offset = tp->tty_org;
X
X	/* Blank the new line at top or bottom. */
X	vid_copy(NIL_PTR, vid_base, offset, LINE_WIDTH);
X	set_6845(VID_ORG, tp->tty_org >> 1);	/* 6845 thinks in words */
X  }
X}
X
X/*===========================================================================*
X *				ega_int					     *
X *===========================================================================*/
XPUBLIC ega_int()
X{
X/*
X *  Need to change ega registers for scrolling.  Called from clock
X *  when need_ega_int is set.  Done this way because we only want to
X *  do this every so often, because we have to wait for a vert
X *  retrace interval.
X */
X
X  int old_state;
X
X  /*
X   * VID_ORG takes effect at the next retrace.  LINE_CMP presumably
X   * takes effect immediately, but won't show until we get to that
X   * line.  So to be completely clean, we first wait for non-retrace
X   * status (which of course will usually be the case), set the
X   * video origin to take effect on the next retrace, then wait
X   * for that retrace, and then set the overflow reg.  Perhaps this
X   * is paranoid, but various people have reported screen glitch.
X   */
X  old_state = wait_no_retrace();
X  set_6845(VID_ORG, ega_origin >> 1);	/* 6845 thinks in words */
X  wait_retrace();
X  if (ega_line > 255)
X    setb6845(OVRFL_REG, 0x1f);  /* high order bit is in overflow reg */
X  else
X    setb6845(OVRFL_REG, 0x0f);  /* high order bit 0 */
X  setb6845(LINE_CMP, ega_line & 0xff);  /* now set line compare reg */
X  need_ega_int = 0;
X  restore(old_state);
X}
X
X/*===========================================================================*
X *				flush					     *
X *===========================================================================*/
XPRIVATE flush(tp)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
X{
X/* Have the characters in 'ramqueue' transferred to the screen. */
X
X  if (tp->tty_rwords == 0) return;
X  vid_copy((char *)tp->tty_ramqueue, vid_base, tp->tty_vid, tp->tty_rwords);
X
X  /* Update the video parameters and cursor. */
X  tp->tty_vid = (tp->tty_vid + 2 * tp->tty_rwords);
X  if ((! softscroll) && ega && (tp->tty_vid >= SCR_BYTES))
X    tp->tty_vid -= SCR_BYTES;
X  set_6845(CURSOR, tp->tty_vid >> 1);	/* cursor counts in words */
X  tp->tty_rwords = 0;
X}
X
X
X/*===========================================================================*
X *				move_to					     *
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/* Move the cursor to (x, y). */
X
X  flush(tp);			/* flush any pending characters */
X  if (x < 0 || x >= LINE_WIDTH || y < 0 || y >= SCR_LINES) return;
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  if ((! softscroll) && ega && (tp->tty_vid >= SCR_BYTES))
X    tp->tty_vid -= SCR_BYTES;
X
X  set_6845(CURSOR, tp->tty_vid >> 1);	/* cursor counts in words */
X}
X
X
X/*===========================================================================*
X *				parse_escape				     *
X *===========================================================================*/
XPRIVATE parse_escape(tp, c)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xchar c;				/* next character in escape sequence */
X{
X/* The following ANSI escape sequences are currently supported.
X * If n and/or m are omitted, they default to 1.
X *   ESC [nA moves up n lines
X *   ESC [nB moves down n lines
X *   ESC [nC moves right n spaces
X *   ESC [nD moves left n spaces
X *   ESC [m;nH" moves cursor to (m,n)
X *   ESC [J clears screen from cursor
X *   ESC [K clears line from cursor
X *   ESC [nL inserts n lines ar cursor
X *   ESC [nM deletes n lines at cursor
X *   ESC [nP deletes n chars at cursor
X *   ESC [n@ inserts n chars at cursor
X *   ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
X *   ESC M scrolls the screen backwards if the cursor is on the top line
X */
X
X  switch (tp->tty_esc_state) {
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		switch (c) {
X		  case '[': 	/* Control Sequence Introducer */
X			tp->tty_esc_intro = c;
X			tp->tty_esc_state = 2; 
X			break;
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			if (tp->tty_esc_parmp 
X					< tp->tty_esc_parmv + MAX_ESC_PARMS)
X				*tp->tty_esc_parmp =
X				  *tp->tty_esc_parmp * 10 + (c - '0');
X			break;
X		}
X		else if (c == ';') {
X			if (++tp->tty_esc_parmp 
X					< tp->tty_esc_parmv + MAX_ESC_PARMS)
X				*tp->tty_esc_parmp = 0;
X			break;
X		}
X		else {
X			do_escape(tp, c);
X		}
X		break;
X	default:		/* illegal state */
X		tp->tty_esc_state = 0;
X		break;
X  }
X}
X
X/*===========================================================================*
X *				do_escape				     *
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, value, attr, src, dst, count, limit, m;
X
X  /* Some of these things hack on screen RAM, so it had better be up to date */
X  flush(tp);
X
X  /* Handle a sequence beginning with just ESC */
X  if (tp->tty_esc_intro == '\0') {
X	switch (c) {
X		case 'M':		/* Reverse Index */
X			if (tp->tty_row == 0)
X				scroll_screen(tp, GO_BACKWARD);
X			else
X				tp->tty_row--;
X			move_to(tp, tp->tty_column, tp->tty_row);
X			break;
X
X		default: break;
X	}
X  } else {
X	/* Handle a sequence beginning with ESC [ and parameters */
X	if (tp->tty_esc_intro == '[') {
X		value = tp->tty_esc_parmv[0];
X		attr = tp->tty_attribute;
X		switch (c) {
X		    case 'A': 		/* ESC [nA moves up n lines */
X			n = (value == 0 ? 1 : value);
X			move_to(tp, tp->tty_column, tp->tty_row - n);
X			break;
X
X	    	    case 'B':		/* ESC [nB moves down n lines */
X			n = (value == 0 ? 1 : value);
X			move_to(tp, tp->tty_column, tp->tty_row + n);
X			break;
X
X		    case 'C':		/* ESC [nC moves right n spaces */
X			n = (value == 0 ? 1 : value);
X			move_to(tp, tp->tty_column + n, tp->tty_row);
X			break;
X
X		    case 'D':		/* ESC [nD moves left n spaces */
X			n = (value == 0 ? 1 : value);
X			move_to(tp, tp->tty_column - n, tp->tty_row);
X			break;
X
X		    case 'H':		/* ESC [m;nH" moves cursor to (m,n) */
X			move_to(tp, MAX(1, MIN(LINE_WIDTH, 
X			    tp->tty_esc_parmv[1])) - 1,
X			    MAX(1, MIN(SCR_LINES, tp->tty_esc_parmv[0])) - 1 );
X			break;
X
X		    case 'J':		/* ESC [J clears screen from cursor */
X			if (value == 0) {
X				n=2*((SCR_LINES-(tp->tty_row+1))*LINE_WIDTH
X					      + LINE_WIDTH - (tp->tty_column));
X				vx = tp->tty_vid;
X				if (ega) {
X					ct = MIN(n, SCR_BYTES - vx);
X					vid_copy(NIL_PTR, vid_base, vx, ct/2);
X					n -= ct;
X					if (n > 0) 
X					      vid_copy(NIL_PTR,vid_base,0,n/2);
X				} else 
X					long_vid_copy(NIL_PTR,vid_base,vx,n/2);
X			}
X			break;
X
X		    case 'K':		/* ESC [K clears line from cursor */
X			if (value == 0) {
X				n = 2 * (LINE_WIDTH - (tp->tty_column));
X				vid_copy(NIL_PTR, vid_base, tp->tty_vid, n/2);
X			}
X			break;
X
X		    case 'L':		/* ESC [nL inserts n lines ar cursor */
X			n = value;
X			if (n < 1) n = 1;
X			if (n > (SCR_LINES - tp->tty_row)) 
X				n = SCR_LINES - tp->tty_row;
X
X			/* These are all relative to start of screen, ignoring
X			 * difficulties such as wraparound.  They are actually 
X			 * appropiate args to scr_down for soft_scroll case.
X			 */
X			src = (SCR_LINES - n) * LINE_WIDTH * 2 - 2;
X			dst = SCR_LINES * LINE_WIDTH * 2 - 2;
X			count = (SCR_LINES - n - tp->tty_row) * LINE_WIDTH;
X			if (softscroll)
X				limit = 0x7fff;   /* no wraparound possible */
X			else if (ega)
X				limit = SCR_BYTES;
X			else
X			limit = vid_mask + 1;
X
X			/*
X			 * The copy will have three phases: src and dest
X			 * wrapped around, dest wrapped around and src not,
X			 * and neither wrapped around 
X			 */
X			src += tp->tty_org;
X			dst += tp->tty_org;
X			if (src >= limit && dst >= limit) {
X				m = MIN (count, (src - limit) / 2 + 1);
X				l_scr_down(vid_base, src-limit, dst-limit, m);
X				count -= m;
X				src -= m * 2;
X				dst -= m * 2;
X			}
X			if (dst >= limit && count > 0) {
X				m = MIN (count, (dst - limit) / 2 + 1);
X				l_scr_down(vid_base, src, dst - limit, m);
X				count -= m;
X				src -= m * 2;
X				dst -= m * 2;
X			}
X			if (count > 0) l_scr_down(vid_base, src, dst, count);
X
X			/* OK, now let's clear the lines we inserted */
X			dst = tp->tty_row * LINE_WIDTH * 2;
X			count = n * LINE_WIDTH;
X			dst += tp->tty_org;
X			if (dst < limit) {
X				m = MIN (count, (limit - dst) / 2);
X				long_vid_copy(NIL_PTR, vid_base, dst, m);
X				count -= m;
X				dst += m * 2;
X			}
X			if (count > 0)
X			       long_vid_copy(NIL_PTR,vid_base,dst-limit,count);
X			break;
X
X		    case 'M':		/* ESC [nM deletes n lines at cursor */
X			n = value;
X			if (n < 1) n = 1;
X			if (n > (SCR_LINES - tp->tty_row)) 
X				n = SCR_LINES - tp->tty_row;
X
X			/* These are all relative to start of screen, ignoring 
X			 * difficulties such as wraparound.  They are actually 
X			 * appropiate args to scr_down for soft_scroll case.
X			 */
X			src = (tp->tty_row + n) * LINE_WIDTH * 2;
X			dst = (tp->tty_row) * LINE_WIDTH * 2;
X			count = (SCR_LINES - n - tp->tty_row) * LINE_WIDTH;
X			if (softscroll)
X				limit = 0x7fff;   /* no wraparound possible */
X			else if (ega)
X				limit = SCR_BYTES;
X			else
X				limit = vid_mask + 1;
X			/*
X			 * The copy will have three phases: src and dest
X			 * not wrapped, src wrapped dest not, both wrapped
X			 */
X			src += tp->tty_org;
X			dst += tp->tty_org;
X			if (src < limit && dst < limit) {
X				m = MIN (count, (limit - src) / 2);
X				l_scr_up(vid_base, src, dst, m);
X				count -= m;
X				src += m * 2;
X				dst += m * 2;
X			}
X			if (dst < limit && count > 0) {
X				m = MIN (count, (limit - dst) / 2);
X				l_scr_up(vid_base, src - limit, dst, m);
X				count -= m;
X				src += m * 2;
X				dst += m * 2;
X			}
X			if (count > 0) 
X				l_scr_up(vid_base, src-limit, dst-limit,count);
X
X			/* OK, now let's clear the lines at the bottom */
X			dst = (SCR_LINES - n) * LINE_WIDTH * 2;
X			count = n * LINE_WIDTH;
X			dst += tp->tty_org;
X			if (dst < limit) {
X				m = MIN (count, (limit - dst) / 2);
X				long_vid_copy(NIL_PTR, vid_base, dst, m);
X				count -= m;
X				dst += m * 2;
X			}
X			if (count > 0)
X			       long_vid_copy(NIL_PTR,vid_base,dst-limit,count);
X			break;
X
X		    case 'P':		/* ESC [nP deletes n chars at cursor */
X			n = value;
X			if (n < 1) n = 1;
X			if (n > (LINE_WIDTH - tp->tty_column))
X				n = LINE_WIDTH - tp->tty_column;
X			src = (tp->tty_row * LINE_WIDTH + tp->tty_column+n) *2;
X			dst = (tp->tty_row * LINE_WIDTH + tp->tty_column) * 2;
X			count = LINE_WIDTH - tp->tty_column - n;
X			src += tp->tty_org;
X			dst += tp->tty_org;
X			if ((! softscroll) && ega) {
X				if (src > SCR_BYTES) src -= SCR_BYTES;
X				if (dst > SCR_BYTES) dst -= SCR_BYTES;
X			}
X			scr_up(vid_base, src, dst, count);
X			vid_copy(NIL_PTR, vid_base, dst + count * 2, n);
X			break;
X
X		    case '@':  		/* ESC [n@ inserts n chars at cursor */
X			n = value;
X			if (n < 1) n = 1;
X			if (n > (LINE_WIDTH - tp->tty_column))
X				n = LINE_WIDTH - tp->tty_column;
X			src = (tp->tty_row * LINE_WIDTH + LINE_WIDTH- n-1) * 2;
X			dst = (tp->tty_row * LINE_WIDTH + LINE_WIDTH - 1) * 2;
X			count = LINE_WIDTH - tp->tty_column - n;
X			src += tp->tty_org;
X			dst += tp->tty_org;
X			if ((! softscroll) && ega) {
X				if (src > SCR_BYTES)
X					src -= SCR_BYTES;
X				if (dst > SCR_BYTES)
X					dst -= SCR_BYTES;
X			}
X			scr_down(vid_base, src, dst, count);
X			dst = (tp->tty_row * LINE_WIDTH + tp->tty_column) * 2;
X			dst += tp->tty_org;
X			if ((! softscroll) && ega) {
X				if (dst > SCR_BYTES) dst -= SCR_BYTES;
X			}
X			vid_copy(NIL_PTR, vid_base, dst, n);
X			break;
X
X	   	    case 'm':		/* ESC [nm enables rendition n */
X	 		switch (value) {
X 			    case 1: /*  BOLD  */
X				if (color)
X	 				tp->tty_attribute = /* red fg */
X					 	(attr & 0xf0ff) | 0x0400;
X				else
X		 			tp->tty_attribute |= 0x0800; /* inten*/
X 				break;
X 
X 			    case 4: /*  UNDERLINE */
X				if (color)
X					tp->tty_attribute = /* blue fg */
X					 (attr & 0xf0ff) | 0x0100;
X				else
X					tp->tty_attribute = /* ul */
X					 (attr & 0x8900);
X 				break;
X 
X 			    case 5: /*  BLINKING */
X				if (color) /* can't blink color */
X					tp->tty_attribute = /* magenta fg */
X					 (attr & 0xf0ff) | 0x0500;
X				else
X		 			tp->tty_attribute |= /* blink */
X					 0x8000;
X 				break;
X 
X 			    case 7: /*  REVERSE  (black on light grey)  */
X				if (color)
X	 				tp->tty_attribute = 
X					 ((attr & 0xf000) >> 4) |
X					 ((attr & 0x0f00) << 4);
X				else if ((attr & 0x7000) == 0)
X					tp->tty_attribute =
X					 (attr & 0x8800) | 0x7000;
X				else
X					tp->tty_attribute =
X					 (attr & 0x8800) | 0x0700;
X  				break;
X
X 			    default: if (value >= 30 && value <= 37) {
X					tp->tty_attribute = 
X					 (attr & 0xf0ff) |
X					 (ansi_colors[(value - 30)] << 8);
X					blank_color = 
X					 (blank_color & 0xf0ff) |
X					 (ansi_colors[(value - 30)] << 8);
X				} else if (value >= 40 && value <= 47) {
X					tp->tty_attribute = 
X					 (attr & 0x0fff) |
X					 (ansi_colors[(value - 40)] << 12);
X					blank_color =
X					 (blank_color & 0x0fff) |
X					 (ansi_colors[(value - 40)] << 12);
X				} else
X	 				tp->tty_attribute = blank_color;
X  				break;
X	 		}
X			break;
X
X	   	    default:
X			break;
X		}	/* closes switch(c) */
X	}	/* closes if (tp->tty_esc_intro == '[') */
X  }
X  tp->tty_esc_state = 0;
X}
X
X/*===========================================================================*
X *				long_vid_copy				     *
X *===========================================================================*/
XPRIVATE long_vid_copy(src, base, offset, count)
Xchar *src;
Xunsigned int base, offset, count;
X{
X  int ct;	
X/*
X * break up a call to vid_copy for machines that can only write
X * during vertical retrace.  Vid_copy itself does the wait.
X */
X
X  while (count > 0) {
X	ct = MIN (count, vid_retrace >> 1);
X	vid_copy(src, base, offset, ct);
X	if (src != NIL_PTR) src += ct * 2;
X	offset += ct * 2;
X	count -= ct;
X  }
X}
X
X/*===========================================================================*
X *				long_src_up				     *
X *===========================================================================*/
XPRIVATE l_scr_up(base, src, dst, count)
Xunsigned int base, src, dst, count;
X{
X  int ct, old_state, wait;
X
X  /*
X   * Break up a call to scr_up for machines that can only write
X   * during vertical retrace.  scr_up doesn't do the wait, so we do.
X   * Note however that we keep interrupts on during the scr_up.  This
X   * could lead to snow if an interrupt happens while we are doing
X   * the display.  Sorry, but I don't see any good alternative.
X   * Turning off interrupts makes us loses RS232 input chars.
X   */
X
X  wait = color && ! ega;
X  while (count > 0) {
X	if (wait) {
X		old_state = wait_retrace();
X		restore(old_state);
X	}
X	ct = MIN (count, vid_retrace >> 1);
X	scr_up(base, src, dst, ct);
X	src += ct * 2;
X	dst += ct * 2;
X	count -= ct;
X  }
X}
X
X/*===========================================================================*
X *				long_scr_down				     *
X *===========================================================================*/
XPRIVATE l_scr_down(base, src, dst, count)
Xunsigned int base, src, dst, count;
X{
X  int ct, old_state, wait;
X
X  /* Break up a call to scr_down for machines that can only write
X   * during vertical retrace.  scr_down doesn't do the wait, so we do.
X   * Note however that we keep interrupts on during the scr_down.  This
X   * could lead to snow if an interrupt happens while we are doing
X   * the display.  Sorry, but I don't see any good alternative.
X   * Turning off interrupts makes us loses RS232 input chars.
X   */
X
X  wait = color && ! ega;
X  while (count > 0) {
X	if (wait) {
X		old_state = wait_retrace();
X		restore(old_state);
X	}
X	ct = MIN (count, vid_retrace >> 1);
X	scr_down(base, src, dst, ct);
X	src -= ct * 2;
X	dst -= ct * 2;
X	count -= ct;
X  }
X}
X
X/*===========================================================================*
X *				set_6845				     *
X *===========================================================================*/
XPRIVATE set_6845(reg, val)
Xint reg;			/* which register pair to set */
Xint val;			/* 16-bit value to set it to */
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  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/* Similar, but used for registers where we only want to set one byte */
X
XPRIVATE setb6845(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);	/* output high byte */
X}
X
X/*===========================================================================*
X *				beep					     *
X *===========================================================================*/
XPRIVATE int beeping = 0;
XPRIVATE int stopbeep();
X
XPRIVATE beep(f)
Xint f;				/* this value determines beep frequency */
X{
X/* Making a beeping sound on the speaker (output for CRTL-G).  The beep is
X * kept short, because interrupts must be disabled during beeping, and it
X * is undesirable to keep them off too long.  This routine works by turning
X * on the bits in port B of the 8255 chip that drive the speaker.
X */
X
X  int k, s, x;
X  message mess;
X
X  if (beeping) return;
X  s = lock();			/* disable interrupts */
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  beeping = 1;
X  restore(s);			/* re-enable interrupts to previous state */
X
X  mess.m_type = SET_ALARM;
X  mess.CLOCK_PROC_NR = TTY;
X  mess.DELTA_TICKS = B_TIME;
X  mess.FUNC_TO_CALL = stopbeep;
X  sendrec(CLOCK, &mess);
X}
X
Xstopbeep() {
X  int s, x;
X
X  s = lock();			/* disable interrupts */
X  port_in(PORT_B,&x);		/* acquire status of port B */
X  port_out(PORT_B, x & 0xfffc);	/* turn bits 0 and 1 on to beep */
X  beeping = 0;
X  restore(s);			/* re-enable interrupts to previous state */
X}
X
X/*===========================================================================*
X *				set_leds				     *
X *===========================================================================*/
XPRIVATE set_leds()
X{
X/* Set the LEDs on the caps lock and num lock keys */
X
X  int count, leds, dummy, i, port;
X
X  if (pc_at == 0 && !ps) return;	/* PC/XT doesn't have LEDs */
X  leds = (numlock<<1) | (capslock<<2);	/* encode LED bits */
X
X  if (ps) {
X	port = PS_KEYBD;
X	count = PS_LED_DELAY;
X  } else {
X	count = LED_DELAY;
X	port = KEYBD;
X  }
X
X  port_out(port, LED_CODE);	/* prepare keyboard to accept LED values */
X  port_in(port, &dummy);	/* keyboard sends ack; accept it */
X  for (i = 0; i < count; i++) ;	/* delay needed */
X  port_out(port, leds);		/* give keyboard LED values */
X  port_in(port, &dummy);	/* keyboard sends ack; accept it */
X}
X
X/*===========================================================================*
X *				tty_init				     *
X *===========================================================================*/
XPRIVATE tty_init()
X{
X/* Initialize the tty tables. */
X
X  register struct tty_struct *tp;
X
X  /* Set initial values. */
X  caps_off = 1;
X  num_off = 1;
X
X  /* Tell the EGA card, if any, to simulate a 16K CGA card. */
X  port_out(EGA + INDEX, 4);	/* register select */
X  port_out(EGA + DATA, 1);	/* no extended memory to be used */
X
X  for (tp = &tty_struct[0]; tp < &tty_struct[NR_CONS]; tp++) {
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_makebreak = TWO_INTS;
X	tp->tty_attribute = BLANK;
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  }
X
X  if (color) {
X	vid_base = COLOR_BASE;
X	vid_mask = C_VID_MASK;
X	vid_port = C_6845;
X	vid_retrace = C_RETRACE;
X  } else {
X	vid_base = MONO_BASE;
X	vid_mask = M_VID_MASK;
X	vid_port = M_6845;
X	vid_retrace = M_RETRACE;
X  }
X
X  if (ega) {
X	vid_mask = C_VID_MASK;
X	vid_retrace = SCR_BYTES;
X	/* normally char height is 14 for EGA and 16 for VGA.  If your BIOS
X	 * doesn't put the char height here, then just use a constant.  This
X	 * should only be used by EGA code, as this value may not be set for
X	 * others.
X	 */
X	char_height = get_byte(0x40, 0x85);  
X  }
X  tty_driver_buf[1] = MAX_OVERRUN;	/* set up limit on keyboard buffering*/
X  set_6845(CUR_SIZE, 31);		/* set cursor shape */
X  set_6845(VID_ORG, 0);			/* use page 0 of video ram */
X  move_to(&tty_struct[0], 0, SCR_LINES-1); /* move cursor to lower left */
X
X  if (ps) {
X	set_leds();		/* turn off numlock led */
X	softscroll = TRUE;
X  }
X
X  /* Determine which keyboard type is attached.  The bootstrap program asks 
X   * the user to type an '='.  The scan codes for '=' differ depending on the
X   * keyboard in use.
X   */
X  switch(scan_code) {
X	case STANDARD_SCAN:	keyb_type = IBM_PC; break;
X	case OLIVETTI_SCAN: 	keyb_type = OLIVETTI; load_olivetti(); break;
X	case DUTCH_EXT_SCAN:	keyb_type = DUTCH_EXT;
X				load_dutch_table(); break;
X	case US_EXT_SCAN:	keyb_type = US_EXT;
X				load_us_ext(); break;
X  }
X}
X
X/*===========================================================================*
X *			load_dutch_table				     *
X *===========================================================================*/
XPRIVATE load_dutch_table()
X{
X/* Load the scan code to ASCII table for extended dutch keyboard. */
X
X  register int i;
X
X  for (i = 0; i < NR_SCAN_CODES; i++) {
X	sh[i] = dutch_sh[i];
X	unsh[i] = dutch_unsh[i];
X	alt_c[i] = dutch_alt[i];
X  }
X
X  minus_code = MINUS_DU;
X  num_slash = NUM_SLASH_DU;
X}
X
X/*===========================================================================*
X *			load_olivetti					     *
X *===========================================================================*/
XPRIVATE load_olivetti()
X{
X/* Load the scan code to ASCII table for olivetti type keyboard. */
X
X  register int i;
X
X  for (i = 0; i < NR_SCAN_CODES; i++) {
X	sh[i] = m24[i];
X	unsh[i] = unm24[i];
X  }
X}
X
X/*===========================================================================*
X *			load_us_ext					     *
X *===========================================================================*/
XPRIVATE load_us_ext()
X{
X/* Load the scan code to ASCII table for US extended keyboard. */
X
X  register int i;
X
X  for (i = 0; i < NR_SCAN_CODES; i++) {
X	sh[i] = sh_usx[i];
X	unsh[i] = unsh_usx[i];
X  }
X}
X
X/*===========================================================================*
X *				putc					     *
X *===========================================================================*/
XPUBLIC putc(c)
Xchar c;				/* character to print */
X{
X/* This procedure is used by the version of printf() that is linked with
X * the kernel itself.  The one in the library sends a message to FS, which is
X * not what is needed for printing within the kernel.  This version just queues
X * the character and starts the output.
X */
X
X  out_char(&tty_struct[0], c);
X}
X
X
X/*===========================================================================*
X *				func_key				     *
X *===========================================================================*/
XPRIVATE func_key(ch)
Xchar ch;			/* scan code for a function key */
X{
X/* This procedure traps function keys for debugging purposes.  When MINIX is
X * fully debugged, it should be removed.
X */
X
X  if (ch == F1) p_dmp();	/* print process table */
X  if (ch == F2) map_dmp();	/* print memory map */
X  if (ch == F3) {		/* hardware vs. software scrolling */
X	softscroll = 1 - softscroll;	/* toggle scroll mode */
X	tty_struct[0].tty_org = 0;
X	move_to(&tty_struct[0], 0, SCR_LINES-1); /* cursor to lower left */
X	set_6845(VID_ORG, 0);
X	if (ega) {
X		/* If EGA, reint line compare reg used for scrolling.
X		 * see comments in scroll code.
X		 */
X		setb6845(OVRFL_REG, 0x1f);
X        	setb6845(LINE_CMP, 0xff);
X	}
X
X	if (softscroll)
X		printf("\033[H\033[JSoftware scrolling enabled.\n");
X	else
X		printf("\033[H\033[JHardware scrolling enabled.\n");
X  }
X
X#ifdef AM_KERNEL
X#ifndef NONET
X  if (ch == F4) net_init();	/* re-initialise the ethernet card */
X#endif NONET
X#endif AM_KERNEL
X  if (ch == F9 && control) sigchar(&tty_struct[0], SIGKILL);	/* SIGKILL */
X}
+ END-OF-FILE console.c.new
chmod 'u=rw,g=r,o=r' 'console.c.new'
set `wc -c 'console.c.new'`
count=$1
case $count in
40525)	:;;
*)	echo 'Bad character count in ''console.c.new' >&2
		echo 'Count should be 40525' >&2
esac
echo Extracting 'const.h.cdif'
sed 's/^X//' > 'const.h.cdif' << '+ END-OF-FILE ''const.h.cdif'
X*** /local/ast/minix/tape3b/kernel/const.h	Fri Jul 15 20:31:25 1988
X--- const.h	Mon Sep 26 23:34:07 1988
X***************
X*** 30,35 ****
X--- 30,36 ----
X  #define PRINTER_VECTOR    15	/* line printer interrupt vector */
X  #define SYS_VECTOR        32	/* system calls are made with int SYSVEC */
X  #define AT_WINI_VECTOR	 118	/* at winchester interrupt vector */
X+ #define PS_KEYB_VECTOR	0x71	/* keyboard interrupt vector for PS/2 */
X  
X  /* The 8259A interrupt controller has to be re-enabled after each interrupt. */
X  #define INT_CTL         0x20	/* I/O port for interrupt controller */
X***************
X*** 37,42 ****
X--- 38,44 ----
X  #define INT2_CTL	0xA0	/* I/O port for second interrupt controller */
X  #define INT2_MASK	0xA1	/* setting bits in this port disables ints */
X  #define ENABLE          0x20	/* code used to re-enable after an interrupt */
X+ #define PCR		0x65	/* Planar Control Register */
X  #endif
X  
X  #define K_STACK_BYTES    512	/* how many bytes for the kernel stack */
+ END-OF-FILE const.h.cdif
chmod 'u=rw,g=r,o=r' 'const.h.cdif'
set `wc -c 'const.h.cdif'`
count=$1
case $count in
989)	:;;
*)	echo 'Bad character count in ''const.h.cdif' >&2
		echo 'Count should be 989' >&2
esac
exit 0