
/*
 *  DNRead.C
 */

#include "lib.h"

long
DNRead(_chan, _buf, bytes)
void *_chan;
void *_buf;
long bytes;
{
    CHANN *chan = (CHANN *)_chan;
    char *buf = (char *)_buf;
    IOSTD *ior;
    int len = 0;
    long n;

    if (chan->eof)
	return(-1);
    while (bytes > 0 ){
        if((ior = (IOSTD *)RemHead(&chan->rdylist)) != NULL) {
	    IFDEBUG(printf("ior from chan->rdylist\n");)
	} else if ((ior = (IOSTD *)GetMsg(&chan->port)) != NULL) {
	    IFDEBUG(printf("ior from chan->port\n");)
	} else {
	    break;
	}
	IFDEBUG(printf("IOR %08lx cmd %d len %d act %d\n", ior, ior->io_Command, ior->io_Length, ior->io_Actual);)
	if (ior->io_Message.mn_Node.ln_Type == NT_REPLYMSG) {
	    if (chan->queued <=0)
		IFDEBUG(puts("DNRead: Software Error"));
	    else
		--chan->queued;
	    IFDEBUG(printf("Freeing reply message");)
	    if (ior->io_Length)
		FreeMem(ior->io_Data, ior->io_Length);
	    FreeMem(ior, sizeof(IOSTD));
	    continue;
	}
	switch(ior->io_Command) {
	case DNCMD_CLOSE:
	case DNCMD_EOF:
	    chan->eof = 1;
	    ReplyMsg((MSG *)ior);
	    break;
	case DNCMD_IOCTL:
	    if (ior->io_Message.mn_Node.ln_Type == NT_REQUEUE)
		AddHead(&chan->rdylist, (NODE *)ior);
	    else
		AddTail(&chan->rdylist, (NODE *)ior);
	    ior->io_Message.mn_Node.ln_Type = NT_REQUEUE;
	    if (len == 0)
		len = -2;
	    goto done;
	case DNCMD_WRITE:
	    IFDEBUG(printf("WRITE LEN/ACT %ld/%ld\n", ior->io_Length, ior->io_Actual);)
	    n = ior->io_Length - ior->io_Actual;
	    IFDEBUG(if (n < 0) puts("len error, act > len");)
	    if (n <= bytes) {
		/* the ior is being written to this channel
		** it is long enough to be completed by this request */
		BMov((char *)ior->io_Data + ior->io_Actual, buf, n);
		bytes -= n;
		len += n;
		buf += n;
		ReplyMsg((MSG *)ior);
	    } else {
		/* the ior is being written to this channel
		** it is NOT long enough to be completed by this request 
		**  Thus, it needs to be  requeued */
		BMov((char *)ior->io_Data + ior->io_Actual, buf, bytes);
		len += bytes;
		ior->io_Actual += bytes;
		bytes = 0;
		if (ior->io_Message.mn_Node.ln_Type == NT_REQUEUE)
		    AddHead(&chan->rdylist, (NODE *)ior);
		else
		    AddTail(&chan->rdylist, (NODE *)ior);
		ior->io_Message.mn_Node.ln_Type = NT_REQUEUE;
	    }
	    break;
	default:
	    ior->io_Error = 1;
	    IFDEBUG(puts("DNRead():default erroneous ior");)
	    ReplyMsg((MSG *)ior);
	}
    }
    IFDEBUG(puts("DONE1");)
done:
    FixSignal(chan);
    if (chan->eof)
	SetSignal(1 << chan->port.mp_SigBit, 1 << chan->port.mp_SigBit);
    IFDEBUG(printf("RETURN %ld\n", len);)
    return(len);
}
