/* Copyright 1984 by the Massachusetts Institute of Technology */

#include	<types.h>
#include	"../include/sys.h"
#include	"../include/sysext.h"
#include	"../include/params.h"

#define	NULL	0

ext dct *DCTVT[];
iorb *sys_iobufs;

/* io_init - initialize all the I/O devices of the system. */
io_init()
{
    reg dct	*devp;
    reg int	i;
    reg iorb *iob;

/*    printf("IO_INIT:\n"); */
#ifdef SYS_IOBUFS
    sys_iobufs = NULL;
    for (i = 0; i < NUM_IOBUFS; i++) {
	iob = (iorb *)mem_alloc(sizeof(iorb) + IO_BUFSIZE);
	iob->i_link = sys_iobufs;
	sys_iobufs = iob;
    }
#endif
    
    for (devp = DCTVT[i = 0]; devp != NULL ; devp = DCTVT[++i])
      devp->d_flg = 0;
    
    for (devp = DCTVT[i = 0]; devp != NULL ; devp = DCTVT[++i]) {
/*	printf("io_init: devp = %x\n", devp); */
	devp->d_qhd = NULL;
	devp->d_qtl = NULL;
	if (!(devp->d_flg & D_INI)) {
	    if (devp->d_iva != NO_IVEC)
	      set_int(devp->d_iva, devp);
	    if (devp->d_ina != NULL)
	      (*devp->d_ina)(devp);
	}
    }
/*  printf("\tIO_INIT: done\n"); */
}

/* sio - Start an i/o operation. */
sio(iob)
reg	iorb	*iob;
{
    reg	dct *devp;
    int	imask;
	
    iob->i_stat = 0;
    iob->i_bxfr = 0;
    iob->i_link = NULL;
    devp = iob->i_devp;
    imask = disable();
    if (devp->d_qhd == NULL) {
	devp->d_qhd = iob;
	devp->d_qtl = iob;
	devp->d_addr = iob->i_addr;
	devp->d_breq = iob->i_breq;
	(*(int (*)())devp->d_strt)(devp);
    }
    else {
	devp->d_qtl->i_link = iob;
	devp->d_qtl = iob;
    }
    enable(imask);
}

/* Do I/O completion.  Queues the I/O completion routine as a task and
 * starts next I/O if one is waiting.
 */
iocmr(devp)
reg	dct	*devp;
{
    reg	iorb	*iob1, *iob2;
    ext	iorb	*bfrlst;
	
    iob1 = devp->d_qhd;
    if ((devp->d_qhd = iob1->i_link) == NULL)
      devp->d_qtl = NULL;
    else {
	iob2 = devp->d_qhd;
	devp->d_addr = iob2->i_addr;
	devp->d_breq = iob2->i_breq;
	(*(int (*)())devp->d_strt)(devp);
	iob1->i_link = NULL;
    }

    addtsk(syshnd, CMPPRI, iob1->i_cmp, iob1);
}

/* Buffer and queue output to a device.  Returns number of bytes written. */
write(devp, data, len)
dct *devp;
byte *data;
int len;
{
    reg iorb *iob;
    int bxfr = 0;
    void write_done();

    while (len) {
#ifdef SYS_IOBUFS
	if ((iob = sys_iobufs) == NULL)
	  return 0;
	sys_iobufs = iob->i_link;
#else
	if ((iob = (iorb *)alloc(sizeof(iorb) + IO_BUFSIZE)) == NULL)
	  return 0;
#endif
	iob->i_addr = (byte *)(iob + 1);
	iob->i_devp = devp;
	iob->i_cmp = write_done;
	iob->i_breq = len > IO_BUFSIZE ? IO_BUFSIZE : len;
	copy(data, iob->i_addr, iob->i_breq);
	data += iob->i_breq;
	len -= iob->i_breq;
	bxfr += iob->i_breq;
	sio(iob);
    }
    return bxfr;
}

/* I/O completion for write().  Just puts iorb back on sys_iobufs list. */
write_done(iob)
iorb *iob;
{
#ifdef SYS_IOBUFS
    iob->i_link = sys_iobufs;
    sys_iobufs = iob;
#else
    free(iob);
#endif
}
