/* This program is probably copyright Commodore-Amiga.  It was mailed
 * to me directly by Robert Peck at Commodore-Amiga in response
 * to a question about a previous version's copyright status.  I
 * therefore assume that it is Commodore-Amiga's intention that this
 * program be freely redistributable.  Fred Fish, 3-Jan-86.
 */
 
/* trackdisk.c */

/* program to demonstrate the use of the trackdisk driver */

/* author: Rob Peck, 12/1/85 */

/* This code may be freely utilized to develop programs for the Amiga */


#include "exec/types.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "exec/ports.h"
#include "exec/libraries.h"
#include "exec/io.h"
#include "exec/tasks.h"
#include "exec/execbase.h"
#include "exec/devices.h"
#include "devices/trackdisk.h"

#define TD_READ CMD_READ
#define BLOCKSIZE TD_SECTOR

SHORT error;
struct MsgPort *diskport;
struct IOExtTD *diskreq;
BYTE diskbuffer[BLOCKSIZE];
BYTE *diskdata;
SHORT testval;
 
extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();
 
ULONG diskChangeCount;
         
ReadCylSec(cyl, sec, hd)
SHORT cyl, sec, hd;
{
        LONG offset;
 
        diskreq->iotd_Req.io_Length = BLOCKSIZE;
        diskreq->iotd_Req.io_Data = (APTR)diskbuffer;
                /* show where to put the data when read */
        diskreq->iotd_Req.io_Command = ETD_READ;
                /* check that disk not changed before reading */
        diskreq->iotd_Count = diskChangeCount;
        
        /* convert from cylinder, head, sector to byte-offset value to get
         * right one (as dos and everyone else sees it)...*/
         
        /* driver reads one CYLINDER at a time (head does not move for
         * 22 sequential sector reads, or better-put, head doesnt move for
         * 2 sequential full track reads.)
         */
        
        offset = TD_SECTOR * (sec + NUMSECS * hd + NUMSECS * NUMHEADS * cyl);
        diskreq->iotd_Req.io_Offset = offset;
        DoIO(diskreq);
        return(0);
}
  
MotorOn()
{
        /* TURN ON DISK MOTOR ... old motor state is returned in io_Actual */
        diskreq->iotd_Req.io_Length = 1;
        /* this says motor is to be turned on */
        diskreq->iotd_Req.io_Command = TD_MOTOR;
        /* do something with the motor */
        DoIO(diskreq);
        printf("\nOld motor state was: %ld",diskreq->iotd_Req.io_Actual);
        printf("\nio_Error value was: %ld",diskreq->iotd_Req.io_Error);
        return(0);
}
 
MotorOff()
{
        printf("\n\nNow turn it off");
        diskreq->iotd_Req.io_Length = 0;
        /* says that motor is to be turned on */
        diskreq->iotd_Req.io_Command = TD_MOTOR;
        /* do something with the motor */
        DoIO(diskreq);
        printf("\nOld motor state was: %ld",diskreq->iotd_Req.io_Actual);
        printf("\nio_Error value was: %ld",diskreq->iotd_Req.io_Error);
        return(0);
}
  
