[comp.os.minix] RS-232 for MINIX

vandys@Lindy.UUCP (06/02/87)

	This is it, folks.  Multi-user MINIX has arrived.  Before you
throw away your VAX, though, perhaps you should be aware of the limitations.

1. Bugs
	There is at least one major bug left.  It is possible to cause a
panic in TTY by hitting return on both keyboards simultaneously a couple
of times.  Clearly a race condition, but only one of many I've found.
I'm running out of time here (back on the critical path), so I thought I'd
let some of the net talent help me out.

2. Shortcomings
	AST didn't put BAUD RATE into his TTY structs (good-bye, V7 standard).
ser_init() in tty.c does the setup, so it's only a one-baud-rate interface
currently.  The fix for this entails only legwork; if someone is interested
and doesn't have the reference manuals for the serial card, get in touch
with me & I'll send you the dope.  In brief, you'll have to fix the IOCTL's
for the TTY interface, and then add them to stty(1).

3. Modem control
	DTR and RTS are always driven high, and DSR is not honored.  Thus,
putting a login modem port will have the unfortunate characteristic of not
logging the user off when carrier is lost.  This area is actually a much
bigger rat's nest, and I'd only recommend implementing it to someone who
has experience with this sort of RS-232 interfacing.  If no one wants to
touch it, I'll work on this next.

4. Olivetti
	TTY was getting too enormous, so I tore out all the Olivetti code.
If you have an Olivetti-type keyboard, please be warned & don't honor my
changes in this area, particularly in tty.c.

	Overall, I'd say that doing the RS-232 interface for MINIX is about
twice as hard as it would be for UNIX.  The biggest problem is that the
entire TTY scheme is incredibly naive.  However, MINIX is in very distinguished
company for underestimating the difficulty of TTY interfaces: HP-1000 RTE-A,
Spectrum HP-UX, PC/RT 4.2BSD, and IX all stumbled in this area.  Hopefully, the
worst of it is now done.

5. inews
	Thinks the diffs are included text.  Remove the '|' at the
beginning of each line in the diffs.

	Please don't hesitate to mail me if you have any questions!

					Enjoy!
					Andrew Valencia
					vandys@lindy.stanford.edu
					br.ajv@rlg.BITNET

