#ifndef _BASE_H_
#define _BASE_H_
/*
 * $Id: base.h,v 3.3 1994/05/19 04:29:29 ppessi Exp $
 *
 * Netinfo device base. Define the device structure 
 *
 * Copyright (c) 1993 Pekka Pessi
 *
 * Created      : Sun Nov 28 17:45:55 1993 ppessi
 * Last modified: Thu May 19 04:09:29 1994 ppessi
 *
 * $Log: base.h,v $
 * Revision 3.3  1994/05/19  04:29:29  ppessi
 * Added support for DOS notifications
 *
 * Revision 3.2  1994/02/27  00:07:45  ppessi
 * Removed from DeviceCmd_t typedef a "const" keyword.
 * It resulted in bad optimization with SAS C 6.51.
 *
 * Revision 3.1  1994/01/23  02:46:18  ppessi
 * New command semantics, new version.
 *
 * Revision 1.3  1994/01/23  02:34:32  ppessi
 * Created new unit hieararchy, dropped the magic cookie passing
 * system for setnet/getent/endent -style access.
 *
 * Revision 1.2  1994/01/20  16:16:17  ppessi
 * Added CMD_WRITE and CMD_UPDATE
 *
 * Revision 1.1  1994/01/18  09:12:48  ppessi
 * Initial revision
 *
 * Revision 1.1  93/11/30  03:18:50  ppessi
 * Initial revision
 * 
 */

#include "config.h"

#ifndef EXEC_LIBRARIES_H
#include <exec/libraries.h>
#endif

#ifndef DEVICES_NETINFO_H
#include <devices/netinfo.h>
#endif

#ifndef EXEC_TASKS_H
#include <exec/tasks.h>
#endif

#ifndef UTILITY_TAGITEM_H
#include <utility/tagitem.h>
#endif

#ifndef EXEC_IO_H
#include <exec/io.h>
#endif

#ifndef EXEC_DEVICES_H
#include <exec/devices.h>
#endif

#ifndef EXEC_ERRORS_H
#include <exec/errors.h>
#endif

#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif

#ifndef EXEC_SEMAPHORES_H
#include <exec/semaphores.h>
#endif

#ifdef USE_PRAGMAS
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>

#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>

#define SysBase (nid->nid_ExecBase)
#define DOSBase (nid->nid_DOSBase)
#endif

extern const UBYTE _DevName[]; 

/*
 * Device base 
 */
struct NetInfoDevice {
  struct Library         nid_Lib;
  APTR		         nid_SegList;
  /* like there were no reference operator in C... */
  struct SignalSemaphore nid_Lock[1];
  APTR                   nid_ExecBase;
  APTR                   nid_DOSBase;
  struct MsgPort         nid_Port[1];	/* Port to send requests */
  struct Message        *nid_Death;	/* Kill task by this message */
  struct MsgPort         nid_NotifyPort[1]; /* Port for notify messages */
  struct List            nid_Instances[1];
  struct NetInfoMap     *nid_Maps[NETINFO_UNITS];
};

#define nid_Task nid_Port->mp_SigTask
#define nid_SigBit nid_Port->mp_SigBit

/* Internal constants */
#define NETINFOSIZE ((sizeof(struct NetInfoDevice) +3) & ~3)
#define NID_PRIORITY 1

typedef void (* DeviceCmd_t)(BASE, struct NetInfoReq *, struct NetInfoMap *);

/*
 * Structure for each netinfo map
 */
struct NetInfoMap {
  struct Node            nim_Node[1];
  struct MsgPort        *nim_Port;
  const struct MapMethods *nim_Methods;
  const DeviceCmd_t     *nim_Commands;
  struct SignalSemaphore nim_PointerLock[1];
  struct List            nim_Pointer[1];     /* under nid_Lock */
  struct SignalSemaphore nim_ReqLock[1];
  struct List            nim_Rx[1];
  struct List            nim_Wx[1];
  WORD                   nim_OpenCnt;
  WORD                   nim_Flags;	     
  const UBYTE           *nim_Filename;
  struct SignalSemaphore nim_EntLock[1];
  struct List            nim_Ent[1];
  struct NotifyRequest   nim_Notify[1];
};

#define NIMF_PARSED   0x0001
#define NIMF_CHANGED  0x0002

#define nim_Name nim_Node->ln_Name

/*
 * Define map methods
 */
struct MapMethods {
  struct Ent *        (*parse_ent)(BASE, register UBYTE *p);
  int                 (*print_out)(BASE, BPTR, struct Ent *); 
  void *              (*copy_out)(struct NetInfoReq *req, struct Ent *e);
  struct Ent *        (*copy_in)(BASE, struct NetInfoReq *req);
  void                (*cleanup)(BASE, struct NetInfoMap *);
  void                (*membercmd)(BASE, struct NetInfoReq *, 
				   struct NetInfoMap *);
  void                (*notify)(BASE, struct NetInfoMap *);
};

#define DoMethod(cmd, req, unit)\
  ((unit)->nim_Commands[cmd])(nid, (req), (unit))
#define Method(method, unit)\
  (*((unit)->nim_Methods->method))

/*
 * Instance allocated for each opener (stored to io_Unit)
 */
struct NetInfoPointer {
  struct Node        nip_Node[1];
  UBYTE              nip_Flags;
  UBYTE              nip_UnitNumber;
  struct NetInfoMap *nip_Map;		     /* backpointer */
  struct Ent        *nip_Ent;		     /* latest entry read */
};

#define nip_Name nip_Node->ln_Name

/* Device initialization functions */
ASM ULONG _LibInit(REG(a0) APTR seglist, REG(d0) struct Library *devbase);
ASM ULONG _DevInit(BASEREG, REG(a0) APTR seglist);

/* Library entry points */
ASM LONG _DevOpen(BASEREG, REG(a1) struct IORequest *req, REG(d0) ULONG unit,
		  REG(d1) ULONG flags);
ASM ULONG _DevClose(BASEREG, REG(a1) struct IORequest *req);
ASM ULONG _DevExpunge(BASEREG);
ASM ULONG _DevRes(void);
ASM VOID _NetInfoBeginIO(BASEREG, REG(a1) struct NetInfoReq *req);
ASM ULONG _NetInfoAbortIO(BASEREG, REG(a1) struct NetInfoReq *req);

/* in server.c */
ASM LONG NetInfoStartup(void);
void NetInfoTask(BASE, struct Message *msg);
struct NetInfoMap *InitNetInfoMap(BASE, struct MsgPort *, ULONG);
void DeInitNetInfoMap(BASE, struct NetInfoMap *);
struct Unit *CreateNewUnit(BASE, short unit);
void ExpungeUnit(BASE, struct Unit *);
void PerformIO(BASE, struct NetInfoReq *req);
void TermIO(struct NetInfoReq *req);
ULONG AbortReq(BASE, struct List *, struct NetInfoReq *);

/* Common method */
void UnknownCommand(BASE, struct NetInfoReq *, struct NetInfoMap *);   

/* support functions */
struct NetInfoMap *CheckUnit(BASE, struct Unit *u);
void FreeListVec(BASE, struct List *list);
struct Node *FindNode(struct List *list, struct Node *node);
char *strsep(register char **stringp, register const char *delim);

static __inline void InitList(struct List *list)
{
  list->lh_Head = (struct Node*)&list->lh_Tail;
  list->lh_Tail = NULL;
  list->lh_TailPred = (struct Node*)&list->lh_Head;
}

void InMsg(const char *fmt, ...);

#endif /* _BASE_H_ */
