#include <resources/battmembitsshared.h>
#include <resources/battmembitsamiga.h>
#include <resources/battmem.h>
#include <exec/execbase.h>
#include <dos/dosextens.h>
#include <exec/memory.h>
#include <dos/rdargs.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/battmem.h>

	/* Argument template and extra help. */

#define ARG_TEMPLATE	"T=Timeout/K,U=UseLUNS/K,H=HostID/K/N,S=Sync/K,F=Fast/K,Q=Queue/K"

#define ARG_HELP	"\nUsage: SetBatt [Timeout L|S] [UseLUNS Y|N] [HostID n] [Sync Y|N]\n\
               [Fast Y|N] [Queue Y|N]\n\n\
               Timeout Set (L)ong or (S)hort SCSI selection timeout.\n\
               UseLUNS Access logical units above 0 at any given\n\
                       SCSI address, responds to (Y)es or (N)o.\n\
               HostID  Set the SCSI controller's host ID, correct IDs are 0..7.\n\
               Sync    Initiate synchronous transfer, responds to\n\
                       (Y)es or (N)o.\n\
               Fast    Initiate fast synchronous transfer, responds to\n\
                       (Y)es or (N)o.\n\
               Queue   Enable SCSI-2 tagged queuing, responds to\n\
                       (Y)es or (N)o.\n\n"

#define ARG_MAXNUM 6

	/* Argument vector offsets. */

enum {
	ARG_TIMEOUT, ARG_USELUNS, ARG_HOSTID, ARG_SYNC, ARG_FAST, ARG_QUEUE
};

	/* Handy international toupper() macro. */

#define ToUpper(c)	((((c) >= 224 && (c) <= 254) || ((c) >= 'a' && (c) <= 'z')) ? (c) - 32 : (c))

	/* Shared library identifiers. */

extern struct ExecBase *SysBase;
extern struct DosLibrary *DOSBase;

struct Library *BattMemBase;

	/* Version string. */

static char setbattver[] = "\0$VER: SetBatt 1.1 (4.5.94)";

	/* Prototypes for this module. */

void ShowConfig (void);

	/* Main():

	 *      Main entry point to this module.
	 */

