/*
** $VER: device.c 1.0 (20 Dec 1995)
**
** memory.device - direct memory access
**
** (C) Copyright 1995 Marius Gröger
**     All Rights Reserved
**
** Inspired by z2ram device in Linux/68k/Amiga
**
** 20 Dec 1995 : 001.000 :  created
*/

#define DEBUG 0

/*F*/ /* includes */
#ifndef CLIB_ALIB_PROTOS_H
#include <clib/alib_protos.h>
#endif
#ifndef CLIB_EXEC_PROTOS_H
#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>
#endif

#ifndef EXEC_MEMORY_H
#include <exec/memory.h>
#endif
#ifndef EXEC_IO_H
#include <exec/io.h>
#endif
#ifndef EXEC_ERRORS_H
#include <exec/errors.h>
#endif
#ifndef DEVICES_TRACKDISK_H
#include <devices/trackdisk.h>
#endif

#ifndef _STRING_H
#include <string.h>
#endif

#ifndef __MEMORY_H
#include "memory.h"
#endif
#ifndef __DEBUG_H
#include "debug.h"
#endif
#ifndef __COMPILER_H
#include "compiler.h"
#endif
/*E*/

/*F*/ /* imports */
/*E*/
/*F*/ /* exports */
PUBLIC ASM SAVEDS struct Device *DevInit(REG(d0) BASEPTR, REG(a0) ULONG seglist, REG(a6) struct Library *_SysBase);
PUBLIC ASM SAVEDS LONG DevOpen(REG(a1) struct IOExtTD *iotd, REG(d0) ULONG unit, REG(d1) ULONG flags, REG(a6) BASEPTR);
PUBLIC ASM SAVEDS BPTR DevExpunge(REG(a6) BASEPTR);
PUBLIC ASM SAVEDS BPTR DevClose( REG(a1) struct IOExtTD *ior, REG(a6) BASEPTR);
PUBLIC VOID DevTermIO(BASEPTR, struct IOExtTD *iotd);
PUBLIC ASM SAVEDS VOID DevBeginIO(REG(a1) struct IOExtTD *iotd, REG(a6) BASEPTR);
PUBLIC ASM SAVEDS LONG DevAbortIO(REG(a1) struct IOExtTD *ior, REG(a6) BASEPTR);
/*E*/
/*F*/ /* private */
/*E*/


   /*
   ** initialise device
   */
/*F*/ PUBLIC ASM SAVEDS struct Device *DevInit(REG(d0) BASEPTR, REG(a0) ULONG seglist, REG(a6) struct Library *_SysBase)
{
   BOOL ok;
   UBYTE *p;
   UWORD i;

   d(("entered device, initialising device base...\n"));

      /* clear data base */
   for(p = ((UBYTE*)mb) + sizeof(struct Library), i = sizeof(struct MemoryBase)-sizeof(struct Library); i; i--)
      *p++ = 0;

   SysBase = _SysBase;

   mb->mb_SegList = seglist;           /* store DOS segment list */

   InitSemaphore(&mb->mb_Lock);

   ok = TRUE;

   d(("left %ld\n",ok));

   return (struct Device *)(ok ? mb : NULL);
}
/*E*/

   /*
   ** open device
   */
/*F*/ PUBLIC ASM SAVEDS LONG DevOpen(REG(a1) struct IOExtTD *iotd, REG(d0) ULONG unit, REG(d1) ULONG flags, REG(a6) BASEPTR)
{
   LONG rv = 0;

   d(("entered\n"));

   /* Make sure our open remains single-threaded. */
   ObtainSemaphore(&mb->mb_Lock);

   mb->mb_DevNode.lib_OpenCnt++;
   mb->mb_DevNode.lib_Flags &= ~LIBF_DELEXP;
   iotd->iotd_Req.io_Error = 0;
   iotd->iotd_Req.io_Unit = NULL;
   iotd->iotd_Req.io_Device = (struct Device *)mb;
   iotd->iotd_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;

   ReleaseSemaphore(&mb->mb_Lock);

   return rv;
}
/*E*/

   /*
   ** close device
   */
