#include "defs.h"

long start(void) { return(-1); } /* in case somebody tries to run us */

struct ExecBase *SysBase = NULL;

char ID[] = "$VER: autodialer "__VERSION__" ("__COMMODORE_DATE__") © 1993 Iain Hibbert";
char DeviceName[] = "dialer.device";

/*
 *  the RomTag structure (const puts it in the code segment)
 */
const struct Resident RomTag = {
    RTC_MATCHWORD,
    &RomTag,
    &RomTag+1,              /* EndCode */
    0,                      /* no flags */
    VERSION,
    NT_DEVICE,
    0,                      /* zero priority */
    DeviceName,
    ID,
    DevInit
};


/*
 *  initialise device (in a Forbid)
 *
 *  NOTE! this is the first piece of code called, and as we have NO startup
 *        code anywhere, we have to set up SysBase etc ourselves.. there is
 *        NO auto-initialisation code anywhere, NO memory allocation, NO
 *        clearing of BSS space.. we are totally on our own..
 *
 *  segment pointer in a0
 */
struct DevBase *
DevInit(__a0 APTR seg)
{
struct DevBase *db;
static APTR func_table[] = {
    DevOpen,
    DevClose,
    DevExpunge,
    DevReserved,
    DevBeginIO,
    DevAbortIO,
    -1
};

    SysBase = *(struct ExecBase **)4;

    db = (struct DevBase *)MakeLibrary(func_table, NULL, NULL, sizeof(struct DevBase), NULL);

    if( db ) {

        /*
         *  set up the device structure
         */
        db->b_Lib.lib_Node.ln_Type = NT_DEVICE;
        db->b_Lib.lib_Node.ln_Name = DeviceName;
        db->b_Lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
        db->b_Lib.lib_Version = VERSION;
        db->b_Lib.lib_Revision = REVISION;
        db->b_Lib.lib_IdString = ID;

        db->b_Segment = seg;

        NewList(&db->b_UList);

        /*
         *  online at last!
         */
        AddDevice((struct Device *)db);
    }

    return(db);
}


/*
 *  open device (in a Forbid)
 *
 *      unitnum:    d0
 *      flags:      d1
 *      iob:        a1
 *      device:     a6
 *
 */
struct DevBase *
DevOpen( __d0 ULONG unitnum,
         __d1 ULONG flags,
         __a1 struct IOExtSer *iob,
         __a6 struct DevBase *db)
{
struct DevUnit *unit;

    db->b_Lib.lib_OpenCnt++;    /* fake opener so we don't get expunged */

    /*
     *  set fail conditions as default..
     */
    iob->IOSer.io_Error = IOERR_OPENFAIL;
    iob->IOSer.io_Device = (struct Device *)-1;     /* trashed */

    if( unit = get_unit(unitnum, db) ) {

        unit->du_iob = iob;

        OpenDevice(unit->du_SerName, unit->du_SerUnit, (struct IORequest *)iob, flags);

        if( iob->IOSer.io_Error == 0 && !autodial(unit) ) {
            CloseDevice((struct IORequest *)iob);

            iob->IOSer.io_Error = IOERR_OPENFAIL;
            iob->IOSer.io_Device = (struct Device *)-1; /* just in case! */
        }

        free_unit(unit);
    }

    db->b_Lib.lib_OpenCnt--;    /* end of fake opener */

    return(iob->IOSer.io_Error);
}


/*
 *  close device (in a Forbid)
 *
 *      iob:    a1
 *      device: a6
 *
 *  This should never get called, since WE don't actually open..
 */
APTR
DevClose(__a1 struct IOExtSer *iob,
         __a6 struct DevBase *db)
{
    return(NULL);
}


/*
 *  device Expunge (in a Forbid)
 *
 *      device: a6
 *
 *  returns segment passed to Init if we want to expunge, NULL otherwise
 *
 */
APTR
DevExpunge(__a6 struct DevBase *db)
{
APTR dseg = db->b_Segment;

    /*
     *  but not yet if we are still open!
     */
    if( db->b_Lib.lib_OpenCnt ) {
        return(NULL);
    }

    /*
     *  bye bye
     */
    Remove( &db->b_Lib.lib_Node );
    FreeMem((UBYTE *)db - db->b_Lib.lib_NegSize, db->b_Lib.lib_NegSize + db->b_Lib.lib_PosSize);
    return(dseg);
}


/*
 *  Device Reserved Call (reserved for future use by C=)
 *
 *      no arguments
 *
 */
ULONG
DevReserved(void)
{
    return(NULL);
}


/*
 *  device BeginIO
 *
 *      iob:    a1
 *      device: a6
 *
 *  Hopefully never gets called..
 */
void
DevBeginIO(__a1 struct IOExtSer *iob,
           __a6 struct DevBase *db)
{
}


/*
 *  device AbortIO
 *
 *      iob:    a1
 *      device: a6
 *
 *  Hopefully never gets called..
 */
ULONG
DevAbortIO(__a1 struct IOExtSer *iob,
           __a6 struct DevBase *db)
{
    return(NULL);
}