int main (void)
{
	LONG Result = RETURN_FAIL;

	/* Set up SysBase. */

	/* SysBase = *(struct ExecBase **) 4; */
	/* SysBase = (struct ExecBase *)OpenLibrary("exec.library",37); */

	/* Open dos.library. */

	if (DOSBase = (struct DosLibrary *) OpenLibrary ("dos.library", 37)) {
		/* Open battmem.resource. */

		if (BattMemBase = (struct Library *) OpenResource (BATTMEMNAME)) {
			struct RDArgs *ArgsPtr;
			UBYTE **Args;

			/* Allocate space for the RDArgs auxilary structure. */

			if (ArgsPtr = AllocVec (sizeof (struct RDArgs), MEMF_PUBLIC | MEMF_CLEAR)) {
				/* Provide extended help information. */

				ArgsPtr->RDA_ExtHelp = ARG_HELP;

				/* Allocate space for the arguments. */

				if (Args = (UBYTE **) AllocVec (sizeof (UBYTE *) * ARG_MAXNUM, MEMF_PUBLIC | MEMF_CLEAR)) {
					/* Read the args if any. */

					if (ReadArgs (ARG_TEMPLATE, (APTR) Args, ArgsPtr)) {
						UBYTE Data;

						Result = RETURN_OK;

						/* Obtain exclusive access
						 * to battmem.resource.
						 */

						ObtainBattSemaphore ();

						/* Set the SCSI scan timeout. */

						if (Args[ARG_TIMEOUT]) {
							switch (ToUpper (Args[ARG_TIMEOUT][0])) {
							case 'L':
								Data = 1;
								WriteBattMem (&Data, BATTMEM_SCSI_TIMEOUT_ADDR, BATTMEM_SCSI_TIMEOUT_LEN);
								break;

							case 'S':
								Data = 0;
								WriteBattMem (&Data, BATTMEM_SCSI_TIMEOUT_ADDR, BATTMEM_SCSI_TIMEOUT_LEN);
								break;

							default:
								Printf ("SetBatt: Argument not recognized \"%s\".\n", Args[ARG_TIMEOUT]);
								Result = RETURN_FAIL;
								break;
							}
						}

						/* Toggle LUNs. */

						if (Result != RETURN_FAIL) {
							if (Args[ARG_USELUNS]) {
								switch (ToUpper (Args[ARG_USELUNS][0])) {
								case 'Y':
									Data = 1;
									WriteBattMem (&Data, BATTMEM_SCSI_LUNS_ADDR, BATTMEM_SCSI_LUNS_LEN);
									break;

								case 'N':
									Data = 0;
									WriteBattMem (&Data, BATTMEM_SCSI_LUNS_ADDR, BATTMEM_SCSI_LUNS_LEN);
									break;

								default:
									Printf ("SetBatt: Argument not recognized \"%s\".\n", Args[ARG_USELUNS]);
									Result = RETURN_FAIL;
									break;
								}
							}
						}

						/* Select SCSI host ID. */

						if (Result != RETURN_FAIL) {
							if (Args[ARG_HOSTID]) {
								LONG ID = *((LONG *) Args[ARG_HOSTID]);

								if (ID < 0 || ID > 7) {
									Printf ("SetBatt: SCSI Host ID must be between 0 and 7.\n");
									Result = RETURN_FAIL;
								}
								else {
									Data = ID ^ 7;
									WriteBattMem (&Data, BATTMEM_SCSI_HOST_ID_ADDR, BATTMEM_SCSI_HOST_ID_LEN);
								}
							}
						}

						/* Toggle (general) synchronous transfer. */

						if (Result != RETURN_FAIL) {
							if (Args[ARG_SYNC]) {
								switch (ToUpper (Args[ARG_SYNC][0])) {
								case 'Y':
									Data = 1;
									WriteBattMem (&Data, BATTMEM_SCSI_SYNC_XFER_ADDR, BATTMEM_SCSI_SYNC_XFER_LEN);
									break;

								case 'N':
									Data = 0;
									WriteBattMem (&Data, BATTMEM_SCSI_SYNC_XFER_ADDR, BATTMEM_SCSI_SYNC_XFER_LEN);
									break;

								default:
									Printf ("SetBatt: Argument not recognized \"%s\".\n", Args[ARG_SYNC]);
									Result = RETURN_FAIL;
									break;
								}
							}
						}

						/* Toggle FAST synchronous transfer. */

						if (Result != RETURN_FAIL) {
							if (Args[ARG_FAST]) {
								switch (ToUpper (Args[ARG_FAST][0])) {
								case 'Y':
									Data = 0;
									WriteBattMem (&Data, BATTMEM_SCSI_FAST_SYNC_ADDR, BATTMEM_SCSI_FAST_SYNC_LEN);
									break;

								case 'N':
									Data = 1;
									WriteBattMem (&Data, BATTMEM_SCSI_FAST_SYNC_ADDR, BATTMEM_SCSI_FAST_SYNC_LEN);
									break;

								default:
									Printf ("SetBatt: Argument not recognized \"%s\".\n", Args[ARG_FAST]);
									Result = RETURN_FAIL;
									break;
								}
							}
						}

						/* Toggle SCSI-2 tagged queuing. */

						if (Result != RETURN_FAIL) {
							if (Args[ARG_QUEUE]) {
								switch (ToUpper (Args[ARG_QUEUE][0])) {
								case 'Y':
									Data = 1;
									WriteBattMem (&Data, BATTMEM_SCSI_TAG_QUEUES_ADDR, BATTMEM_SCSI_TAG_QUEUES_LEN);
									break;

								case 'N':
									Data = 0;
									WriteBattMem (&Data, BATTMEM_SCSI_TAG_QUEUES_ADDR, BATTMEM_SCSI_TAG_QUEUES_LEN);
									break;

								default:
									Printf ("SetBatt: Argument not recognized \"%s\".\n", Args[ARG_QUEUE]);
									Result = RETURN_FAIL;
									break;
								}
							}
						}

						/* Show the current configuration. */

						if (Result != RETURN_FAIL)
							ShowConfig ();

						/* Release access semaphore. */

						ReleaseBattSemaphore ();

						/* Start the cleanup. */

						FreeArgs (ArgsPtr);
					}
					else
						PrintFault (IoErr (), "SetBatt");

					FreeVec (Args);
				}
				else
					Printf ("SetBatt: Unable to allocate argument line!\n");

				FreeVec (ArgsPtr);
			}
		}
		else
			Printf ("SetBatt: Failed to open \"%s\"!\n", BATTMEMNAME);

		CloseLibrary ((struct Library *) DOSBase);
	}

	return (Result);
}



	/* ShowConfig():

	 *      Display the current battmem settings.
	 */

