[comp.os.minix] minix/ST adding midi

hcj@lzaz.ATT.COM (HC Johnson) (01/04/89)

This is midi.shar, the new midi files for adding rs232 and midi to
minix-st.
==============================================================
echo extracting 'midi.c'
sed -e 's/^X//' >midi.c <<'SHAR_EOF'
X/* MIDI driver */
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 "proc.h"
X#include "tty.h"
X#include "stacia.h"
X#include "staddr.h"
X#include "glo.h"
X#include "ring.h"
X
XPRIVATE dbg_flag = 0;
XPRIVATE Tx_active = 0;
XPRIVATE Tx_int = 0;
XPRIVATE message	commes;		/* message used for console input chars */
X
XPUBLIC struct ring midiring;
X#define COM_OUT_SIZE 512
XPRIVATE  char	com_out_buffer[COM_OUT_SIZE];
X
X#define COM_IN_SIZE 512
XPRIVATE  char	com_in_buffer[COM_IN_SIZE];
X
XPRIVATE int midi_o_flag = 0;
X
Xextern int Midi_wempty ;
X
X/*
X * This file contains the device_dependent part of the midi driver.
X *
X */
X
X/*===========================================================================*
X *				open 					     *
X *===========================================================================*/
XPRIVATE int open(tp)
Xregister struct tty_struct *tp;
X{
X	int s;
X	int i;
X	int midiinit();
X
X	midi_o_flag = 1;
X		s = lock();
X		midiinit(tp); /* will turn off all interrupts */
X		tp->tty_inhead = tp->tty_inqueue;
X		tp->tty_intail = tp->tty_inqueue;
X		tp->tty_mode = RAW;
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_baud   = 0;
X
X		tp->tty_inhibited = 0;
X
X
X	restore(s);
X	MDI->ac_cs = MDI_INIT | A_RXINT;
X}
X
X
X/*===========================================================================*
X *				close 					     *
X *===========================================================================*/
XPRIVATE int close(tp)
Xregister struct tty_struct *tp;
X{
X	midi_o_flag = 0;
X	MDI->ac_cs = A_RESET;
X	MDI->ac_cs = MDI_INIT ;
X}
X/*===========================================================================*
X *				ioctl 					     *
X *===========================================================================*/
X
XPRIVATE int ioctl(tp,m_ptr)
Xregister struct tty_struct *tp;
Xmessage *m_ptr;
X{
X  int i;
X
X  switch(m_ptr->TTY_REQUEST) {
X     case TIOCSTART:
X	open(tp);
X	return(OK);
X     case TIOCSTOP:
X	close(tp);
X	return(OK);
X     default:
X	return(EINVAL);
X  }
X}
X
X  
X
X/*===========================================================================*
X *				start					     *
X *===========================================================================*/
X
XPRIVATE int start(tp)
Xregister struct tty_struct *tp;
X{
X	int r;
X	int i;
X	register int k;	
X
Xmidi_o_flag = 1;;
X	if(midi_o_flag == 0) {
X		midi_o_flag++;
X		r = lock();
X		open();
X	
X		restore(r);
X	}
X
X	if (tp->tty_outleft == 0)
X		return(1);
Xif(dbg_flag)
Xprintf("Start left=%d\n\r",tp->tty_outleft);
X	do {
X		if((r = midienque( *(char*)tp->tty_phys)) == 0)
X			break;
X		tp->tty_phys++;
X		tp->tty_cum++;		/* number of characters printed */
X	} while ( --tp->tty_outleft != 0 );
X	midiqstart();
X	return(r);
X}
X/*===========================================================================*
X *				echo	 				     *
X *===========================================================================*/
XPRIVATE echo(tp, c)
Xregister struct tty_struct *tp;
X{
X  midienque(c);
X  midiqstart();
X}
X/*
X * This file contains the device_dependent part of the midi driver.
X *
X */
X
XPRIVATE midiput(c)
X{
Xif(dbg_flag)
Xprintf("midiput(%x)\n",c);
X	while(( MDI->ac_cs & A_TXRDY) == 0) ;
X	MDI->ac_cs = MDI_INIT | A_RXINT;
X	MDI->ac_da = c;
X	return(1);
X}
X
X/*===========================================================================*
X *				mdiint					     *
X *===========================================================================*/
X
XPUBLIC mdiint()
X{
X	int i,s;
X	register k;
X
Xif(dbg_flag)
Xprintf("mdiint()\n\r");
X	k = midiring.i_tail;
X/* we want to lock up here looking for an input burst */
X	for (s=0; s<10000; s++) {
X	for (;((i = MDI->ac_cs) & A_IRQ) ; ) {
X		if( i & A_RXRDY)  {
X			midirrdy();
X			s = 0;
X			continue;
X		}
X		if(Tx_int && (i & A_TXRDY)) {
X			Tx_int = 0;
X			midiqstart();
X		}
X	}
X	}
X	if ( k != midiring.i_tail) {
X		midicharint();
X	}
X}
X
Xmidiqstart()
X{
X	int n,s;
X
X	if(Tx_int) { /* its active */
X		return;
X	}
X	if(Tx_active)  { /* send in progress */
X		while(( MDI->ac_cs & A_TXRDY) == 0) ;
X		MDI->ac_cs = MDI_INIT | A_RXINT;
X	}
X	if((n = midiring.o_tail - midiring.o_head) < 0)
X		n += midiring.o_length;
X
X	if(n == 0) {
X		restore(s);
X		return;
X	} else if (n == 1) {
X		Tx_active = 1;
X		Tx_int = 0;
X		MDI->ac_cs = MDI_INIT | A_RXINT;
X		MDI->ac_da = midideque();
X		Midi_wempty = 1;
X		midicharint();
X	} else {
X		Tx_active = 0;
X		Tx_int = 1;
X		MDI->ac_cs = MDI_INIT | A_RXINT | A_TXINT;
X		MDI->ac_da = midideque();
X	}
X}
X
X
XPUBLIC midicharint()
X{
X	/* Build and send the interrupt message. */
Xif(dbg_flag)
Xprintf("mdi_rrdy charint msg n=%d\n\r",midiring.i_tail - midiring.i_head);
X	commes.m_type = TTY_CHAR_INT;
X	commes.ADDRESS = (char *)&midiring ;
X	interrupt(MIDI, &commes);	/* send message to tty task */
X}
X
X
X/*===========================================================================*
X *				midi_init				     *
X *===========================================================================*/
XPUBLIC midiinit(tp)
Xregister struct tty_struct *tp;
X{
X  int i;
X  struct ring *rp = &midiring;
X
X
X	rp->i_buffer = com_in_buffer;
X	rp->i_length = COM_IN_SIZE;
X	rp->i_head = 0;
X	rp->i_tail = 0;
X	rp->i_lo_water = (TTY_IN_BYTES / 16);	/* restart at this level */
X	rp->i_hi_water = (TTY_IN_BYTES / 4);	/* send xoff function at this level */
X	rp->i_lo_water = (16);	/* restart at this level */
X	rp->i_hi_water = (64);	/* send xoff function at this level */
X
X	rp->o_buffer = com_out_buffer;
X	rp->o_length = COM_OUT_SIZE;
X	rp->o_head = 0;
X	rp->o_tail = 0;
X	rp->o_lo_water = COM_OUT_SIZE / 4;
X	rp->o_hi_water = 3 * COM_OUT_SIZE / 4;
X
X	rp->rx_stat = 0;
X	rp->tx_stat = 0;
X	rp->xoff_flag = 0;
X	rp->xon_flag = 0;
X	rp->rtscts = 1;
X	rp->xoff_char = XOFF_CHAR;
X	rp->xon_char = XON_CHAR;
X
X  tp->tty_start = start;
X  tp->tty_echo = echo;
X  tp->tty_open = open;
X  tp->tty_close = close;
X  tp->tty_ioctl = ioctl;
X	MDI->ac_cs = A_RESET;
X	MDI->ac_cs = MDI_INIT ;
X}
X/*===========================================================================*
X *				midi_dmp				     *
X *===========================================================================*/
Xmidi_dmp()
X{
X	dbg_flag ^=1;
X	printf("DMP:dbg_flag=%d ohead=%d otail=%d ihead=%d itail=%d \n\r",
X		dbg_flag,
X		midiring.o_head, midiring.o_tail,
X		midiring.i_head, midiring.i_tail
X		);
X	printf("\tring flgs: tx=%x rx=%x xoff=%x on=%x dtrcts=%x\n\r",
X		midiring.rx_stat, midiring.tx_stat,
X		midiring.xoff_flag, midiring.xon_flag,
X		midiring.rtscts);
X}
XMddeguger(x)
X{
X	printf("Mddeguger(%x)\n",x);
X}
SHAR_EOF
echo extracting 'midis.s'
sed -e 's/^X//' >midis.s <<'SHAR_EOF'
X#define MIDI_RING
X#ifdef MIDI_RING
X
X! entry points
X	.define	_midiget	!get chars from input ring
X	.define	_midienque	!put chars to output ring
X	.define	_midideque	!take chars from output ring
X	.define	_midirrdy	!process rec char interrupt
X
X	.extern	_midiring	!input and output rings
X	.extern	_Midi_wempty	!a flag cleared in do_odone
X	.extern	_midicharint
X
X	.extern _Mddeguger
X
X	.sect	.text
X	.sect	.rom
X	.sect	.data
X	.sect	.bss
X
X	.sect	.text
X_setjmp:
X!
X!  ring buffer offsets locked to ring.h
X!
Xi_buffer = 0
Xi_length = 4
Xi_head = 6
Xi_tail = 8
Xi_lo_wat = 0xa
Xi_hi_wat = 0xc
Xo_buffer = 0xe
Xo_length = 0x12
Xo_head = 0x14
Xo_tail = 0x16
Xo_low_wat = 0x18
Xo_hi_wat = 0x1a
Xrs_data = 0x1c
Xts_data = 0x1d
Xxoff_flag = 0x1e
Xxon_flag = 0x1f
Xrtscts_flag = 0x20
Xxoff_char = 0x21
Xxon_char  = 0x22
X
Xac_cs = 0
Xac_da = 2
X
X	.sect	.text
X! setup a0, a1 for routines
Xmidiptr:
X	lea	_midiring,a0		! pointer to midi iorec
X	lea	0xfffffc04,a1		! pointer to mfp
X	rts		! 4e75
X
X_midienque:
X	move.w	4(a7), d1
X	movem.l	d2,-(a7)		!  save regs
X	move.w	sr,-(a7)		! save status
X	or.w	#0x700,sr		! IPL 7, disable interrupts
X	bsr	midiptr			! get buffer pointer
X
X	move.w	o_tail(a0),d2		! tail index
X	bsr	wrapout		! test for wrap around
X	cmp.w	o_head(a0),d2		! compare with head index
X	beq	L7		! same, buffer is full
X	move.l	o_buffer(a0),a1		! get current buffer address
X	move.b	d1,0x0(a1,d2.w)		! write char in buffer
X	move.w	d2,o_tail(a0)		! save new tail index
X
X	move.l	#1,d0			! char sent
XL6:
X	move	(a7)+,sr		! restore status
X	movem.l	(a7)+,d2		! restore regs
X	rts		! 4e75
XL7:
X	move.l	#0,d0			! char not sent
X	bra	L6
X
X
X_midideque: !midi input
X	movem.l	d2,-(a7)		!  save regs
X	move	sr,-(a7)		! save status
X	or.w	#0x700,sr		! IPG 7, disable interrupts
X	bsr	midiptr		! get midi pointer
X	move	o_head(a0),d1		! head index
X	cmp.w	o_tail(a0),d1		! tail index
X	beq	G10		! no char in buffer ?
X	bsr	wrapin		! test for wrap arround
X	move.l	o_buffer(a0),a1		! get buffer address
X	move.l	#0x0,d0		! 7000
X	move.b	0x0(a1,d1.w),d0		! get char from the buffer
X	move	d1,o_head(a0)		! set new head index
X	bra	G9		! 6006
XG10:
X	move.w	#0x100,d0	!1xx if no char
X
XG9:
X	move	(a7)+,sr		! restore status
X	movem.l	(a7)+,d2		! restore regs
X	rts		! 4e75
X
X_midiget: !midi input
X	movem.l	d2-d3,-(a7)		!  save regs
X	move	sr,-(a7)		! save status
X	or.w	#0x700,sr		! IPL 7, disable interrupts
X	bsr	midiptr		! get midi pointer
X	move	i_head(a0),d1		! head index
X	cmp.w	i_tail(a0),d1		! tail index
X	beq	L10		! no char in buffer ?
X	bsr	wrapin		! test for wrap arround
X	move.l	i_buffer(a0),a1		! get buffer address
X	move.l	#0x0,d0		! 7000
X	move.b	0x0(a1,d1.w),d0		! get char from the buffer
X	move	d1,i_head(a0)		! set new head index
X	bra	L9		! 6006
XL10:
Xmove.w	#0x100,d0	!1xx if no char
X
XL9:
X	move	(a7)+,sr		! restore status
X	movem.l	(a7)+,d2-d3		! restore regs
X	rts		! 4e75
X
X!midi receiver interrupt routine
X! called as a C program
X_midirrdy:
Xrcvint: 
X	movem.l	d2-d3/a2,-(a7)		!  save regs
X	bsr	midiptr		! get midi pointer
X	move.b	ac_da(a1),d0		! read data from rec. register
X	move	i_tail(a0),d1		! 3228 0008
X	bsr	wrapin		! 6100 01f8
X	cmp.w	i_head(a0),d1		! b268 0006
X	beq	R2		! yes, head == tail
X	move.l	i_buffer(a0),a2		! get buffer address
X	move.b	d0,0x0(a2,d1.w)		!  put.data in the buffer
X	move	d1,i_tail(a0)		! save new tail index
XR2:
X	movem.l	(a7)+,d2-d3/a2		! restore regs
X	rts
X
Xwrapin: !test for wrap arround
X	add.w	#1,d1		! head index + 1
X	cmp.w	i_length(a0),d1		! equal to buffer size ?
X	bcs	W1		! no
X	move.l	#0x0,d1		! else start with zero again
XW1:
X	rts		! 4e75
X
Xwrapout: !test for wrap arround
X	add.w	#1,d2		! tail index +1
X	cmp.w	o_length(a0),d2		! equal to buffer size?
X	bcs	W2		! no
X	move.l	#0x0,d2		! else start with zero again
XW2:
X	rts		! 4e75
X
X
X#endif ATARI_ST
SHAR_EOF
echo extracting 'miditty.c'
sed -e 's/^X//' >miditty.c <<'SHAR_EOF'
X/*
X * This file contains the device-independent part of the terminal driver.
X * The device-independent part accepts characters to be printed from
X * programs and queues them in a standard way for device-dependent output.
X * It also accepts input and queues it for programs.
X * This file contains one entry point: midi_task().
X * It accepts not only messages about typed input, but
X * also requests to read and write from terminals, etc. 
X *
X * The valid messages and their parameters are:
X *
X *   MIDI_CHAR_INT: a character has been typed on a terminal (input interrupt)
X *   MIDI_O_DONE:   a character has been output (output completed interrupt)
X *   MIDI_READ:     a process wants to read from a terminal
X *   MIDI_WRITE:    a process wants to write on a terminal
X *   MIDI_IOCTL:    a process wants to change a terminal's parameters
X *   MIDI_SETPGRP:  indicate a change in a control terminal
X *   CANCEL:       terminate a previous incomplete system call immediately
X *
X *    m_type      MIDI_LINE   PROC_NR    COUNT   MIDI_SPEK  MIDI_FLAGS  ADDRESS
X * ---------------------------------------------------------------------------
X * | MIDI_CHAR_INT|         |         |         |         |         |array ptr|
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | MIDI_O_DONE  |minor dev|         |         |         |         |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | MIDI_READ    |minor dev| proc nr |  count  |         |         | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | MIDI_WRITE   |minor dev| proc nr |  count  |         |         | buf ptr |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | MIDI_IOCTL   |minor dev| proc nr |func code|erase etc|  flags  |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | MIDI_SETPGRP |minor dev| proc nr |         |         |         |         |
X * |-------------+---------+---------+---------+---------+---------+---------|
X * | CANCEL      |minor dev| proc nr |         |         |         |         |
X * ---------------------------------------------------------------------------
X */
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 "proc.h"
X#include "tty.h"
X#include "ring.h"
X
X/* IN_CANON will be dis-asserted when set, noop if == 0 */
X
XPRIVATE int Rs_blocked = 0;
XPUBLIC struct tty_struct miditty_struct[1];
X
X#define DBG(x) printf(x);
X
X
X/*===========================================================================*
X *				midi_task				     *
X *===========================================================================*/
XPUBLIC midi_task()
X{
X/* Main routine of the terminal task. */
X
X  message miditty_mess;		/* buffer for all incoming messages */
X  register struct tty_struct *tp;
X
X  miditty_init();			/* initialize */
X  while (TRUE) {
X	receive(ANY, &miditty_mess);
X	tp = &miditty_struct[miditty_mess.TTY_LINE];
X	if(tp->tty_incount == 0 && Rs_blocked)
X	    do_charint(&miditty_mess);
X	switch(miditty_mess.m_type) {
X	    case MIDI_CHAR_INT:	do_charint(&miditty_mess);		break;
X	    case MIDI_READ:	do_read(tp, &miditty_mess);		break;
X	    case MIDI_WRITE:	do_write(tp, &miditty_mess);	break;
X	    case MIDI_IOCTL:	do_ioctl(tp, &miditty_mess);	break;
X	    case MIDI_SETPGRP:   do_setpgrp(tp, &miditty_mess);	break;
X	    case MIDI_OPEN:      do_open(tp, &miditty_mess);	break;
X	    case MIDI_CLOSE:     do_close(tp, &miditty_mess);	break;
X	    case CANCEL   :	do_cancel(tp, &miditty_mess);	break;
X	    case MIDI_O_DONE:	break; /* reserved for future use (RS-232 terminals)*/
X	    default:		tty_reply(TASK_REPLY, miditty_mess.m_source, 
X					miditty_mess.PROC_NR, EINVAL, 0L, 0L);
X	}
X  }
X}
X
X
X/*===========================================================================*
X *				do_close					     *
X *===========================================================================*/
XPRIVATE do_close(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xmessage *m_ptr;			/* message containing pointer to char(s) */
X{
X	int minor;
X	minor = m_ptr->DEVICE;
X	(*tp->tty_close)(tp);
X	tty_reply(TASK_REPLY, m_ptr->m_source, 
X		m_ptr->PROC_NR, OK, 0L, 0L);
X}
X
X/*===========================================================================*
X *				do_open					     *
X *===========================================================================*/
XPRIVATE do_open(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xmessage *m_ptr;			/* message containing pointer to char(s) */
X{
X	int minor;
X	return; /* we do not know how to handle this and set pgrp also */
X}
X
X/*===========================================================================*
X *				do_odone				     *
X *===========================================================================*/
XPUBLIC int Midi_wempty = 0;
XPRIVATE do_odone(tp)
Xstruct tty_struct *tp;
X{
X	unsigned char *ptr;
X
X	Midi_wempty = 0;
X/* there may be more to send */
X  if ((*tp->tty_start)(tp))	/* copy data to queue and start I/O */
X	finish(tp, tp->tty_cum);
X}
X
X/*===========================================================================*
X *				do_charint				     *
X *===========================================================================*/
Xstatic cnt_max = 0;
XPRIVATE do_charint(m_ptr)
Xmessage *m_ptr;			/* message containing pointer to char(s) */
X{
X/* A character has been typed.  If a character is typed and the tty task is
X * not able to service it immediately, the character is accumulated within
X * the tty driver.  Thus multiple chars may be accumulated.  A single message
X * to the tty task may have to process several characters.
X */
X
X  int m, n, count, replyee, caller, s;
X  char   ch;
X  struct tty_struct *tp;
X  struct ring *ptr;
X
X  if(Midi_wempty)
X	  do_odone(miditty_struct);
X  Rs_blocked = 0;
X  ptr = (struct ring*)m_ptr->ADDRESS;		/* pointer to accumulated char array */
X  while(ptr->i_head != ptr->i_tail) {
X
X	tp = &miditty_struct[0];	/* pointer to struct for this character */
X	if (tp->tty_incount >= TTY_IN_BYTES-4) {
X		Rs_blocked |= 1;
X		break;
X	}
X	
X	m = midiget();
X 	if((m & 0x100))
X		break;
X	ch = m ;
X	n = COM0;	/* get the line number it came in on */
X
X	m= in_char(n, ch&0377);	/* queue the char and echo it */
X
X	/* See if a previously blocked reader can now be satisfied. */
X	if (tp->tty_inleft > 0 ) {	/* does anybody want input? */
X		m = tp->tty_mode & (CBREAK | RAW);
X		if (tp->tty_lfct > 0 ||
X		    (m != 0 && tp->tty_incount > 0) ||
X		    (((tp->tty_mode & IN_CANON) ) &&
X			 tp->tty_incount >= tp->tty_eof)
X		    ) {
X
X
X			m = rd_chars(tp,m_ptr);
X
X			/* Tell hanging reader that chars have arrived. */
X			replyee = (int) tp->tty_incaller;
X			caller = (int) tp->tty_inproc;
X			tty_reply(REVIVE, replyee, caller, m, 0L, 0L);
X		}
X	}
X  }
X}
X
X
X/*===========================================================================*
X *				in_char					     *
X *===========================================================================*/
XPRIVATE in_char(line, ch)
Xint line;			/* line number on which char arrived */
Xint ch;				/* code for character that arrived */
X{
X/* A character has just been typed in.  Process, save, and echo it. */
X
X  register struct tty_struct *tp;
X  int mode;
X
X  tp = &miditty_struct[line];	/* set 'tp' to point to proper struct */
X  if (tp->tty_incount >= TTY_IN_BYTES) {
X	return(0);	/* no room, discard char */
X}
X  mode = tp->tty_mode & (RAW | CBREAK);
X  if (mode != RAW) ch &= 0177;	/* 7-bit chars except in raw mode */
X
Xif((tp->tty_mode & IN_CANON) == 0) { /* bit set means not CANON */
X  /* Processing for COOKED and CBREAK mode contains special checks. */
X  if (mode == COOKED || mode == CBREAK) {
X	/* Handle erase, kill and escape processing. */
X	if (mode == COOKED) {
X		/* First erase processing (rub out of last character). */
X		if (ch == tp->tty_erase && tp->tty_escaped == NOT_ESCAPED) {
X			if (chuck(tp) != -1) {	/* remove last char entered */
X				echo(tp, '\b');	/* remove it from the screen */
X				echo(tp, ' ');
X				echo(tp, '\b');
X			}
X			return(1);
X		}
X
X		/* Now do kill processing (remove current line). */
X		if (ch == tp->tty_kill && tp->tty_escaped == NOT_ESCAPED) {
X			while ( chuck(tp) == OK) /* keep looping */ ;
X			echo(tp, tp->tty_kill);
X			echo (tp, '\n');
X			return(1);
X		}
X
X		/* Handle EOT and the escape symbol (backslash). */
X		if (tp->tty_escaped == NOT_ESCAPED) {
X			/* Normal case: previous char was not backslash. */
X			if (ch == '\\') {
X				/* An escaped symbol has just been typed. */
X				tp->tty_escaped = ESCAPED;
X				echo(tp, ch);
X				return(1);	/* do not store the '\' */
X			}
X			/* CTRL-D means end-of-file, unless it is escaped. It
X			 * is stored in the text as MARKER, and counts as a
X			 * line feed in terms of knowing whether a full line
X			 * has been typed already.
X			 */
X			if (ch == tp->tty_eof) ch = MARKER;
X		} else {
X			/* Previous character was backslash. */
X			tp->tty_escaped = NOT_ESCAPED;	/* turn escaping off */
X			if (ch != tp->tty_erase && ch != tp->tty_kill &&
X						   ch != tp->tty_eof) {
X				/* Store the escape previously skipped over */
X				*tp->tty_inhead++ = '\\';
X				tp->tty_incount++;
X				if (tp->tty_inhead ==
X						&tp->tty_inqueue[TTY_IN_BYTES])
X					tp->tty_inhead = tp->tty_inqueue;
X			}
X		}
X	}
X	/* Both COOKED and CBREAK modes come here; first map CR to LF. */
X	if (ch == '\r' && (tp->tty_mode & CRMOD)) ch = '\n';
X
X	/* Check for interrupt and quit characters. */
X	if (ch == tp->tty_intr) {
X		sigchar(tp, SIGINT);
X		return(1);
X	}
X	if (ch == tp->tty_quit) {
X		sigchar(tp, SIGQUIT);
X		return(1);
X	}
X
X	/* Check for and process CTRL-S (terminal stop). */
X	if (ch == tp->tty_xoff) {
X		tp->tty_inhibited |= STOPPED;
X		return(1);
X	}
X
X	/* Check for stopped output (any key including CTRL-Q) */
X	if (tp->tty_inhibited & STOPPED) {
X		tp->tty_inhibited &= ~STOPPED;
X		if ((*tp->tty_start)(tp))	/* resume output */
X			finish(tp, tp->tty_cum);
X		return(1);
X	}
X  }
X
X  /* All 3 modes come here. */
X  if (ch == '\n' || ch == MARKER) tp->tty_lfct++;	/* count line feeds */
X } else {
X/* AT LEAST WE CAN USE THE RETURN KEY */
X  if (ch == '\n' || ch == '\r') tp->tty_lfct++;
X }
X  *tp->tty_inhead++ = ch;	/* save the character in the input queue */
X  if (tp->tty_inhead == &tp->tty_inqueue[TTY_IN_BYTES])
X	tp->tty_inhead = tp->tty_inqueue;	/* handle wraparound */
X  tp->tty_incount++;
X  echo(tp, ch);
X  return(1);
X}
X
X
X/*===========================================================================*
X *				echo					     *
X *===========================================================================*/
XPRIVATE echo(tp, c)
Xregister struct tty_struct *tp;	/* terminal on which to echo */
Xregister char c;		/* character to echo */
X{
X/* Echo a character on the terminal. */
X
X  if ( (tp->tty_mode & ECHO) == 0) return;	/* if no echoing, don't echo */
X  if ((c != MARKER) || (tp->tty_mode & RAW))
X	  (*tp->tty_echo)(tp, c);
X}
X
X
X/*===========================================================================*
X *				chuck					     *
X *===========================================================================*/
XPRIVATE int chuck(tp)
Xregister struct tty_struct *tp;	/* from which tty should chars be removed */
X{
X/* Delete one character from the input queue.  Used for erase and kill. */
X
X  char *prev;
X
X  /* If input queue is empty, don't delete anything. */
X  if (tp->tty_incount == 0) return(-1);
X
X  /* Don't delete '\n' or '\r'. */
X  prev = (tp->tty_inhead != tp->tty_inqueue ? tp->tty_inhead - 1 :
X					     &tp->tty_inqueue[TTY_IN_BYTES-1]);
X  if (*prev == '\n' || *prev == '\r') return(-1);
X  tp->tty_inhead = prev;
X  tp->tty_incount--;
X  return(OK);			/* char erasure was possible */
X}
X
X
X/*===========================================================================*
X *				do_read					     *
X *===========================================================================*/
XPRIVATE do_read(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xmessage *m_ptr;			/* pointer to message sent to the task */
X{
X/* A process wants to read from a terminal. */
X
X  int code, caller;
X
X  if (tp->tty_inleft > 0) {	/* if someone else is hanging, give up */
X	tty_reply(TASK_REPLY,m_ptr->m_source,m_ptr->PROC_NR, E_TRY_AGAIN,0L,0L);
X	return;
X  }
X
X  /* Copy information from the message to the tty struct. */
X  tp->tty_incaller = m_ptr->m_source;
X  tp->tty_inproc = m_ptr->PROC_NR;
X  tp->tty_in_vir = m_ptr->ADDRESS;
X  tp->tty_inleft = m_ptr->COUNT;
X
X  /* Try to get chars.  This call either gets enough, or gets nothing. */
X  code = rd_chars(tp,m_ptr);
X
Xif(code == SUSPEND && (tp->tty_inhibited & 2)) {
Xprintf("midi restarted sent <%x>\n\r",tp->tty_xon);
X	echo (tp->tty_xon);
X	tp->tty_inhibited &= ~2;
X}
X
X  caller = (int) tp->tty_inproc;
X  tty_reply(TASK_REPLY, m_ptr->m_source, caller, code, 0L, 0L);
X}
X
X
X/*===========================================================================*
X *				rd_chars				     *
X *===========================================================================*/
X
XPRIVATE int rd_chars(tp,m_ptr)
Xregister struct tty_struct *tp;	/* pointer to terminal to read from */
Xmessage *m_ptr;
X{
X/* A process wants to read from a terminal.  First check if enough data is
X * available. If so, pass it to the user.  If not, send FS a message telling
X * it to suspend the user.  When enough data arrives later, the tty driver
X * copies it to the user space directly and notifies FS with a message.
X */
X
X  int cooked, ct, user_ct, buf_ct, cum, enough, eot_seen;
X  vir_bytes in_vir, left;
X  phys_bytes user_phys, tty_phys;
X  char ch, *tty_ptr;
X  struct proc *rp;
X  extern phys_bytes umap();
X  static char tty_buf[256];	/* scratch buffer to/from user space */
X
X  message miditty_mess;
X
X/* for midi and midi, call a get routine to fill the tty queue */
X  cooked = ( (tp->tty_mode & (RAW | CBREAK)) ? 0 : 1);	/* 1 iff COOKED mode */
X  if (tp->tty_incount == 0 || (cooked && tp->tty_lfct == 0)) return(SUSPEND);
X  rp = proc_addr(tp->tty_inproc);
X  in_vir = (vir_bytes) tp-> tty_in_vir;
X  left = (vir_bytes) tp->tty_inleft;
X  if ( (user_phys = umap(rp, D, in_vir, left)) == 0) return(E_BAD_ADDR);
X  tty_phys = umap(proc_addr(TTY), D, (vir_bytes) tty_buf, (vir_bytes) sizeof(tty_buf));
X  cum = 0;
X  enough = 0;
X  eot_seen = 0;
X
X  /* The outer loop iterates on buffers, one buffer load per iteration. */
X  while (tp->tty_inleft > 0) {
X	buf_ct = MIN(tp->tty_inleft, tp->tty_incount);
X	buf_ct = MIN(buf_ct, sizeof(tty_buf));
X	ct = 0;
X	tty_ptr = tty_buf;
X
X	/* The inner loop fills one buffer. */
X	while(buf_ct-- > 0) {
X		ch = *tp->tty_intail++;
X		if (tp->tty_intail == &tp->tty_inqueue[TTY_IN_BYTES])
X			tp->tty_intail = tp->tty_inqueue;
X		*tty_ptr++ = ch;
X		ct++;
X		if (ch == '\n' || ch == MARKER) {
X			tp->tty_lfct--;
X			if (cooked && ch == MARKER) eot_seen++;
X			enough++;	/* exit loop */
X			if (cooked) break;	/* only provide 1 line */
X		}
X	}
X
X	/* Copy one buffer to user space.  Be careful about CTRL-D.  In cooked
X	 * mode it is not transmitted to user programs, and is not counted as
X	 * a character as far as the count goes, but it does occupy space in 
X	 * the driver's tables and must be counted there.
X	 */
X	user_ct = (eot_seen ? ct - 1 : ct);	/* bytes to copy to user */
X	phys_copy(tty_phys, user_phys, (phys_bytes) user_ct);
X	user_phys += user_ct;
X	cum += user_ct;
X	tp->tty_inleft -= ct;
X	tp->tty_incount -= ct;
X	if (tp->tty_incount == 0 || enough) break;
X  }
X  if(tp->tty_incount == 0 && tp->tty_inleft && !enough && Rs_blocked) {
X	ct = tty_reply(TTY_CHAR_INT, MIDI, m_ptr->PROC_NR, OK, 0L, 0L);
X	if(ct)
Xprintf("requeuing CHARINT, error = %d\n\r",ct);
X  }
X
X  tp->tty_inleft = 0;
X  return(cum);
X}
X
X
X/*===========================================================================*
X *				finish					     *
X *===========================================================================*/
XPRIVATE finish(tp, code)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xint code;			/* reply code */
X{
X/* A command has terminated (possibly due to DEL).  Tell caller. */
X
X  int replyee, caller;
X
X  tp->tty_outleft = 0;
X#ifdef ATARI_ST
X  (proc_addr(tp->tty_outproc))->p_physio = 0;	/* enable (un)shadowing */
X#endif
X  if (tp->tty_waiting == NOT_WAITING) return;
X  replyee = (int) tp->tty_otcaller;
X  caller = (int) tp->tty_outproc;
X  tty_reply(TASK_REPLY, replyee, caller, code, 0L, 0L);
X  tp->tty_waiting = NOT_WAITING;
X}
X
X
X/*===========================================================================*
X *				do_write				     *
X *===========================================================================*/
XPRIVATE do_write(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty struct */
Xmessage *m_ptr;			/* pointer to message sent to the task */
X{
X/* A process wants to write on a terminal. */
X
X  vir_bytes out_vir, out_left;
X  struct proc *rp;
X  extern phys_bytes umap();
X
X  /* Copy message parameters to the tty structure. */
X  tp->tty_otcaller = m_ptr->m_source;
X  tp->tty_outproc = m_ptr->PROC_NR;
X  tp->tty_out_vir = m_ptr->ADDRESS;
X  tp->tty_outleft = m_ptr->COUNT;
X  tp->tty_waiting = WAITING;
X  tp->tty_cum = 0;
X
X  /* Compute the physical address where the data is in user space. */
X  rp = proc_addr(tp->tty_outproc);
X  out_vir = (vir_bytes) tp->tty_out_vir;
X  out_left = (vir_bytes) tp->tty_outleft;
X  if ( (tp->tty_phys = umap(rp, D, out_vir, out_left)) == 0) {
X	/* Buffer address provided by user is outside its address space. */
X	tp->tty_cum = E_BAD_ADDR;
X	tp->tty_outleft = 0;
X  }
X#ifdef ATARI_ST
X  rp->p_physio = 1;	/* disable (un)shadowing */
X#endif
X
X  /* Copy characters from the user process to the terminal. */
X  if ((*tp->tty_start)(tp))	/* copy data to queue and start I/O */
X	finish(tp, tp->tty_cum);
X}
X
X
X/*===========================================================================*
X *				do_ioctl				     *
X *===========================================================================*/
XPRIVATE do_ioctl(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty_struct */
Xmessage *m_ptr;			/* pointer to message sent to task */
X{
X/* Perform IOCTL on this terminal. */
X
X  long flags, erki, erase, kill, intr, quit, xon, xoff, eof, baud;
X  int r;
X
X  r = OK;
X  flags = 0;
X  erki = 0;
X  switch(m_ptr->TTY_REQUEST) {
X     case TIOCSETP:
X	/* Set erase, kill, and flags. */
X	baud = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* ispeed  */
X	tp->tty_baud = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* ispeed  */
X	tp->tty_erase = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE);	/* erase  */
X	tp->tty_kill  = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE);	/* kill  */
X	tp->tty_mode  = (int) m_ptr->TTY_FLAGS;	/* mode word */
X	if(baud != tp->tty_baud)
X		r = (*tp->tty_ioctl)(tp, m_ptr);
X	break;
X
X     case TIOCSETC:
X	/* Set intr, quit, xon, xoff, eof (brk not used). */
X
X	tp->tty_intr = (char) ((m_ptr->TTY_SPEK >> 24) & BYTE);	/* interrupt */
X	tp->tty_quit = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* quit */
X	tp->tty_xon  = (char) ((m_ptr->TTY_SPEK >>  8) & BYTE);	/* CTRL-S */
X	tp->tty_xoff = (char) ((m_ptr->TTY_SPEK >>  0) & BYTE);	/* CTRL-Q */
X	tp->tty_eof  = (char) ((m_ptr->TTY_FLAGS >> 8) & BYTE);	/* CTRL-D */
X	break;
X
X     case TIOCGETP:
X	/* Get erase, kill, and flags. */
X	erase = ((long) tp->tty_erase) & BYTE;
X	kill  = ((long) tp->tty_kill) & BYTE;
X	baud  = ((long) tp->tty_baud) & BYTE;
X	erki  = (baud << 16) | (erase << 8) | kill;
X	flags = (long) tp->tty_mode;
X	break;
X
X     case TIOCGETC:
X	/* Get intr, quit, xon, xoff, eof. */
X	intr  = ((long) tp->tty_intr) & BYTE;
X	quit  = ((long) tp->tty_quit) & BYTE;
X	xon   = ((long) tp->tty_xon)  & BYTE;
X	xoff  = ((long) tp->tty_xoff) & BYTE;
X	eof   = ((long) tp->tty_eof)  & BYTE;
X	erki  = (intr << 24) | (quit << 16) | (xon << 8) | (xoff << 0);
X	flags = (eof <<8);
X	break;
X
X     case TIOCSTART:
X     case TIOCSTOP:
X	miditty_init();
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	break;
X     case TCSETAW: /* wait for output to drain */
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	/* Set erase, kill, and flags. */
X	tp->tty_baud = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* ispeed  */
X	tp->tty_erase = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE);	/* erase  */
X	tp->tty_kill  = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE);	/* kill  */
X	tp->tty_mode  = (int) m_ptr->TTY_FLAGS;	/* mode word */
X	break;
X     case TCSETAF: /* wait for output to drain, then flush input */
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	/* Set erase, kill, and flags. */
X	tp->tty_baud = (char) ((m_ptr->TTY_SPEK >> 16) & BYTE);	/* ispeed  */
X	tp->tty_erase = (char) ((m_ptr->TTY_SPEK >> 8) & BYTE);	/* erase  */
X	tp->tty_kill  = (char) ((m_ptr->TTY_SPEK >> 0) & BYTE);	/* kill  */
X	tp->tty_mode  = (int) m_ptr->TTY_FLAGS;	/* mode word */
X	break;
X     case TCSBRK:  /* drain output, send a break */
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	break;
X     case TCXONC:  /* start/stop output arg ==0 stop, ==1 start */	
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X     	break;
X     case TCFLSH:  /* flush: 0==input 1==output 2=both */
X	r = (*tp->tty_ioctl)(tp, m_ptr);
X	break;
X
X     default:
X	r = EINVAL;
X  }
X
X  /* Send the reply. */
X  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r, flags, erki);
X}
X
X
X/*===========================================================================*
X *				do_setpgrp				     *
X *===========================================================================*/
XPRIVATE do_setpgrp(tp, m_ptr)
Xregister struct tty_struct *tp; /* pointer to tty struct */
Xmessage *m_ptr;			/* pointer to message sent to task */
X{
X/* A control process group has changed */
X
X   if((tp->tty_pgrp = m_ptr->TTY_PGRP) )
X	(*tp->tty_open)(tp);	/* do a device open to force midi/midi startup */
X   tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK, 0L, 0L);
X}
X
X
X/*===========================================================================*
X *				do_cancel				     *
X *===========================================================================*/
XPRIVATE do_cancel(tp, m_ptr)
Xregister struct tty_struct *tp;	/* pointer to tty_struct */
Xmessage *m_ptr;			/* pointer to message sent to task */
X{
X/* A signal has been sent to a process that is hanging trying to read or write.
X * The pending read or write must be finished off immediately.
X */
X
X  /* First check to see if the process is indeed hanging.  If it is not, don't
X   * reply (to avoid race conditions).
X   */
X  if (tp->tty_inleft == 0 && tp->tty_outleft == 0) return;
X
X  /* Kill off input and output. */
X  tp->tty_inhead = tp->tty_inqueue;	/* discard all input */
X  tp->tty_intail = tp->tty_inqueue;
X  tp->tty_incount = 0;
X  tp->tty_lfct = 0;
X  tp->tty_inleft = 0;
X  tp->tty_outleft = 0;
X  tp->tty_waiting = NOT_WAITING;	/* don't send reply */
X  tp->tty_inhibited = RUNNING;
X  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINTR, 0L, 0L);
X}
X
X
X/*===========================================================================*
X *				tty_reply				     *
X *===========================================================================*/
XPRIVATE tty_reply(code, replyee, proc_nr, status, extra, other)
Xint code;			/* TASK_REPLY or REVIVE */
Xint replyee;			/* destination address for the reply */
Xint proc_nr;			/* to whom should the reply go? */
Xint status;			/* reply code */
Xlong extra;			/* extra value */
Xlong other;			/* used for IOCTL replies */
X{
X/* Send a reply to a process that wanted to read or write data. */
X
X  message miditty_mess;
X
X  miditty_mess.m_type = code;
X  miditty_mess.REP_PROC_NR = proc_nr;
X  miditty_mess.REP_STATUS = status;
X  miditty_mess.TTY_FLAGS = extra;	/* used by IOCTL for flags (mode) */
X  miditty_mess.TTY_SPEK = other;	/* used by IOCTL for erase and kill chars */
X  send(replyee, &miditty_mess);
X}
X
X/*===========================================================================*
X *				sigchar					     *
X *===========================================================================*/
XPRIVATE sigchar(tp, sig)
Xregister struct tty_struct *tp;	/* pointer to tty_struct */
Xint sig;			/* SIGINT, SIGQUIT, or SIGKILL */
X{
X/* Process a SIGINT, SIGQUIT or SIGKILL char from the keyboard */
X
X  tp->tty_inhibited = RUNNING;	/* do implied CRTL-Q */
X  finish(tp, EINTR);		/* send reply */
X  tp->tty_inhead = tp->tty_inqueue;	/* discard input */
X  tp->tty_intail = tp->tty_inqueue;
X  tp->tty_incount = 0;
X  tp->tty_lfct = 0;
X  if (tp->tty_pgrp)
X	cause_sig(tp->tty_pgrp, sig);
X}
X
X
X/*===========================================================================*
X *				miditty_init				     *
X *===========================================================================*/
XPRIVATE miditty_init()
X{
X/* Initialize the tty tables. */
X
X  register struct tty_struct *tp;
X  int i;
X
X  for (i = 0; i < NR_MIDI; i++) {
X	tp = &miditty_struct[i];
X  tp->tty_inhead = tp->tty_inqueue;	/* discard all input */
X  tp->tty_intail = tp->tty_inqueue;
X  tp->tty_incount = 0;
X  tp->tty_lfct = 0;
X  tp->tty_inleft = 0;
X  tp->tty_outleft = 0;
X  tp->tty_waiting = NOT_WAITING;	/* don't send reply */
X  tp->tty_inhibited = RUNNING;
X	tp->tty_mode = RAW;
X
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	Midi_wempty = 0;
X	midiinit(tp);
X  }
X}
X
Xmiditty_dmp()
X{
X	struct tty_struct *tp;
X
X	tp = &miditty_struct[0];
X
Xprintf("\rTTY for MIDI: cnt_max=%d\n\
X\r\tinhead=%lx intail=%lx inqueue=%lx mode=%x\n\
X\r\terase=%x kill=%x intr=%x quit=%x xon=%x xoff=%x eof=%x\n\
X\r\tincount=%d lfct=%d escaped=%x inhibited=%x waiting=%x\n\
X\r\tincaller=%d inproc=%d in_vir=%lx inleft=%d otcaller=%d outproc=%d\n\
X\r\t out_vir=%lx phys=%lx outleft=%d cum=%d pgrp=%d baud=%x\n\r",
Xcnt_max,
X	tp->tty_inhead ,
X	tp->tty_intail , tp->tty_inqueue,
X	tp->tty_mode ,
X
X	tp->tty_erase ,
X	tp->tty_kill  ,
X	tp->tty_intr  ,
X	tp->tty_quit  ,
X	tp->tty_xon   ,
X	tp->tty_xoff  ,
X	tp->tty_eof   ,
X	tp->tty_incount, tp->tty_lfct, tp->tty_escaped, tp->tty_inhibited,
X	tp->tty_waiting,
X  	tp->tty_incaller,		/* process that made the call (usually FS) */
X  	tp->tty_inproc,		/* process that wants to read from tty */
X  	tp->tty_in_vir,		/* virtual address where data is to go */
X  	tp->tty_inleft,		/* how many chars are still needed */
X  	tp->tty_otcaller,		/* process that made the call (usually FS) */
X  	tp->tty_outproc,		/* process that wants to write to tty */
X  	tp->tty_out_vir,		/* virtual address where data comes from */
X  	tp->tty_phys,		/* physical address where data comes from */
X  	tp->tty_outleft,		/* # chars yet to be copied to tty_outqueue */
X  	tp->tty_cum,			/* # chars copied to tty_outqueue so far */
X  	tp->tty_pgrp,			/* Slot number of controlling process */
X  	tp->tty_baud		/* index of baud (midi) */
X	);
X}
SHAR_EOF