/*
 *
 *	DISCLAIMER:
 *
 *	This program is provided as a service to the programmer
 *	community to demonstrate one or more features of the Amiga
 *	personal computer.  These code samples may be freely used
 *	for commercial or noncommercial purposes.
 * 
 * 	Commodore Electronics, Ltd ("Commodore") makes no
 *	warranties, either expressed or implied, with respect
 *	to the program described herein, its quality, performance,
 *	merchantability, or fitness for any particular purpose.
 *	This program is provided "as is" and the entire risk
 *	as to its quality and performance is with the user.
 *	Should the program prove defective following its
 *	purchase, the user (and not the creator of the program,
 *	Commodore, their distributors or their retailers)
 *	assumes the entire cost of all necessary damages.  In 
 *	no event will Commodore be liable for direct, indirect,
 *	incidental or consequential damages resulting from any
 *	defect in the program even if it has been advised of the 
 *	possibility of such damages.  Some laws do not allow
 *	the exclusion or limitation of implied warranties or
 *	liabilities for incidental or consequential damages,
 *	so the above limitation or exclusion may not apply.
 *
 */

/* 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);
}