void ShowConfig (void)
{
	UBYTE Data;

	/* Amnesia on the Amiga side? */

	if (!ReadBattMem (&Data, BATTMEM_AMIGA_AMNESIA_ADDR, BATTMEM_AMIGA_AMNESIA_LEN)) {
		if (!(Data & 1))
			Printf ("\33[33mWarning\33[31m - a memory loss has occured on the Amiga side!\n\n");
	}

	/* Long or short timeouts? */

	if (!ReadBattMem (&Data, BATTMEM_SCSI_TIMEOUT_ADDR, BATTMEM_SCSI_TIMEOUT_LEN)) {
		if (Data & 1)
			Printf ("The SCSI selection timeout is \33[33mLONG\33[31m (2 seconds).\n");
		else
			Printf ("The SCSI selection timeout is \33[33mSHORT\33[31m (128 milliseconds).\n");
	}

	/* Scan LUNs? */

	if (!ReadBattMem (&Data, BATTMEM_SCSI_LUNS_ADDR, BATTMEM_SCSI_LUNS_LEN)) {
		if (Data & 1)
			Printf ("Logical SCSI units above 0 \33[33mARE\33[31m accessed.\n");
		else
			Printf ("Logical SCSI units above 0 \33[33mARE NOT\33[31m accessed.\n");
	}

	Printf ("\n");

	/* Amnesia on the shared Amiga/Amix side? */

	if (!ReadBattMem (&Data, BATTMEM_SHARED_AMNESIA_ADDR, BATTMEM_SHARED_AMNESIA_LEN)) {
		if (!(Data & 1))
			Printf ("\33[33mWarning\33[31m - a memory loss has occured on the shared Amiga/Unix side!\n\n");
	}

	/* Show SCSI host ID. */

	if (!ReadBattMem (&Data, BATTMEM_SCSI_HOST_ID_ADDR, BATTMEM_SCSI_HOST_ID_LEN))
		Printf ("The SCSI controller's host ID is \33[33m%ld\33[31m.\n", (Data & 7) ^ 7);

	/* Synchronous transfer enabled? */

	if (!ReadBattMem (&Data, BATTMEM_SCSI_SYNC_XFER_ADDR, BATTMEM_SCSI_SYNC_XFER_LEN)) {
		if (Data & 1)
			Printf ("Synchronous transfer is \33[33mINITIATED\33[31m.\n");
		else
			Printf ("Synchronous transfer is \33[33mNOT INITIATED\33[31m.\n");
	}

	/* Fast synchronous transfer enabled? */

	if (!ReadBattMem (&Data, BATTMEM_SCSI_FAST_SYNC_ADDR, BATTMEM_SCSI_FAST_SYNC_LEN)) {
		if (Data & 1)
			Printf ("Fast synchronous transfer is \33[33mNOT INITIATED\33[31m (<=5MB/s).\n");
		else
			Printf ("Fast synchronous transfer is \33[33mINITIATED\33[31m (>5MB/s).\n");
	}

	/* SCSI-2 tagged queuing enabled? */

	if (!ReadBattMem (&Data, BATTMEM_SCSI_TAG_QUEUES_ADDR, BATTMEM_SCSI_TAG_QUEUES_LEN)) {
		if (Data & 1)
			Printf ("SCSI-2 tagged queuing is \33[33mENABLED\33[31m.\n");
		else
			Printf ("SCSI-2 tagged queuing is \33[33mDISABLED\33[31m.\n");
	}
}