SeekFullRange(howmany)
SHORT howmany;
{
        int i;
        for(i=0; i<howmany; i++)
        {
                diskreq->iotd_Req.io_Offset =
                        ((NUMCYLS -1)*NUMSECS*NUMHEADS -1 ) * 512;
                /* seek to cylinder 79, head 1 */
                diskreq->iotd_Req.io_Command = TD_SEEK;
                DoIO(diskreq);
                if(diskreq->iotd_Req.io_Error != 0)
                        printf("\nSeek Cycle Number %ld, Error = %ld",
                                                i, diskreq->iotd_Req.io_Error);
                diskreq->iotd_Req.io_Offset = 0;
                        /* seek to cylinder 0, head 0 */
                diskreq->iotd_Req.io_Command = TD_SEEK;
                DoIO(diskreq);
                if(diskreq->iotd_Req.io_Error != 0)
                        printf("\nSeek Cycle Number %ld, Error = %ld",
                                                i, diskreq->iotd_Req.io_Error);
                printf("\nCompleted a seek");
        }
        return(0);
}
main()   
{
        SHORT cylinder,head,sector;
        
        diskdata = &diskbuffer[0];
                /* point to first location in disk buffer */
        diskport = CreatePort(0,0);
        if(diskport == 0) exit(100);    /* error in createport */
        diskreq = (struct IOExtTD *)CreateExtIO(diskport,
                                                sizeof(struct IOExtTD));
                /* make an io request block for communicating with the disk */
        if(diskreq == 0) { DeletePort(diskport); exit(200); }
 
            error = OpenDevice(TD_NAME,0,diskreq,0);
                    /* open the device for access, unit 0 is builtin drive */
            printf("\nError value returned by OpenDevice was: %lx", error);
    
            /* now get the disk change value */
            diskreq->iotd_Req.io_Command = TD_CHANGENUM;
            DoIO(diskreq);
            diskChangeCount = diskreq->iotd_Req.io_Actual;
            printf("\nChange number for disk is currently %ld",diskChangeCount);    
            MotorOn();
            SeekFullRange(10);
            for(cylinder=0; cylinder<80; cylinder++)    /* tracks to test */
               { 
               for(head=0; head<2; head++)      /* number of heads to test */
                    for(sector=0; sector<11; sector++)  /* sectors to test */
                    {
                    ReadCylSec(cylinder, sector, head);
                    if(diskreq->iotd_Req.io_Error != 0)
                       printf("\nError At Cyl=%ld, Sc=%ld, Hd=%ld, Error=%ld",
                                    cylinder,sector,head,
                                    diskreq->iotd_Req.io_Error);
                    }
                printf("\nCompleted reading Cylinder=%ld",cylinder);
                }
            MotorOff();
            CloseDevice(diskreq);
 
        DeleteExtIO(diskreq, sizeof(struct IOExtTD));
        DeletePort(diskport);
}       /* end of main */
 
 
/***********************************************************************
*
*       Exec Support Function -- Extended IO Request
*
***********************************************************************/
 
extern APTR AllocMem();
 
/****** exec_support/CreateExtIO **************************************
*
*   NAME
*       CreateExtIO() -- create an Extended IO request
*
*   SYNOPSIS
*       ioReq = CreateExtIO(ioReplyPort,size);
*
*   FUNCTION
*       Allocates memory for and initializes a new IO request block
*       of a user-specified number of bytes.
*
*   INPUTS
*       ioReplyPort - a pointer to an already initialized
*               message port to be used for this IO request's reply port.
*
*   RESULT
*       Returns a pointer to the new block.  Pointer is of the type
*       struct IORequest.
*
*       0 indicates inability to allocate enough memory for the request block
*       or not enough signals available.
*
*   EXAMPLE
*       struct IORequest *myBlock;
*       if( (myBlock = CreateExtIO(myPort,sizeof(struct IOExtTD)) == NULL)
*               exit(NO_MEM_OR_SIGNALS);
*
*       example used to allocate space for IOExtTD (trackdisk driver
*       IO Request block for extended IO operations).
*
*   SEE ALSO
*       DeleteExtIO
*
***********************************************************************/
 
struct IORequest *CreateExtIO(ioReplyPort,size)
    struct MsgPort *ioReplyPort;
    LONG size;
{
    struct IORequest *ioReq;
 
    if (ioReplyPort == 0)
        return ((struct IORequest   *) 0);
 
    ioReq = (struct IORequest *)AllocMem (size, MEMF_CLEAR | MEMF_PUBLIC);
 
    if (ioReq == 0)
        return ((struct IORequest   *) 0);
 
    ioReq -> io_Message.mn_Node.ln_Type = NT_MESSAGE;
    ioReq -> io_Message.mn_Node.ln_Pri = 0;
 
    ioReq -> io_Message.mn_ReplyPort = ioReplyPort;
 
    return (ioReq);
}
  
/****** exec_support/DeleteExtIO **************************************
*
*   NAME
*       DeleteExtIO() - return memory allocated for extended IO request
*
*   SYNOPSIS
*       DeleteExtIO(ioReq,size);
*
*   FUNCTION
*       See summary line at NAME.  Also frees the signal bit which
*       had been allocated by the call to CreateExtIO.
*
*   INPUTS
*       A pointer to the IORequest block whose resources are to be freed.
*
*   RESULT
*       Frees the memory.  Returns (no error conditions shown)
*
*   EXAMPLE
*       struct IORequest *myBlock;
*       DeleteExtIO(myBlock,(sizeof(struct IOExtTD)));
*
*       example shows that CreateExtIO had been used to create a trackdisk
*       (extended) IO Request block.
*
*   SEE ALSO
*       CreateExtIO
*
**************************************************************************/
  
DeleteExtIO(ioExt,size)
    struct IORequest *ioExt;
    LONG size;
{
    ioExt -> io_Message.mn_Node.ln_Type = 0xff;
    ioExt -> io_Device = (struct Device *) -1;
    ioExt -> io_Unit = (struct Unit *) -1;
 
    FreeMem (ioExt, size);
}
