/* Disk.c - Disk support routines */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the author.                                           BBS:      */
/* | o  | ||   John Toebes    Dave Baker                     (919)-471-6436  */
/* |  . |//                                                                  */
/* ======                                                                    */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "handler.h"
#define PHYSSIZE 512
extern void  DskChngIntA(); /* Assem disk change interrupt server routine */ 


void RemDskChngInt(global)
GLOBAL global;
{
   BUG(("RemChngInt\n"));
   if (global->dskchngpkt != NULL)
      {
      /* now remove the disk change interrupt */
      global->devreq->iotd_Req.io_Command = TD_REMCHANGEINT;
BUG(("devreq Rmsgprt: %08lx\n",global->devreq->iotd_Req.io_Message.mn_ReplyPort))
BUG(("dskchngR msgprt: %08lx\n",global->dskchngpkt->dc_req.iotd_Req.io_Message.mn_ReplyPort));
BUG(("task msgprt: %08lx\n",global->port));
BUG(("devmsg msgprt: %08lx\n",global->devport));
      DoIO((struct IORequest *)global->devreq);
     
BUG(("DoIO end\n"));
      DeleteExtIO((struct IORequest *)global->dskchngpkt);
   }
BUG(("RemChngInt Exit\n"));
}

void DskChngInt(global)
GLOBAL global;
{
   BUG(("Disk Change Interrupt Called\n"));
   BUG(("DskChng devname:%s\n",global->devname));
   global->changedisk = 1;
}

int AddDskChngInt(global)
GLOBAL global;    
{

   /* assumes that a msg port has been allocated */   
   if (((global->dskchngpkt) = (struct DskChngPacket *)
      CreateExtIO(global->port, sizeof(struct DskChngPacket)))== NULL)
      return(NULL);

   /* Copy the Device and Unit pointers from OpenDevice */
   global->dskchngpkt->dc_req.iotd_Req.io_Device =
                       global->devreq->iotd_Req.io_Device;
   global->dskchngpkt->dc_req.iotd_Req.io_Unit =
                       global->devreq->iotd_Req.io_Unit;
   global->dskchngpkt->dc_req.iotd_Req.io_Flags = 0;

   BUG(("Reply port %08lx vs %08lx\n", 
         global->dskchngpkt->dc_req.iotd_Req.io_Message.mn_ReplyPort,
         global->port));
   global->dskchngpkt->dc_req.iotd_Req.io_Command = TD_ADDCHANGEINT;
   global->dskchngpkt->dc_req.iotd_Req.io_Data    = 
                (APTR)&(global->dskchngpkt->dc_int);     
 
   /* Initialize the interrupt structure */
   global->dskchngpkt->dc_int.is_Node.ln_Type = NT_INTERRUPT;
   global->dskchngpkt->dc_int.is_Node.ln_Pri  = 0;
   global->dskchngpkt->dc_int.is_Node.ln_Name = "DskChngInt";
   global->dskchngpkt->dc_int.is_Data         = (APTR)global;
   global->dskchngpkt->dc_int.is_Code         = DskChngIntA;
     
   /* Async IO so we don't sleep here for the msg */
   SendIO((struct IORequest *)&global->dskchngpkt->dc_req);
 
   return(1);
    
}

int ReadPhy(global, block, key)
GLOBAL global;
char *block;
KEY key;
{
   BUG(("ReadPhy Block:%08lx Key:%ld\n",block,key));

   /* Make sure the disk is there! */
   if (global->diskstatus == ID_NO_DISK_PRESENT)
      demanddisk(global);

   Motor(global,1);

   global->deviotimeout = 2;
   global->devreq->iotd_Req.io_Length = PHYSSIZE;
   global->devreq->iotd_Req.io_Data   = (APTR)block;

   /* show where to put the data when read */
   global->devreq->iotd_Req.io_Command = ETD_READ;

   /* check that disk not changed before reading */
   global->devreq->iotd_Count = global->DiskChange;

   global->devreq->iotd_Req.io_Offset = TD_SECTOR * key;
   DoIO((struct IORequest *)global->devreq);

   return((int)global->devreq->iotd_Req.io_Error);
}

int WritePhy(global, block, key)
GLOBAL global;
char  *block;
KEY key;
{
   BUG(("WritePhy Block:%08lx Key:%ld\n",block,key));

   /* make sure the disk is there */
   if (global->diskstatus == ID_NO_DISK_PRESENT)
      demanddisk(global);

   Motor(global,1);
   global->deviotimeout = 2;
   global->devreq->iotd_Req.io_Length = PHYSSIZE;
   global->devreq->iotd_Req.io_Data   = (APTR)block;

   /* show where to put the data when read */
   global->devreq->iotd_Req.io_Command = ETD_WRITE;

   /* check that disk not changed before reading */
   global->devreq->iotd_Count = global->DiskChange;

   global->devreq->iotd_Req.io_Offset = TD_SECTOR * key;
   DoIO((struct IORequest *)global->devreq);

   return((int)global->devreq->iotd_Req.io_Error);
}

int Motor(global,flag)
GLOBAL global;
int flag;
{
   /* TURN ON DISK MOTOR ... old motor state is returned in io_Actual */
   global->devreq->iotd_Req.io_Length = flag;

   /* this says motor is to be turned on */
   global->devreq->iotd_Req.io_Command = TD_MOTOR;

   /* do something with the motor */
   DoIO((struct IORequest *)global->devreq);
   return((int)global->devreq->iotd_Req.io_Error);
}

/* Reset the drive for a new disk and return the protection status of it */
int ResetDrive(global)
GLOBAL global;
{
   /* now get the disk change value */
   global->devreq->iotd_Req.io_Command = TD_CHANGESTATE;
   DoIO((struct IORequest *)global->devreq);
   if (global->devreq->iotd_Req.io_Actual)
      {
      BUG(("Pretending no disk in drive\n"));
      global->diskstatus = ID_NO_DISK_PRESENT;
      return(-1);
      }

   global->diskstatus = ID_NOT_REALLY_DOS;

   global->devreq->iotd_Req.io_Command = TD_CHANGENUM;
   DoIO((struct IORequest *)global->devreq);

   global->DiskChange = global->devreq->iotd_Req.io_Actual;

   global->devreq->iotd_Req.io_Command = TD_PROTSTATUS;
   DoIO((struct IORequest *)global->devreq);

   return(global->devreq->iotd_Req.io_Actual);
}

void demanddisk(global)
GLOBAL global;
{
while(global->diskstatus == ID_NO_DISK_PRESENT)
   {
   request(global, REQ_MUST, NULL);
   ResetDrive(global);
   /* We really should verify that we have the right disk but for now */
   /* we will trust the user to follow the requesters                 */
   }
}
