
/*****************************************************\
*  cdx.device demo program -- Disk Change Interrupts  *
*                                                     *
*  Copyright © 1992 Xetec, Inc.                       *
*                                                     *
*  Marty Flickinger                     Jun 19, 1992  *
*******************************************************
* This demo shows how to detect CD disc changes from  *
* the cdx.device directly using the new 1.5 disc-     *
* change interrupt commands (works even if the CD     *
* drive is not mounted (no CD0:)                      *
\*****************************************************/

/* Rev 1.1 */

#include <exec/types.h>
#include <exec/io.h>
#include <exec/interrupts.h>
#include <CDx.h>


struct	Interrupt	CDint;

struct	Task		*AgreedTask;
struct	MsgPort		*CDport;
struct	IOStdReq	*CDreq,CDreq2;

int	TheSigBit = -1;
ULONG	AgreedSignal;
int	OpenError = 1;
int	Count;


void HandleDiscChange(void);
void main(int,char **);
void Cleanup(char *);
int  OpenCDx(int);
void CloseCDx(void);


/*******************************************************\
*	This routine is called every time a CD is	*
*	inserted or removed.  Remember that interrupt	*
*	code is only permitted to call a few Exec	*
*	functions and nothing else.  In this example,	*
*	we bump a counter and send a message to our	*
*	main code.					*
\*******************************************************/

void	HandleDiscChange(void)
{
	Count++;

	Signal(AgreedTask,AgreedSignal);	/* Hey! Wake up! */
}


void main(argc,argv)
int   argc;
char  **argv;
{
	int	drive;

	if (argc==2)
		drive = atoi(argv[1]);

	if ((argc!=2)||(drive<1)||(drive>8))
		Cleanup("Usage: DCItest3 <drive>\n  where <drive> is 1-8\n");


/**** First, prep the info that will allow the Disc-Change interrupt to	****/
/**** alert me that a change has occurred.				****/

	TheSigBit = AllocSignal(-1);		/* Signal bit to watch for */
	if (TheSigBit == -1)
		Cleanup("Can't get a SigBit");
	AgreedSignal = (1<<TheSigBit);		/* Turn into a signal flag */
	AgreedTask = (struct Task *)FindTask(0); /* Task to signal is me */

/**** Now, prepare an IOrequest so I can talk to the cdx.device		****/

	if (OpenCDx(drive-1))				/* Translates to 0-7 */
		Cleanup("Couldn't open cdx.device for that drive");

	Count = 0;

/**** Prepare my interrupt structure & link it to my interrupt code	****/

	CDint.is_Node.ln_Type = NT_INTERRUPT;
	CDint.is_Node.ln_Name = "MyIntTest";
	CDint.is_Code = (void (*)())HandleDiscChange;
	CDint.is_Data = 0;

	printf("My interrupt is %lx\n",&CDint);

/**** OK, give the interrupt to cdx.device.  We use DoIO here because,	****/
/**** unlike the CD_ADDCHANGEINT command, CD_ADDCHANGER will keep the	****/
/**** interrupt but return the IO request				****/

	CDreq->io_Command = CD_ADDCHANGER;
	CDreq->io_Data = (APTR)&CDint;
	CDreq->io_Offset =
		DCI_INSERTIONS | DCI_REMOVALS;	/* Want both reported */
	DoIO(CDreq);		/* Link into device's disc change list */

	printf("Waiting for disc changes now...\n");

/**** In a real application, you would now go on about your business.	****/
/**** By using a line such as:						****/
/****	sigs = Wait(AgreedSignal | (1<<Window->UserPort->mp_SigBit));	****/
/**** you can wait for a disc change or other intuition messages.	****/
/**** For this test, we will just wait until we've received 3 disc	****/
/**** changes, then we exit gracefully.					****/

	do {
		Wait(AgreedSignal);
		printf("(%ld) ",Count);		/* Show my counter number */

/**** If you need to know whether it was an insertion or removal,	****/
/**** just check the state of the drive now.				****/

		CDreq->io_Command = CD_CHANGESTATE;
		DoIO(CDreq);

		if (CDreq->io_Actual == 0)
			printf("Disc inserted\n");
		else
			printf("Disc removed\n");
	} while (Count<3);

/**** Be sure to remove the interrupt, or the system will bomb on disc	****/
/**** changes after you're gone!					****/

	printf("Removing interrupt now\n");
	CDreq->io_Command = CD_REMCHANGER;
	CDreq->io_Data = (APTR)&CDint;		/* Tell it which one */
	DoIO(CDreq);

	Cleanup("Done");
}


void Cleanup(msg)
char  *msg;
{
	printf("%ls\n",msg);		/* Print the 'error' message */

	CloseCDx();			/* Close cdx.device */

	if (TheSigBit != -1)
		FreeSignal(TheSigBit);

	exit(0);
}


/***************************************************************\
*	This routine prepares the request/reply port and	*
*	opens the device (cdx.device)				*
\***************************************************************/

int OpenCDx(unit)
int   unit;
{
	OpenError = 1;

	CDport = (struct MsgPort *)CreatePort(0,0);
	if (CDport) {
		CDreq = (struct IOStdReq *)CreateStdIO(CDport);
		if (CDreq) {
			OpenError = OpenDevice("cdx.device",unit,CDreq,0);
			return(OpenError);
		}
		DeletePort(CDport);
	}
	return(-1);				/* Failed to prep */
}


/***************************************************************\
*	This routine closes the cdx.device and eliminates	*
*	the IOrequest and reply port				*
\***************************************************************/

void CloseCDx(void)
{
	if (!OpenError)
		CloseDevice(CDreq);
	if (CDreq)
		DeleteStdIO(CDreq);
	if (CDport)
		DeletePort(CDport);
	OpenError = 1;
}
