#include "defs.h"
#include "protos.h"

struct IOExtSer *
cmd_invalid(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    iob->IOSer.io_Error = IOERR_NOCMD;
    dprintf(unit, 1,"*** cmd_invalid\n");
    return(iob);
}

struct IOExtSer *
cmd_reset(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    dprintf(unit, 1,"*** cmd_reset\n");
    return(iob);
}

struct IOExtSer *
cmd_read(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;
unsigned int count;
char *r, *w = iob->IOSer.io_Data;

    ObtainSemaphore(&unit->u_Modem->nm_Semaphore);

    r = unit->u_Readptr;

    if( unit->u_Bufcount < iob->IOSer.io_Length ) {
        count = iob->IOSer.io_Actual = unit->u_Bufcount;
        AddTail( (struct List *)&unit->u_Readlist, &iob->IOSer.io_Message.mn_Node );
        iob->IOSer.io_Flags &= ~IOF_QUICK;
        dprintf(unit, 1, "cmd_read %ld (queued)\n", iob->IOSer.io_Length);
        iob = NULL;
    }
    else {
        count = iob->IOSer.io_Actual = iob->IOSer.io_Length;
        dprintf(unit, 1, "cmd_read %ld (complete)\n", iob->IOSer.io_Length);
    }

    unit->u_Bufcount -= count;

    /*
     *  copy chars from the buffer to the read request, quickly
     */
    while( count-- ) {
        *w++ = *r--;
        if( r < unit->u_Buffer ) r += UNIT_BUF_SIZE;
    }

    unit->u_Readptr = r;

    /* and let the task know we took something */
    Signal(unit->u_Modem->nm_Taskptr, SIGBREAKF_CTRL_C);

    ReleaseSemaphore(&unit->u_Modem->nm_Semaphore);

    return(iob);
}

struct IOExtSer *
cmd_write(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    /*
     *  handle the case of a null-terminated string write
     */
    if( iob->IOSer.io_Length == -1 ) {
    char *p = iob->IOSer.io_Data;

        while( *p ) p++;
        iob->IOSer.io_Length = p - iob->IOSer.io_Data;
    }

    ObtainSemaphore(&unit->u_Modem->nm_Semaphore);

    dprintf(unit, 1, "cmd_write %ld (queued)\n" ,iob->IOSer.io_Length);

    /*
     *  we let the Task handle where it goes, just queue it
     *  and tell her we sent something
     */
    AddTail( (struct List *)&unit->u_Writelist, &iob->IOSer.io_Message.mn_Node );
    iob->IOSer.io_Flags &= ~IOF_QUICK;
    Signal(unit->u_Modem->nm_Taskptr, SIGBREAKF_CTRL_C);

    ReleaseSemaphore(&unit->u_Modem->nm_Semaphore);

    return(NULL);   /* its always queued */
}

struct IOExtSer *
cmd_update(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    iob->IOSer.io_Error = IOERR_NOCMD;
    dprintf(unit, 1, "cmd_update\n");
    return(iob);
}

struct IOExtSer *
cmd_clear(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    ObtainSemaphore(&unit->u_Modem->nm_Semaphore);

    dprintf(unit, 1, "cmd_clear (was %ld)\n",unit->u_Bufcount);

    unit->u_Bufcount = 0;
    unit->u_Readptr = unit->u_Writeptr = unit->u_Buffer;

    ReleaseSemaphore(&unit->u_Modem->nm_Semaphore);

    return(iob);
}

struct IOExtSer *
cmd_stop(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    dprintf(unit, 1, "cmd_stop (not implemented)\n");
    return(iob);
}

struct IOExtSer *
cmd_start(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    dprintf(unit, 1, "cmd_start (not implemented)\n");
    return(iob);
}

struct IOExtSer *
cmd_flush(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;
struct IOExtSer *io,*temp;

    dprintf(unit, 1, "cmd_flush\n");

    ObtainSemaphore(&unit->u_Modem->nm_Semaphore);

    io = unit->u_Readlist.mlh_Head;
    while( temp = io->IOSer.io_Message.mn_Node.ln_Succ ) {
        dprintf(unit, 2, "cmd_flush flushed read (read %ld of %ld)\n",io->IOSer.io_Actual,io->IOSer.io_Length);
        Remove(&io->IOSer.io_Message.mn_Node);
        ReplyMsg(&io->IOSer.io_Message);
        io = temp;
    }

    io = unit->u_Writelist.mlh_Head;
    while( temp = io->IOSer.io_Message.mn_Node.ln_Succ ) {
        dprintf(unit, 2, "cmd_flush flushed write (written %ld of %ld)\n",io->IOSer.io_Actual,io->IOSer.io_Length);
        Remove(&io->IOSer.io_Message.mn_Node);
        ReplyMsg(&io->IOSer.io_Message);
        io = temp;
    }

    ReleaseSemaphore(&unit->u_Modem->nm_Semaphore);

    return(iob);
}

struct IOExtSer *
sdcmd_query(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    ObtainSemaphore(&unit->u_Modem->nm_Semaphore);

    iob->IOSer.io_Actual = unit->u_Bufcount;
    iob->io_Status = (unit->u_SReg[SREG_STATE] == STATE_CONNECTED ? 0 : (1<<5));

    dprintf(unit, 1, "sdcmd_query = %ld\n",iob->IOSer.io_Actual);

    ReleaseSemaphore(&unit->u_Modem->nm_Semaphore);

    return(iob);
}

struct IOExtSer *
sdcmd_break(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    dprintf(unit, 1, "sdcmd_break (not implemented)\n");
    return(iob);
}

struct IOExtSer *
sdcmd_setparams(struct IOExtSer *iob)
{
struct NullUnit *unit = (struct NullUnit *)iob->IOSer.io_Unit;

    dprintf(unit, 1, "sdcmd_setparams (does nothing)\n");
    return(iob);
}

#define ASDG_RTS (1<<0)
#define ASDG_DTR (1<<1)

struct IOExtSer *
asdg_dtrcontrol(struct IOExtSer *iob)
{
struct NullUnit *unit = iob->IOSer.io_Unit;

    dprintf(unit, 1, "asdg_dtrcontrol\n");

    if( ASDG_DTR & iob->IOSer.io_Offset )
        if( ASDG_DTR & iob->IOSer.io_Length ) {
            /* raise DTR */
            dprintf(unit, 2,"asdg_dtrcontrol (raise DTR)\n");
        }
        else {
            /* lower DTR */
            dprintf(unit, 2,"asdg_dtrcontrol (lower DTR)\n");
            Signal(unit->u_Modem->nm_Taskptr, SIGBREAKF_CTRL_D);
        }

    if( ASDG_RTS & iob->IOSer.io_Offset )
        if( ASDG_RTS & iob->IOSer.io_Length ) {
            /* raise RTS */
            dprintf(unit, 2,"asdg_dtrcontrol (raise RTS)\n");
        }
        else {
            /* lower RTS */
            dprintf(unit, 2,"asdg_dtrcontrol (lower RTS)\n");
        }

    return(iob);
}