************************* Start of diffs *************************
| --- fs/misc.c ---
|170,175d169
|<   /* Loop on file descriptors, closing any that are open. */
|<   for (i=0; i < NR_FDS; i++) {
|< 	fd = i;
|< 	do_close();
|<   }
|< 
|185a180,188
|> 
|>   /* Loop on file descriptors, closing any that are open. */
|>   /* VANDYS: moved 'til after do_unpause() 'cause it looks at the */
|>   /*  inode of the file descriptor it's paused on. */
|>   for (i=0; i < NR_FDS; i++) {
|> 	fd = i;
|> 	do_close();
|>   }
|> 
| --- fs/pipe.c ---
|244c244,254
|< 	f = get_filp(rfp->fp_fd);
|---
|> 	struct fproc *tmpfil = fp;
|> 
|> 	  /*
|> 	   * VANDYS: get_filp() uses "fp", but I think we're needing to
|> 	   *  talk about "rfp" here
|> 	   */
|> 	fp = rfp;
|> 	if( (f = get_filp( (rfp->fp_fd >> 8) & 0xFF )) == 0 )
|> 	  panic("get_filp() = NULL");
|> 	fp = tmpfil;
|> 
| --- mm/getset.c ---
|28a29,32
|> 	case SETPGRP:
|> 		r = result2 = rmp->mp_procgrp = who;
|> 		break;
|> 
| --- mm/main.c ---
|56c56,57
|< 		error = E_BAD_CALL;
|---
|> 		panic("MM gets bad request",mm_call);
|> 		/* error = E_BAD_CALL; */
| --- mm/signal.c ---
|77a78
|> PRIVATE int tgrp;
|98a100
|>   tgrp = rmp->mp_procgrp;
|116c118
|< 	id = (i+1 == SIGINT || i+1 == SIGQUIT ? 0 : proc_id);
|---
|> 	id = ( (i+1 == SIGINT || i+1 == SIGQUIT) ? 0 : proc_id);
|145a148
|>   if( proc_id == 0 )
|159c162
|< 	if (proc_id == 0 && mp->mp_procgrp != rmp->mp_procgrp) send_sig = FALSE;
|---
|> 	if (proc_id == 0 && tgrp != rmp->mp_procgrp) send_sig = FALSE;
|160a164
|> 	if( proc_id == 0 )
| --- mm/table.c ---
|67c67
|< 	no_sys,		/* 38 = unused	*/
|---
|> 	do_getset,	/* 38 = setpgrp */
| --- kernel/floppy.c ---
|414d413
|<   extern int olivetti;
| --- kernel/main.c ---
|46a47
|>   extern int ser_int();
|125a127
|>   set_vec(RS232_VECTOR, ser_int, base_click);
| --- kernel/tty.c ---
|23,24c23
|<  *   TTY_CHAR_INT: a character has been typed on a terminal (input interrupt)
|<  *   TTY_O_DONE:   a character has been output (output completed interrupt)
|---
|>  *   TTY_INT:	   interrupt routines have produced work
|34c33
|<  * | TTY_O_DONE  |minor dev|         |         |         |         |         |
|---
|>  * | TTY_O_DONE  |minor dev| proc nr |  count  | replyee |         |         |
|58c57,63
|< #define NR_TTYS            1	/* how many terminals can system handle */
|---
|> #define RS232			/* Configured for RS-232 handling */
|> 
|> #ifdef RS232
|> #define NR_TTYS            2	/* how many terminals can system handle */
|> #else
|> #define NR_TTYS		   1	/* Only console */
|> #endif RS232
|81a87,93
|> #ifdef RS232
|> PRIVATE void ser_out(), ser_init(), ser_sneak();
|> PRIVATE void do_odone();
|> PRIVATE int ser_busy();
|> #endif
|> PRIVATE void tty_bad(), do_ttint();
|> 
|175,198d186
|< 
|< /* Scan codes to ASCII for Olivetti M24 for unshifted keys. */
|< PRIVATE char unm24[] = {
|<  0,033,'1','2','3','4','5','6',        '7','8','9','0','-','^','\b','\t',
|<  'q','w','e','r','t','y','u','i',      'o','p','@','[','\r',0202,'a','s',
|<  'd','f','g','h','j','k','l',';',      ':',']',0200,'\\','z','x','c','v',
|<  'b','n','m',',','.','/',0201,'*',     0203,' ',0204,0241,0242,0243,0244,0245,
|<  0246,0247,0250,0251,0252,023,0210,0267,0270,0271,0211,0264,0265,0266,0214,0261,
|< 0262,0263,'0','.',' ',014,0212,'\r',   0264,0262,0266,0270,032,0213,' ','/',
|<  0253,0254,0255,0256,0257,0215,0216,0217
|< };
|< 
|< /* Scan codes to ASCII for Olivetti M24 for shifted keys. */
|< PRIVATE char m24[] = {
|<  0,033,'!','"','#','$','%','&',        047,'(',')','_','=','~','\b','\t',
|<  'Q','W','E','R' ,'T','Y','U','I',     'O','P',0140,'{','\r',0202,'A','S',
|<  'D','F','G','H','J','K','L','+',      '*','}',0200,'|','Z','X','C','V',
|<  'B','N','M','<','>','?',0201,'*',     0203,' ',0204,0221,0222,0223,0224,0225,
|<  0226,0227,0230,0231,0232,0270,023,'7', '8','9',0211,'4','5','6',0214,'1',
|<  '2','3',0207,0177,0271,014,0272,'\r', '\b','\n','\f',036,032,0273,0274,'/',
|<  0233,0234,0235,0236,0237,0275,0276,0277
|< };
|< 
|< 
|211a200,203
|> 	if( (tty_mess.TTY_LINE < 0) || (tty_mess.TTY_LINE > (NR_TTYS-1)) ){
|> 	    tty_bad(&tty_mess);
|> 	    continue;
|> 	}
|214c206
|< 	    case TTY_CHAR_INT:	do_charint(&tty_mess);		break;
|---
|> 	    case TTY_INT:	do_ttint();			break;
|219,221c211,213
|< 	    case TTY_O_DONE:	/* reserved for future use (RS-232 terminals)*/
|< 	    default:		tty_reply(TASK_REPLY, tty_mess.m_source, 
|< 					tty_mess.PROC_NR, EINVAL, 0L, 0L);
|---
|> 	    default:
|> 		tty_bad(&tty_mess);
|> 		break;
|225a218,229
|>     /*
|>      * Flags for interrupt events for the TTYs
|>      */
|> char tt_in[NR_TTYS], tt_out[NR_TTYS];
|>     /*
|>      * Scan our various interrupt sources, call the appropriate routines
|>      *  for those who have work to do.
|>      */
|> PRIVATE void
|> do_ttint(){
|>     register x;
|>     register struct tty_struct *tp;
|226a231,276
|>     lock();
|>     for( x = 0; x < NR_TTYS; ++x )
|> 	if( tt_in[x] ){
|> 	    tt_in[x] = 0;
|> 	    unlock();
|> 	    do_charint();
|> 	    lock();
|> 	}
|> #ifdef RS232
|>     for( x = 1; x < NR_TTYS; ++x )
|> 	if( tt_out[x] ){
|> 	    tt_out[x] = 0;
|> 	    unlock();
|> 	    tp = &tty_struct[x];
|> 	    tty_reply(REVIVE, tp->tty_otcaller,
|> 		tp->tty_outproc, tp->tty_cum,0L,0L);
|> 	    lock();
|> 	}
|> #endif RS232
|>     unlock();
|> }
|> 
|>   /*
|>    * tty_bad()--dump out bad tty messages
|>    */
|> PRIVATE void
|> tty_bad(p)
|>   message *p;
|> {
|> #ifdef DEBUG
|>   register char *q = (char *)p;
|>   register x;
|> 
|>   printf("\nIllegal TTY message:\n");
|>   for( x = 1; x <= sizeof(message); ++x ){
|>     printf(" %2x", (*q++) & 0xFF);
|>     if( (x % 16) == 0 ) printf("\n");
|>   }
|>   printf("\n");
|> #else
|>   printf("m_type = %d\n",p->m_type);
|>   panic("TTY",p->TTY_LINE);
|> #endif DEBUG
|> }
|> 
|> 
|230,231c280
|< PRIVATE do_charint(m_ptr)
|< message *m_ptr;			/* message containing pointer to char(s) */
|---
|> PRIVATE do_charint()
|239,240c288,290
|<   int m, n, count, replyee, caller;
|<   char *ptr, *copy_ptr, ch;
|---
|>   register n;
|>   int m, count, replyee, caller;
|>   register char *ptr, *copy_ptr, ch;
|244c294
|<   ptr = m_ptr->ADDRESS;		/* pointer to accumulated char array */
|---
|>   ptr = tty_driver_buf;		/* pointer to accumulated char array */
|252,253c302
|<   ptr = m_ptr->ADDRESS;
|<   *ptr = 0;			/* accumulation count set to 0 */
|---
|>   tty_driver_buf[0] = 0;	/* accumulation count set to 0 */
|293,297d341
|<   /* Function keys are temporarily being used for debug dumps. */
|<   if (ch >= F1 && ch <= F10) {	/* Check for function keys F1, F2, ... F10 */
|< 	func_key(ch);		/* process function key */
|< 	return;
|<   }
|300,302c344,350
|<   if (tp->tty_makebreak)
|< 	ch = make_break(ch);	/* console give 2 ints/ch */
|<   else
|---
|>   if (tp->tty_makebreak){
|> 	if( ch >= F1 && ch <= F10 ){
|> 	  func_key(ch);
|> 	  return;
|> 	}
|> 	if( (ch = make_break(ch)) == 0 ) return;
|>   } else
|304d351
|<   if (ch == 0) return;
|362a410
|> #ifdef NOTDEF
|363a412
|> #endif NOTDEF
|368c417
|< 		cause_sig(LOW_USER + 1 + line, sig);
|---
|> 		cause_sig(LOW_USER+1+(line ? line+1 : 0),sig);
|413,423c462,467
|<   if (olivetti == FALSE) {
|< 	/* Standard IBM keyboard. */
|< 	code = (shift1 || shift2 || capslock ? sh[c] : unsh[c]);
|< 	if (control && c < TOP_ROW) code = sh[c];	/* CTRL-(top row) */
|< 	if (c > 70 && numlock) code = sh[c];	/* numlock depressed */
|<   } else {
|< 	/* (Olivetti M24 or AT&T 6300) with Olivetti-style keyboard. */
|< 	code = (shift1 || shift2 || capslock ? m24[c] : unm24[c]);
|< 	if (control && c < TOP_ROW) code = sh[c];	/* CTRL-(top row) */
|< 	if (c > 70 && numlock) code = m24[c];	/* numlock depressed */
|<   }
|---
|> 
|>   /* Standard IBM keyboard. */
|>   code = (shift1 || shift2 || capslock ? sh[c] : unsh[c]);
|>   if (control && c < TOP_ROW) code = sh[c];	/* CTRL-(top row) */
|>   if (c > 70 && numlock) code = sh[c];		/* numlock depressed */
|> 
|457,459c501,512
|<   if ( (tp->tty_mode & ECHO) == 0) return;	/* if no echoing, don't echo */
|<   if (c != MARKER) out_char(tp, c);
|<   flush(tp);			/* force character out onto the screen */
|---
|>     if ( (tp->tty_mode & ECHO) == 0) return;	/* if no echoing, don't echo */
|>     if( c != MARKER ){
|> 	if( tp == &tty_struct[0] ){
|> 	    out_char(tp, c);
|> 	    flush(tp);	/* force character out onto the screen */
|> #ifdef RS232
|> 	} else if( tp == &tty_struct[1] ){
|> 	    ser_sneak(tp,c);
|> #endif RS232
|> 	} else
|> 	    panic("Illegal TTY struct in echo()\n");
|>     }
|619a673,682
|> #ifdef RS232
|>     /*
|>      * Don't let more than one write come through at a time
|>      */
|>   if( (tp > tty_struct) && ser_busy(tp) ){
|>     tty_reply(TASK_REPLY, m_ptr->m_source,m_ptr->PROC_NR,E_TRY_AGAIN,0L,0L);
|>     return;
|>   }
|> #endif RS232
|> 
|631c694,695
|<   out_left = (vir_bytes) tp->tty_outleft;
|---
|>   /* out_left = (vir_bytes) tp->tty_outleft; */
|>   out_left = (vir_bytes) (m_ptr->COUNT);
|781a846
|> #define COM1		   1	/*   ...and for COM1: serial port */
|799,806d863
|< /* Definitions used for determining if the keyboard is IBM or Olivetti type. */
|< #define KB_STATUS	0x64	/* Olivetti keyboard status port */
|< #define BYTE_AVAIL	0x01	/* there is something in KEYBD port */
|< #define KB_BUSY	        0x02	/* KEYBD port ready to accept a command */
|< #define DELUXE		0x01	/* this bit is set up iff deluxe keyboard */
|< #define GET_TYPE	   5	/* command to get keyboard type */
|< #define OLIVETTI_EQUAL    12	/* the '=' key is 12 on olivetti, 13 on IBM */
|< 
|870,871c927
|< 	keybd_mess.m_type = TTY_CHAR_INT;
|< 	keybd_mess.ADDRESS = tty_driver_buf;
|---
|> 	tt_in[CONSOLE] = 1;
|1168a1225,1231
|>     /*
|>      * Our interrupt message; we specify 0 only to keep our sanity
|>      *  checks happy; this message merely causes a scan of ALL interrupts
|>      */
|>   keybd_mess.TTY_LINE = 0;
|>   keybd_mess.m_type = TTY_INT;
|> 
|1173d1235
|< 	tp->tty_devstart = console;
|1174a1237
|> 	tp->tty_devstart = console;
|1180a1244
|> 	tp->tty_makebreak = ONE_INT;
|1181a1246,1248
|> #ifdef RS232
|>   tty_struct[1].tty_devstart = ser_out;
|> #endif RS232
|1201,1205c1268,1273
|<   /* Determine which keyboard type is attached.  The bootstrap program asks 
|<    * the user to type an '='.  The scan codes for '=' differ depending on the
|<    * keyboard in use.
|<    */
|<   if (scan_code == OLIVETTI_EQUAL) olivetti = TRUE;
|---
|> #ifdef RS232
|>     /*
|>      * Now set up the RS-232 stuff
|>      */
|>   ser_init();
|> #endif RS232
|1238a1307,1581
|> 
|> #ifdef RS232
|> /*****************************************************************************/
|> /*****************************************************************************/
|> /*****************************************************************************/
|> /*****************************************************************************/
|> /*****************************************************************************/
|> /* RS-232 driver */
|> 
|> #define Base (0x3F0)		/* Base of registers */
|> #define LineReg (Base + 0x0B)	/* Line control register */
|> #define HighBaud (Base + 9)	/* Where to stuff baud rate */
|> #define LowBaud (Base + 8)
|> #define LineStat (Base + 0x0D)	/* Line status register */
|> #define LineData (Base + 8)	/* Transmit/Receive data register */
|> #define ModemReg (Base + 0x0C)	/* Modem line control register */
|> #define IntReg (Base + 9)	/* Interrupt control register */
|> #define IntId (Base + 0x0A)	/* Interrupt status register */
|> #define ModemStat (Base + 0x0E)	/* Modem status register */
|> 
|>     /*
|>      * Aliases for otherwise unused fields
|>      */
|>     /* Count of subrosa characters queued */
|> #define SNEAK tty_org
|>     /* Index to next slot for queueing a char */
|> #define SNEAKIN tty_vid
|>     /* Index to next place from which to dequeue a char */
|> #define SNEAKOUT tty_attribute
|>     /* Flag that TTY has no write request posted */
|> #define NEEDNEW tty_echar
|>     /* Segment & Offset for user's buffer in current I/O */
|> #define SEG tty_column
|> #define OFFSET tty_row
|>     /* Flags that CR has been sent for current LF in CRMOD */
|> #define RSFLAGS tty_esc_state
|> #define CRSENT 1
|> 
|>     /*
|>      * Continue transmitting if possible.  If possible, starts the transmit
|>      *  of another byte.  On return, we indicate whether we have already
|>      *  sent EOI (from within interrupt()) to the interrupt controller.
|>      */
|> PRIVATE
|> ser_cont(p,isr)
|>     register struct tty_struct *p;
|>     int isr;
|> {
|>     int c;
|> 
|> 	/*
|> 	 * By default, assume that no further transmit will start
|> 	 */
|>     p->tty_busy = 0;
|> 
|> 	/*
|> 	 * Keep an interrupt during a new I/O being set up from erroneously
|> 	 *  launching it before its time.
|> 	 */
|>     if( p->NEEDNEW ) return(0);
|> 
|> 	/*
|> 	 * There are more bytes in the current write request.
|> 	 *  Get the next one and send it off.
|> 	 */
|>     if( p->tty_outleft > 0 && p->tty_inhibited == RUNNING ){
|> 	c = get_byte(p->SEG,p->OFFSET++);
|> 	if( (c == '\n') && (p->tty_mode & CRMOD) &&
|> 	  !(p->RSFLAGS & CRSENT)){
|> 	    p->OFFSET -= 1;
|> 	    port_out(LineData,'\r');
|> 	    p->RSFLAGS |= CRSENT;
|> 	    p->tty_busy = 1;
|> 	    return(0);
|> 	} else
|> 	    p->RSFLAGS &= ~CRSENT;
|> 	p->tty_outleft -= 1;
|> 	p->tty_cum += 1;
|> 	port_out(LineData,c);		/* Start transmit */
|> 	p->tty_busy = 1;
|>     }
|> 
|> 	/*
|> 	 * Current request complete, tell our writer.  Flag that a new
|> 	 *  I/O must be queued before further data is valid.
|> 	 */
|>     if( p->tty_outleft == 0 ){
|> 	p->NEEDNEW = 1;
|> 	if( isr ){
|> 	    tt_out[p-tty_struct] = 1;
|> 	    interrupt(TTY, &keybd_mess);
|> 	    return(1);
|> 	} else {
|> 	  tty_reply(REVIVE,p->tty_otcaller,p->tty_outproc,p->tty_cum,0L,0L);
|> 	}
|>     }
|>     return(0);
|> }
|> 
|>     /*
|>      * ser_isr()--called when an interrupt occurs on the RS-232 port
|>      */
|> PUBLIC
|> ser_isr()
|> {
|>     int why_int;
|>     int c;
|>     register k;
|>     register struct tty_struct *p = &tty_struct[COM1];
|>     int cleared = 0;
|> 
|>     port_in(IntId,&why_int);
|> 
|> 	/*
|> 	 * If a byte is now readable, queue it to the main handler
|> 	 */
|>     if( 4 & why_int ){
|> 	port_in(LineData,&c);
|> 	if( (k = tty_driver_buf[0]) < tty_driver_buf[1] ){
|> 	    ++tty_driver_buf[0];
|> 	    tty_driver_buf[ (k += k) + 2 ] = c;	/* Store the char */
|> 	    tty_driver_buf[ k+3 ] = COM1;		/* And its source */
|> 
|> 	    tt_in[COM1] = 1;
|> 	    interrupt(TTY, &keybd_mess);
|> 	    return;
|> 	}
|>     }
|> 
|> 	/*
|> 	 * If a transmit has completed, see if the transmit can be
|> 	 *  continued with more data.
|> 	 */
|>     if( 2 & why_int ){
|> 
|> 	    /*
|> 	     * This is gross. Our TTY routines need to be able to emit
|> 	     *  data, but doing it the "conventional" way will hose an
|> 	     *  on-going write.  So this is a subrosa way for the data
|> 	     *  to trickle out to the user
|> 	     */
|> 	if( p->SNEAK ){
|> 	    port_out( LineData, p->tty_ramqueue[++(p->SNEAKOUT)] );
|> 	    p->SNEAK -= 1;
|> 	    if( p->SNEAKOUT >= TTY_RAM_WORDS ) p->SNEAKOUT = 0;
|> 
|> 	    /*
|> 	     * No "sneak-in" traffic, so process the interrupt
|> 	     *  conventionally
|> 	     */
|> 	} else
|> 	    cleared = ser_cont(p,1);
|>     }
|>     if( !cleared ) port_out(INT_CTL,ENABLE);
|> }
|> 
|>     /*
|>      * Slip kernel-generated traffic into the transmit stream
|>      */
|> PRIVATE void
|> ser_sneak(p,c)
|>     register struct tty_struct *p;
|>     int c;
|> {
|>     register x;
|> 
|>     if( (c == '\n') && (p->tty_mode & CRMOD) ) ser_sneak(p,'\r');
|>     lock();
|>     if( !p->tty_busy ){			/* Nothing happening, just send */
|> 	port_out( LineData, c );
|> 	p->tty_busy = 1;
|> 	unlock();
|> 	return;
|>     }
|> 
|> 	/*
|> 	 * Transmitter currently busy, so queue it FIFO
|> 	 */
|>     x = p->SNEAKIN;
|>     if( x >= TTY_RAM_WORDS ) x = 0;
|>     else ++x;
|>     if( x == p->SNEAKOUT ){
|> 	unlock();	/* Too much echoing garbage */
|> 	return;
|>     }
|>     p->tty_ramqueue[x] = c;
|>     p->SNEAK += 1;
|>     p->SNEAKIN = x;
|>     unlock();
|> }
|> 
|>     /*
|>      * Queue the data for transmission
|>      */
|> PRIVATE void
|> ser_out(p)
|>     register struct tty_struct *p;
|> {
|> 	/*
|> 	 * This will only be 0 for new write requests.  Since RS-232
|> 	 *  I/O will never complete immediately, we always send back
|> 	 *  a suspend response to FS (to keep from locking it up)
|> 	 * If it is non-zero, then we are merely being called to restart
|> 	 *  I/O, probably after a control-S/control-Q flow control sequence.
|> 	 */
|>     if( p->tty_cum == 0 ){
|> 	p->SEG = (p->tty_phys >> 4) & WORD_MASK;
|> 	p->OFFSET = p->tty_phys & OFF_MASK;
|> 	tty_reply(TASK_REPLY,p->tty_otcaller,p->tty_outproc,SUSPEND,0L,0L);
|> 	p->NEEDNEW = 0;
|>     }
|> 
|> 	/*
|> 	 * "Continue" the transmit with the data we have
|> 	 */
|>     lock();
|>     if( !p->tty_busy )
|> 	ser_cont(p,0);
|>     unlock();
|> }
|> 
|>     /*
|>      * ser_init()--set baud rate, bits/char, etc
|>      * NOTE: due to the lack of appropriate IOCTL's, this routine is the
|>      *  only place that gets to set up your TTY.  I'll fix this in a later
|>      *  release.  This entails adding stuff to the ioctl routine above,
|>      *  plus adding the smarts to stty(1)
|>      */
|> PRIVATE void
|> ser_init(){
|>     int c;
|>     register struct tty_struct *p = &tty_struct[COM1];
|> 
|>     lock();
|>       /*
|>        * Initialize our fields
|>        */
|>     p->SNEAK = p->SNEAKIN = p->SNEAKOUT = 0;
|>     p->NEEDNEW = 1;
|>     p->tty_busy = p->tty_outleft = 0;
|> 
|>     port_out(LineReg,0);
|>     port_out(IntReg,0);
|>     port_out(LineReg, 0x80);
|>     port_out(HighBaud, 1);	/* 300 baud */
|>     port_out(LowBaud, 0x80);
|>     port_out(LineReg, 0x03);	/* 8 bits, no parity */
|>     port_in(LineStat, &c);	/* Clear any data from controller */
|>     if( c & 1 ) port_in(LineData,&c);
|>     port_in(ModemStat,&c);
|> 
|>     port_in(ModemReg,&c);
|>     c |= 0x0B;			/* DTR, RTS on, interrupts selected */
|>     port_out(ModemReg,c);
|>     port_out(IntReg,3);		/* Select TX & RX interrupts */
|>     unlock();
|> 	/* Note: when we have SIGHUP handling, we will have to add */
|> 	/*  the modem lines to the list of interrupt sources */
|> }
|> 
|>   /*
|>    * Tell whether the given TTY is currently busy with an I/O
|>    *  request
|>    */
|> PRIVATE int
|> ser_busy(p)
|>   struct tty_struct *p;
|> {
|>   return( !p->NEEDNEW );
|> }
|> #else
|> ser_isr(){
|>   panic("COM1 interrupt",0);
|> }
|> #endif RS232
| --- kernel/const.h ---
|24a25
|> #define RS232_VECTOR	  12	/* RS-232 COM1: interrupt vector */
| --- kernel/glo.h ---
|14d13
|< EXTERN int olivetti;		/* TRUE for Olivetti-style keyboard */
| --- kernel/mpx88.s ---
|12a13
|> |   ser_int:	interrupt routine for IRQ4 COM1: events
|33c34
|< .globl _s_call, _surprise, _trp, _divide, _restart
|---
|> .globl _s_call, _surprise, _trp, _divide, _restart, _ser_int
|37c38
|< .globl _pr_char, _div_trap
|---
|> .globl _pr_char, _div_trap, _ser_isr
|98a100,106
|> |*
|> |* ser_int
|> |*
|> _ser_int:			| Interupt routine for asynch. RS-232 events
|> 	call save
|> 	call _ser_isr
|> 	jmp _restart
| --- h/callnr.h ---
|33a34
|> #define SETPGRP		  38
| --- h/com.h ---
|43,44c43,44
|< #	define TTY_CHAR_INT 1	/* fcn code for tty input interrupt */
|< #	define TTY_O_DONE  2	/* fcn code for tty output done */
|---
|> #	define TTY_INT	   1	/* fcn code for tty input interrupt */
|> /* -- TTY_O_DONE removed due to new interrupt scheme VANDYS */
| --- tools/init.c ---
|92a93
|> 	setpgrp();				/* Move to our own pgrp */
************************* End of diffs *************************

						Fiat Lux

vandys@Lindy.UUCP (06/03/87)

	Well, I had to forget something.  This is needed to build the
modified init.c.  Incidentally, I have a trick for linking against modules
which aren't in the main C library (libc.a).  I have built a second library,
named libaux.a, and I put all new modules in there (for instance, the
getgrent & getpwent modules).  Then when I compile, I say something like:
% cc -o foo foo.c -laux
	to search the library.  Of course, the standard library is then
searched after libaux.a.

				Good luck!
				Andy Valencia

---- Cut here for setpgrp.c ----
#include "../include/lib.h"

PUBLIC int setpgrp()
{
  return callm1(MM, SETPGRP, 0, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
}