/*F*/ PUBLIC ASM SAVEDS BPTR DevClose(REG(a1) struct IOExtTD *ior, REG(a6) BASEPTR)
{
   BPTR seglist;

   d2(("entered\n"));

   ObtainSemaphore(&mb->mb_Lock);

      /* invalidate IO request block */
   ior->iotd_Req.io_Device = (struct Device *)-1;
   ior->iotd_Req.io_Unit = (struct Unit *)-1;

   mb->mb_DevNode.lib_OpenCnt--;

   ReleaseSemaphore(&mb->mb_Lock);

   if (mb->mb_DevNode.lib_Flags & LIBF_DELEXP)
      seglist = DevExpunge(mb);
   else
      seglist = 0;

   return seglist;
}
/*E*/
/*F*/ PUBLIC ASM SAVEDS BPTR DevExpunge(REG(a6) BASEPTR)
{
   BPTR seglist;

   d2(("entered\n"));

   if (mb->mb_DevNode.lib_OpenCnt)
   {
      mb->mb_DevNode.lib_Flags |= LIBF_DELEXP;
      seglist = 0;
   }
   else
   {
         /* detach device from system list */
      Remove((struct Node*)mb);

         /* save seglist for return value */
      seglist = (long)mb->mb_SegList;

         /* return memory
         **
         ** NO FURTHER ACCESS TO DEVICE BASE ALLOWED!
         */
      FreeMem(((char *)mb) - mb->mb_DevNode.lib_NegSize,
         (ULONG)(mb->mb_DevNode.lib_PosSize + mb->mb_DevNode.lib_NegSize));
   }

   return seglist;
}
/*E*/

   /*
   ** initiate io command (1st level dispatcher)
   */
#if 0
/*F*/ static INLINE VOID DevForwardIO(BASEPTR, struct IOExtTD *iotd)
{
   d(("forwarding request %ld\n", iotd->iotd_Req.io_Command));

   /* request is no longer of type "quick i/o" */
   iotd->iotd_Req.io_Flags &= ~IOF_QUICK;
   PutMsg(mb->mb_ServerPort, (struct Message*)iotd);
}
/*E*/
#endif
/*F*/ PUBLIC VOID DevTermIO(BASEPTR, struct IOExtTD *iotd)
{
   d(("cmd = %ld, error = %ld, wireerror = %ld\n", iotd->iotd_Req.io_Command, iotd->iotd_Req.io_Error,iotd->iotd_WireError));

                  /* if this command was done asynchonously, we must
                  ** reply the request
                  */
   if(!(iotd->iotd_Req.io_Flags & IOF_QUICK))
      ReplyMsg((struct Message *)iotd);
   else           /* otherwise just mark it as done */
      iotd->iotd_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
}
/*E*/
/*F*/ PUBLIC ASM SAVEDS VOID DevBeginIO(REG(a1) struct IOExtTD *iotd, REG(a6) BASEPTR)
{
      /* mark request as active */
   iotd->iotd_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
   iotd->iotd_Req.io_Error = 0;

   d(("cmd = %ld\n",iotd->iotd_Req.io_Command));

   switch(iotd->iotd_Req.io_Command)
   {
      case CMD_READ:
         CopyMemQuick((UBYTE*)iotd->iotd_Req.io_Offset, (UBYTE*)iotd->iotd_Req.io_Data,
                  (ULONG)iotd->iotd_Req.io_Length);
         iotd->iotd_Req.io_Actual = iotd->iotd_Req.io_Length;
      break;

      case CMD_WRITE:
         CopyMemQuick((UBYTE*)iotd->iotd_Req.io_Data, (UBYTE*)iotd->iotd_Req.io_Offset,
                  (ULONG)iotd->iotd_Req.io_Length);
         iotd->iotd_Req.io_Actual = iotd->iotd_Req.io_Length;
      break;

      case CMD_RESET:
      case CMD_UPDATE:
      case CMD_CLEAR:
      case CMD_STOP:
      case CMD_START:
      case CMD_FLUSH:
      break;

      case TD_PROTSTATUS:
         iotd->iotd_Req.io_Actual = 0; /* not protected */
      break;

      case TD_MOTOR:
         iotd->iotd_Req.io_Actual = 0;
      break;

      case TD_FORMAT:
         iotd->iotd_Req.io_Actual = iotd->iotd_Req.io_Length;
      break;

      default:
         iotd->iotd_Req.io_Error = IOERR_NOCMD;
      break;
   }

   if (iotd) DevTermIO(mb, iotd);

   return;
}
/*E*/

   /*
   ** stop io-command
   */
/*F*/ PUBLIC ASM SAVEDS LONG DevAbortIO(REG(a1) struct IOExtTD *ior, REG(a6) BASEPTR)
{
   d(("cmd = %ld\n",ior->iotd_Req.io_Command));

   return 0;
}
/*E*/

