Copyright (c) Hyperion Entertainment and contributors.

Difference between revisions of "Resources"

From AmigaOS Documentation Wiki
Jump to navigation Jump to search
Line 1: Line 1:
 
{{NeedUpdate}}
 
{{NeedUpdate}}
   
[[Introduction]]
+
[[Introduction to Amiga System Resources]]
  +
  +
[[BattClock Resource]]
   
 
= Resources =
 
= Resources =

Revision as of 21:49, 16 April 2012

Warning.png This page is not yet fully updated to AmigaOS 4.x some of the information contained here may not be applicable in part or totally.

Introduction to Amiga System Resources

BattClock Resource

Resources

The Amiga’s low-level hardware control functions are collectively referred to as “Resources”. Most applications will never need to use the hardware at the resource level—the Amiga’s device interface is much more convenient and provides for multitasking. However, some high performance applications, such as MIDI time stamping, may require direct access to the Amiga hardware registers.

The Amiga Resources

There are currently seven standard resources in the Amiga system. The following lists the name of each resource and its function.

battclock.resource grants access to the battery-backed clock chip.
battmem.resource grants access to non-volatile RAM.
cia.resource grants access to the interrupts and timer bits of the 8520 CIA (Complex Interface Adapter) chips.
disk.resource grants temporary exclusive access to the disk hardware.
FileSystem.resource grants access to the file system.
misc.resource grants exclusive access to functional blocks of chip registers. At present, definitions have been made for the serial and parallel hardware only.
potgo.resource manages the bits of the proportional I/O pins on the game controller ports.

The resources allow you direct access to the hardware in a way that is compatible with multitasking. They also allow you to temporarily bar other tasks from using the resource. You may then use the associated hardware directly for your special purposes. If applicable, you must return the resource back to the system for other tasks to use when you are finished with it.

See the Amiga Hardware Reference Manual for detailed information on the actual hardware involved.

Look Before You Leap. Resources are just one step above direct hardware manipulation. You are advised to try the higher level device and library approach before resorting to the hardware.

Resource Interface

Resources provide functions that you call to do low-level operations with the hardware they access. In order to use the functions of a resource, you must obtain a pointer to the resource. This is done by calling the OpenResource() function with the resource name as its argument.

OpenResource() returns a pointer to the resource you request or NULL if it does not exist.

#include <resources/filesysres.h>

struct FileSysResource *FileSysResBase = NULL;

if (!(FileSysResBase = OpenResource(FSRNAME)))
    printf("Cannot open %s\n",FSRNAME);

There is no CloseResource() function. When you are done with a resource, you are done with it. However, as you will see later in this chapter, some resources provide functions to allocate parts of the hardware they access. In those cases, you will have to free those parts for anyone else to use them.

Each resource has at least one include file in the resources subdirectory of the include directory. Some of the include files contain only the name of the resource; others list structures and bit definitions used by the resource. The include files will be listed at the end of this chapter.

Calling a resource function is the same as calling any other function on the Amiga. You have to know what parameters it accepts and the return value, if any. The Autodocs for each resource lists the functions and their requirements.

#include <hardware/cia.h>
#include <resources/cia.h>

struct Library *CIAResource = NULL;

void main()
{

WORD mask = 0;

if (!(CIAResource = OpenResource(CIABNAME)))
    printf("Cannot open %s\n",CIABNAME);
else
   {
    /* What is the interrupt enable mask? */
     mask = AbleICR(CIAResource,0);

    printf("\nThe CIA interrupt enable mask: %x \n",mask);
   }
}
Looks Can Be Deceiving. Some resources may look like libraries and act like libraries, but be assured they are not libraries.

BattClock Resource

The battery-backed clock (BattClock) keeps Amiga time while the system is powered off. The time from the BattClock is loaded into the Amiga system clock as part of the boot sequence.

The battclock resource provides access to the BattClock. Three functions allow you to read the BattClock value, reset it and set it to a value you desire.

BattClock Resource Functions

ReadBattClock() Read the time from the BattClock and returns it as the number of seconds since 12:00 AM, January 1, 1978.
ResetBattClock() Reset the BattClock to 12:00 AM, January 1, 1978.
WriteBattClock() Set the BattClock to the number of seconds you pass it relative to 12:00 AM, January 1, 1978.

The utility.library contains time functions which convert the number of seconds since 12:00 AM, January 1, 1978 to a date and time we can understand, and vice versa. You will find these functions useful when dealing with the BattClock. The example program below uses the Amiga2Date() utility function to convert the value returned by ReadBattClock(). See the “Utility Library” chapter of the Amiga ROM Kernel Reference Manual: Libraries for a discussion of the utility.library and the Amiga ROM Kernel Reference Manual: Includes and Autodocs for a listing of its functions.

So, You Want to Be A Time Lord? This resource will allow you to set the BattClock to any value you desire. Keep in mind that this time will endure a reboot and could adversely affect your system.
/*
 * Read_BattClock.c
 *
 * Example of reading the BattClock and converting its output to
 * a useful measure of time by calling the Amiga2Date() utility function.
 *
 * Compile with SAS C 5.10  lc -b1 -cfistq -v -y -L
 *
 * Run from CLI only
 */

#include <exec/types.h>
#include <dos/dos.h>
#include <utility/date.h>
#include <resources/battclock.h>

#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/battclock_protos.h>
#include <clib/utility_protos.h>

#include <stdio.h>

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable SAS CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

VOID main(VOID);

struct Library *UtilityBase = NULL;
struct Library *BattClockBase;

VOID main(VOID)
{
UBYTE *Days[] ={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
UBYTE *Months[] = {"January","February","March","April","May","June",
                   "July","August","September","October","November","December"};
UBYTE *ampm;
ULONG AmigaTime;
struct ClockData MyClock;

if (UtilityBase = (struct Library *)OpenLibrary("utility.library",33))
    {
    if (BattClockBase= OpenResource(BATTCLOCKNAME))
        {
        /* Get number of seconds till now */
        AmigaTime = ReadBattClock();

        /* Convert to a ClockData structure */
        Amiga2Date(AmigaTime,&MyClock);

        printf("\nRobin, tell everyone the BatDate and BatTime");

        /* Print the Date */
        printf("\n\nOkay Batman, the BatDate is ");
        printf("%s, %s %d, %d",Days[MyClock.wday],Months[MyClock.month-1],
                               MyClock.mday,MyClock.year);

        /* Convert military time to normal time and set AM/PM */
        if (MyClock.hour < 12)
            ampm = "AM";        /* hour less than 12, must be morning */
        else
            {
            ampm = "PM";         /* hour greater than 12,must be night */
            MyClock.hour -= 12;  /* subtract the extra 12 of military */
            };

        if (MyClock.hour == 0)
            MyClock.hour = 12;   /* don't forget the 12s */

        /* Print the time */
        printf("\n             the BatTime is ");
        printf("%d:%02d:%02d %s\n\n",MyClock.hour,MyClock.min,MyClock.sec,ampm);
        }
    else
       printf("Error: Unable to open the %s\n",BATTCLOCKNAME);

    /* Close the utility library */
    CloseLibrary(UtilityBase);
    }

else
    printf("Error: Unable to open utility.library\n");
}

Additional programming information on the battclock resource can be found in the include files and the Autodocs for the battclock resource and the utility library.

BattMem Resource

The battery-backed memory (BattMem) preserves a small portion of Amiga memory while the system is powered off. Some of the information stored in this memory is used during the system boot sequence.

The battmem resource provides access to the BattMem. Four functions allow you to use the BattMem.

BattMem Resource Functions

ObtainBattSemaphore Obtain exclusive access to the BattMem.
ReadBattMem() Read a bitstring from the BattMem. You specify the bit position and the number of bits you wish to read.
ReleaseBattSemaphore() Relinquish exclusive access to the BattMem.
WriteBattMem() Write a bitstring to the BattMem. You specify the bit position and the number of bits you wish to write.

The system considers BattMem to be a set of bits rather than bytes. This is done to conserve the limited space available. All bits are reserved, and applications should not read, or write undefined bits. Writing bits should be done with extreme caution since the settings will survive power-down/power-up. You can find the bit definitions in the BattMem include files resources/battmembitsamiga.h, resources/battmembitsamix.h and resources/battmembitsshared.h. They should be consulted before you do anything with the resource.

You Don’t Need This Resource. The BattMem resource is basically for system use only. There is generally no reason for applications to use it. It is documented here simply for completeness.

Additional information on the battmem resource can be found in the include files and the Autodocs for the battmem resource.

BattMem Resource Information

Includes
resources/battmem.i
resources/battmembitsamiga.h
resources/battmembitsamix.h
resources/battmembitsshared.h

AutoDocs
battmem.doc

CIA Resource

The CIA resource provides access to the timers and timer interrupt bits of the 8520 Complex Interface Adapter (CIA) A and B chips. This resource is intended for use by high performance timing applications such as MIDI time stamping and SMPTE time coding.

Four functions allow you to interact with the CIA hardware.

ll

2cCIA Resource Functions
AbleICR() & 8.7cmEnable or disable Interrupt Control Register interrupts. Can also return the current or previous enabled interrupt mask.
AddICRVector() & 8.7cmAllocate one of the CIA timers by assigning an interrupt handler to an interrupt bit and enabling the interrupt of one of the timers. If the timer you request is not available, a pointer to the interrupt structure that owns it will be returned.
RemICRVector() & 8.7cmRemove an interrupt handler from an interrupt bit and disable the interrupt.
SetICR() & 8.7cmCause or clear one or more interrupts, or return the current or previous interrupt status.


Each CIA chip has two interval timers within it—Timer A and Timer B—that may be available. The CIA chips operate at different interrupt levels with the CIA-A timers at interrupt level 2 and the CIA-B timers at interrupt level 6.

boxChoose A Timer Wisely.The timer you use should be based solely on interrupt level and availability. If the timer you request is not available, try for another. Whatever you do, do not base your decision on what you think the timer is used for by the system.

You allocate a timer by calling AddICRVector(). This is the only way you should access a timer. If the function returns zero, you have successfully allocated that timer. If it is unavailable, the owner interrupt will be returned.

/* allocate CIA-A Timer A */
inta = AddICRVector (CIAResource, CIAICRB_TA, &tint);

if (inta)  /* if allocate was not successful */
    printf("Error: Could not allocate timer\n");
else
    {
    ...ready for timing
    }

The timer is deallocated by calling RemICRVector(). This is the only way you should deallocate a timer.

RemICRVector(CIAResource, CIAICRB_TA, &tint);

Your application should not make any assumptions regarding which interval timers (if any) are available for use; other tasks or critical operating system routines may be using the interval timers. In fact, in the latest version of the operating system, the timer device may dynamically allocate one of the interval timers.

boxTime Is Of The Essence!There are a limited number of free CIA interval timers. Applications which use the interval timers may not be able to run at the same time if all interval timers are in use. As a general rule, you should use the timer device for most interval timing.

You read from and write to the CIA interrupt control registers using SetICR() and AbleICR(). SetICR() is useful for sampling which cia interrupts (if any) are active. It can also be used to clear and generate interrupts. AbleICR() is used to disable and enable a particular CIA interrupt. Additional information about these functions can be found in the Amiga ROM Kernel Reference Manual: Includes and Autodocs.

Things to keep in mind:

  1. Never

    directly read from or write to the CIA interrupt control registers. Always use SetICR() and AbleICR().

  2. Your interrupt routine will be called with a pointer to your data area in register A1, and a pointer to the code being called in register A5. No other registers are set up for you. You must observe the standard convention of preserving all registers except D0–D1 and A0–A1.

  3. Never turn off all level 2 or level 6 interrupts. The proper way to disable interrupts for an interval timer that you’ve successfully allocated is via the AbleICR() function.

  4. Interrupt handling code should be written in assembly code and, if possible, should signal a task to do most of the work.

  5. Do not make assumptions about which CIA interval timers (if any) are available for use. The only proper way to own an interval timer is via the AddICRVector() function.

  6. Do not use SetICR(), AbleICR() and RemICRVector() to affect timers or other CIA hardware which your task does not own.

Changes in the CIA resource:

  • In pre-V36 versions of the operating system, SetICR() could return FALSE for a particular interrupt just prior to processing the interrupt. SetICR() now returns TRUE for a particular interrupt until sometime after the interrupt has been processed.
  • Applications which only need to read a CIA interval timer should use the ReadEClock() function of the timer device. See the “Timer Device” chapter of this manual for more information on ReadEClock().
  • The timer device may dynamically allocate a free CIA interval timer. Do not make any assumptions regarding which interval timers are in use unless you are taking over the machine completely.
/*
 * Cia_Interval.c
 *
 * Demonstrate allocation and use of a cia interval timer
 *
 * Compile with SAS C 5.10  lc -b1 -cfistq -v -y -L
 *
 * Run from CLI only
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <exec/interrupts.h>
#include <hardware/cia.h>
#include <resources/cia.h>

#include <clib/exec_protos.h>
#include <clib/cia_protos.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>


/* prototypes */

void    StartTimer      (struct freetimer *ft, struct exampledata *ed);
int     FindFreeTimer   (struct freetimer *ft, int preferA);
int     TryTimer        (struct freetimer *ft);
void    main            ( USHORT, char **);


/* see usage of these defines in StartTimer() below */

#define COUNTDOWN 20
#define HICOUNT 0xFF
#define LOCOUNT 0xFF

#define STOPA_AND  CIACRAF_TODIN |CIACRAF_PBON | CIACRAF_OUTMODE | CIACRAF_SPMODE

        /*
        ;
        ; AND mask for use with control register A
        ; (interval timer A on either CIA)
        ;
        ; STOP -
        ;       START bit 0 == 0 (STOP IMMEDIATELY)
        ;       PBON  bit 1 == same
        ;       OUT   bit 2 == same
        ;       RUN   bit 3 == 0 (SET CONTINUOUS MODE)
        ;       LOAD  bit 4 == 0 (NO FORCE LOAD)
        ;       IN    bit 5 == 0 (COUNTS 02 PULSES)
        ;       SP    bit 6 == same
        ;       TODIN bit 7 == same (unused on ciacra)

        */

#define STOPB_AND  CIACRBF_ALARM | CIACRBF_PBON | CIACRBF_OUTMODE

        /*
        ;
        ; AND mask for use with control register B
        ; (interval timer B on either CIA)
        ;
        ; STOP -
        ;       START bit 0 == 0 (STOP IMMEDIATELY)
        ;       PBON  bit 1 == same
        ;       OUT   bit 2 == same
        ;       RUN   bit 3 == 0 (SET CONTINUOUS MODE)
        ;       LOAD  bit 4 == 0 (NO FORCE LOAD)
        ;       IN0   bit 5 == 0 (COUNTS 02 PULSES)
        ;       IN1   bit 6 == 0 (COUNTS 02 PULSES)
        ;       ALARM bit 7 == same (TOD alarm control bit)

        */

#define STARTA_OR  CIACRAF_START

        /*
        ;
        ; OR mask for use with control register A
        ; (interval timer A on either CIA)
        ;
        ; START -
        ;
        ;       START bit 0 == 1 (START TIMER)
        ;
        ;       All other bits unaffected.
        ;

        */

#define STARTB_OR  CIACRBF_START

        /*
        ;
        ; OR mask for use with control register B
        ; (interval timer A on either CIA)
        ;
        ; START -
        ;
        ;       START bit 0 == 1 (START TIMER)
        ;
        ;       All other bits unaffected.
        ;

        */


/*
 * Structure which will be used to hold all relevant information about
 * the cia timer we manage to allocate.
 *
 */

struct freetimer
{
    struct Library *ciabase;        /* CIA Library Base             */
    ULONG  timerbit;                /* timer bit allocated          */
    struct CIA *cia;                /* ptr to hardware              */
    UBYTE *ciacr;                   /* ptr to control register      */
    UBYTE *cialo;                   /* ptr to low byte of timer     */
    UBYTE *ciahi;                   /* ptr to high byte of timer    */
    struct Interrupt timerint;      /* Interrupt structure          */
    UBYTE  stopmask;                /* Stop/set-up timer            */
    UBYTE  startmask;               /* Start timer                  */
};

/*
 * Structure which will be used by the interrupt routine called
 * when our cia interval timer generates an interrupt.
 *
 */

struct exampledata
{
    struct Task *task;      /* task to signal */
    ULONG   signal;         /* Signal bit to use */
    ULONG   counter;
};


struct CIA *ciaa = (struct CIA *)0xbfe001;
struct CIA *ciab = (struct CIA *)0xbfd000;


#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable SAS CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

/*
 * This is the interrupt routine which will be called when our CIA
 * interval timer counts down.
 *
 * This example decrements a counter each time the interrupt routine
 * is called until the counter reaches 0, at which time it signals
 * our main task.
 *
 * Note that interrupt handling code should be efficient, and will
 * generally be written in assembly code.  Signaling another task
 * such as this example does is also a useful way of handling
 * interrupts in an expedient manner.
 */

void __asm ExampleInterrupt(register __a1 struct exampledata *ed)
{
if (ed->counter)
    {
    ed->counter--;                  /* decrement counter */
    }
else
    {
    ed->counter = COUNTDOWN;        /* reset counter     */

    Signal(ed->task,(1L << ed->signal));
    }
}


/***********************************
 *  main()
 ***********************************/

void main(USHORT argc,char **argv)
{
struct freetimer ft;
struct exampledata ed;

/* Set up data which will be passed to interrupt */

ed.task = FindTask(0L);

if (ed.signal = AllocSignal(-1L))
    {
    /* Prepare freetimer structure : set-up interrupt */

    ft.timerint.is_Node.ln_Type = NT_INTERRUPT;
    ft.timerint.is_Node.ln_Pri  = 0;
    ft.timerint.is_Node.ln_Name = "cia_example";

    ft.timerint.is_Data         = (APTR)&ed;
    ft.timerint.is_Code         = (APTR)ExampleInterrupt;

    /* Call function to find a free CIA interval timer
     * with flag indicating that we prefer a CIA-A timer.
     */

    printf("Attempting to allocate a free timer\n");

    if (FindFreeTimer(&ft,TRUE))
        {
        if (ft.cia == ciaa)
            {
            printf("CIA-A timer ");
            }
        else
            {
            printf("CIA-B timer ");
            }

        if (ft.timerbit == CIAICRB_TA)
            {
            printf("A allocated\n");
            }
        else
            {
            printf("B allocated\n");
            }


        /* We found a free interval timer.  Let's start it running. */

        StartTimer(&ft,&ed);

        /* Wait for a signal */

        printf("Waiting for signal bit %ld\n",ed.signal);

        Wait(1L<<ed.signal);

        printf("We woke up!\n");

        /* Release the interval timer */

        RemICRVector(ft.ciabase,ft.timerbit,&ft.timerint);

        }
    else
        {
        printf("No CIA interval timer available\n");
        }

    FreeSignal(ed.signal);
    }
}


/*
 * This routine sets up the interval timer we allocated with
 * AddICRVector().  Note that we may have already received one, or
 * more interrupts from our timer.  Make no assumptions about the
 * initial state of any of the hardware registers we will be using.
 *
 */

void StartTimer(struct freetimer *ft, struct exampledata *ed)
{
register struct CIA *cia;

cia = ft->cia;

/* Note that there are differences between control register A,
 * and B on each CIA (e.g., the TOD alarm bit, and INMODE bits.
 */

if (ft->timerbit == CIAICRB_TA)
    {
    ft->ciacr = &cia->ciacra;       /* control register A   */
    ft->cialo = &cia->ciatalo;      /* low byte counter     */
    ft->ciahi = &cia->ciatahi;      /* high byte counter    */

    ft->stopmask = STOPA_AND;       /* set-up mask values   */
    ft->startmask = STARTA_OR;
    }
else
    {
    ft->ciacr = &cia->ciacrb;       /* control register B   */
    ft->cialo = &cia->ciatblo;      /* low byte counter     */
    ft->ciahi = &cia->ciatbhi;      /* high byte counter    */

    ft->stopmask = STOPB_AND;       /* set-up mask values   */
    ft->startmask = STARTB_OR;
    }


/* Modify control register within Disable().  This is done to avoid
 * race conditions since our compiler may generate code such as:
 *
 *      value = Read hardware byte
 *      AND  value with MASK
 *      Write value to hardware byte
 *
 * If we take a task switch in the middle of this sequence, two tasks
 * trying to modify the same register could trash each others' bits.
 *
 * Normally this code would be written in assembly language using atomic
 * instructions so that the Disable() would not be needed.
 */


Disable();

/* STOP timer, set 02 pulse count-down mode, set continuous mode */

*ft->ciacr &= ft->stopmask;
Enable();

/* Clear signal bit - interrupt will signal us later */
SetSignal(0L,1L<<ed->signal);

/* Count-down X # of times */
ed->counter = COUNTDOWN;

/* Start the interval timer - we will start the counter after
 * writing the low, and high byte counter values
 */

*ft->cialo = LOCOUNT;
*ft->ciahi = HICOUNT;

/* Turn on start bit - same bit for both A, and B control regs  */

Disable();
*ft->ciacr |= ft->startmask;

Enable();
}


/*
 * A routine to find a free interval timer.
 *
 * This routine makes no assumptions about which interval timers
 * (if any) are available for use.  Currently there are two interval
 * timers per CIA chip.
 *
 * Because CIA usage may change in the future, your code should use
 * a routine like this to find a free interval timer.
 *
 * Note that the routine takes a preference flag (which is used to
 * to indicate that you would prefer an interval timer on CIA-A).
 * If the flag is FALSE, it means that you would prefer an interval
 * timer on CIA-B.
 *
 */

FindFreeTimer(struct freetimer *ft, int preferA)
{
struct CIABase *ciaabase, *ciabbase;

/* get pointers to both resource bases */

ciaabase = OpenResource(CIAANAME);
ciabbase = OpenResource(CIABNAME);

/* try for a CIA-A timer first ? */

if (preferA)
    {
    ft->ciabase = ciaabase; /* library address  */
    ft->cia     = ciaa;     /* hardware address */
    }
else
    {
    ft->ciabase = ciabbase; /* library address  */
    ft->cia     = ciab;     /* hardware address */
    }

if (TryTimer(ft))
    return(TRUE);

/* try for an interval timer on the other cia */

if (!(preferA))
    {
    ft->ciabase = ciaabase; /* library address  */
    ft->cia     = ciaa;     /* hardware address */
    }
else
    {
    ft->ciabase = ciabbase; /* library address  */
    ft->cia     = ciab;     /* hardware address */
    }

if (TryTimer(ft))
    return(TRUE);

return(FALSE);

}


/*
 * Try to obtain a free interval timer on a CIA.
 */

TryTimer(struct freetimer *ft)
{

if (!(AddICRVector(ft->ciabase,CIAICRB_TA,&ft->timerint)))
    {
    ft->timerbit = CIAICRB_TA;
    return(TRUE);
    }

if (!(AddICRVector(ft->ciabase,CIAICRB_TB,&ft->timerint)))
    {
    ft->timerbit = CIAICRB_TB;
    return(TRUE);
    }

return(FALSE);
}

Additional programming information on the CIA resource can be found in the include files and the Autodocs for the CIA resource and the 8520 spec. The includes files and Autodocs are in the Amiga ROM Kernel Reference Manual: Includes and Autodocs and the 8520 spec is in the Amiga Hardware Reference Manual.

|ll|

2cCIA Resource Information
Includes & resources/cia.h
& resources/cia.i
& hardware/cia.h
& hardware/cia.i
AutoDocs & cia.doc
Hardware & 8520 specification


Disk Resource

The Disk resource obtains exclusive access to the floppy disk hardware There are four disk/MFM units available, units 0–3.

Six functions are available for dealing with the floppy disk hardware.

ll

2cDisk Resource Functions
AllocUnit() & Allocate one of the units of the disk resource.
FreeUnit() & Deallocate an allocated disk unit.
GetUnit() & Allocate the disk for a driver.
GetUnitID() & Return the drive ID of a specified drive unit.
GiveUnit() & Free the disk.
ReadUnitID() & Reread and return the drive ID of a specified unit.


The disk resource provides both a gross and a fine unit allocation scheme. AllocUnit() and FreeUnit() are used to claim a unit for long term use, and GetUnit() and GiveUnit() are used to claim a unit and the disk hardware for shorter periods.

The trackdisk device uses and abides by both allocation schemes. Because a trackdisk unit is never closed for Amiga 3.5’’ drives (the file system keeps them open) the associated resource units will always be allocated for these drives. GetUnit() and GiveUnit() can still be used, however, by other applications that have not succeeded with AllocUnit().

You must not change the state of of a disk that the trackdisk device is using unless you either

  1. force its removal before giving it up, or

  2. return it to the original track (with no changes to the track), or

  3. CMD_STOP

    the unit before GetUnit(), update the current track number and CMD_START it after GiveUnit(). This option is only available under V36 and higher versions of the operating system.

ReadUnitID()

is provided to handle drives which use the unit number in a dynamic manner. Subsequent GetUnit() calls will return the value obtained by ReadUnitID().

It is therefore possible to prevent the trackdisk device from using units that have not yet been mounted by successfully performing an AllocUnit() for that unit. It is also possible to starve trackdisk usage by performing a GetUnit(). The appropriate companion routine (FreeUnit() or GiveUnit()) should be called to restore the resource at the end of its use.

Additional programming information on the disk resource can be found in the include files and the Autodocs for the disk resource.

|ll|

2cDisk Resource Information
Includes & resources/disk.h
& resources/disk.i
AutoDocs & disk.doc


FileSystem Resource

The FileSystem resource returns the filesystems that are available on the Amiga. It has no functions. Opening the FileSystem resource returns a pointer to a List structure containing the current filesystems in the Amiga.

Additional programming information on the FileSystem resource can be found in the include files and the Autodocs for the FileSystem resource in the Amiga ROM Kernel Reference Manual: Includes and Autodocs and the “Expansion” chapter of the Amiga ROM Kernel Reference Manual: Libraries.

|ll|

2cFileSystem Resource Information
Includes & resources/filesysres.h
& resources/filesysres.i
AutoDocs & filesysres.doc
Libraries & expansion.library


Misc Resource

The misc resource oversees usage of the serial data port, the serial communication bits, the parallel data and handshake port, and the parallel communication bits. Before using serial or parallel port hardware, it first must be acquired from the misc resource.

The misc resource provides two functions for allocating and freeing the serial and parallel hardware.

ll

2cMisc Resource Functions
AllocMiscResource() & 7.8cmAllocate one of the serial or parallel misc resources.
FreeMiscResource() & 7.8cmDeallocate one of the serial or parallel misc resources.


Once you’ve successfully allocated one of the misc resources, you are free to write directly to its hardware locations. Information on the serial and parallel hardware can be found in the Amiga Hardware Reference Manual and the hardware/custom.h include file.

The two examples below are assembly and ’C’ versions of the same code for locking the serial misc resources and waiting for CTRL-C to be pressed before releasing them.

Assembly Example of Allocating Misc Resources

* Alloc_Misc.a
*
* Assembly language fragment that grabs the two parts of the serial
* resource (using misc.resource).  If it gets the resource, it will
* wait for CTRL-C to be pressed before releasing.
*
* While we are waiting, the query_serial program should be run.  It will try
* to open the serial device and if unsuccessful, will return the name of the
* owner.  It will be us, Serial Port Hog!
*
* When a task has successfully obtained the serial resource, it "owns"
* the hardware registers that control the serial port.  No other tasks
* are allowed to interfere.
*
* Assemble with Adapt
*     HX68 Allocate_Misc.a to Allocate_Misc.o
*
* Link
*     Blink FROM Allocate_Misc.o TO Allocate_Misc LIB LIB:amiga.lib
*

                INCDIR  "include:"
                INCLUDE "exec/types.i"
                INCLUDE "resources/misc.i"
                INCLUDE "dos/dos.i"

        xref    _AbsExecBase     ; We get this from outside...
        xref    _LVOOpenResource ; We get this from outside...
        xref    _LVOWait         ; We get this from outside...

;
; Open Exec and the misc.resource, check for success
;
                move.l  _AbsExecBase,a6         ;Prepare to use exec
                lea.l   MiscName(pc),a1
                jsr     _LVOOpenResource(a6)    ;Open "misc.resource"
                move.l  d0,d7                   ;Stash resource base
                bne.s   resource_ok
                moveq   #RETURN_FAIL,d0
                rts

resource_ok     exg.l   d7,a6                   ;Put resource base in A6

;
; We now have a pointer to a resource.
; Call one of the resource's library-like vectors.
;
                move.l  #MR_SERIALBITS,d0       ;We want these bits
                lea.l   MyName(pc),a1           ;This is our name
                jsr     MR_ALLOCMISCRESOURCE(a6)
                tst.l   d0
                bne.s   no_bits                 ;Someone else has it...
                move.l  #MR_SERIALPORT,d0
                lea.l   MyName(pc),a1
                jsr     MR_ALLOCMISCRESOURCE(a6)
                tst.l   d0
                bne.s   no_port                 ;Someone else has it...
;
; We just stole the serial port registers; wait.
; Nobody else can use the serial port, including the serial.device!
;
                exg.l   d7,a6                   ;use exec again
                move.l  #SIGBREAKF_CTRL_C,d0
                jsr     _LVOWait(a6)            ;Wait for CTRL-C
                exg.l   d7,a6                   ;Get resource base back
;
; Free 'em up
;
                move.l  #MR_SERIALPORT,d0
                jsr     MR_FREEMISCRESOURCE(a6)
no_port
                move.l  #MR_SERIALBITS,d0
                jsr     MR_FREEMISCRESOURCE(a6)
no_bits
                moveq   #RETURN_FAIL,d0
                rts
;
; Text area
;
MiscName        dc.b    'misc.resource',0
MyName          dc.b    'Serial Port Hog',0
                dc.w    0
                END

’C’ Example of Allocating Misc Resources

/*
 * Allocate_Misc.c
 *
 * Example of allocating a miscellaneous resource
 * We will allocate the serial resource and wait till
 * CTRL-C is pressed.  While we are waiting, the
 * query_serial program should be run.  It will try
 * to open the serial device and if unsuccessful, will
 * return the name of the owner.  It will be us!
 *
 * Compile with SAS C 5.10  lc -b1 -cfistq -v -y -L
 *
 * Run from CLI only
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <resources/misc.h>

#include <clib/exec_protos.h>
#include <clib/misc_protos.h>

#include <stdio.h>

#ifdef LATTICE
int CXBRK(void) { return(0); }  /* Disable SAS CTRL/C handling */
int chkabort(void) { return(0); }  /* really */
#endif

struct Library *MiscBase = NULL;

void main(int argc, char **argv)
{
UBYTE *owner = NULL;       /* owner of misc resource */

if (!(MiscBase= (struct Library *)OpenResource(MISCNAME)))
    printf("Cannot open %s\n",MISCNAME);
else
   {
    /* Allocate both pieces of the serial hardware */
    if ((owner = AllocMiscResource(MR_SERIALPORT,"Serial Port Hog")) == NULL)
        {
        if ((owner = AllocMiscResource(MR_SERIALBITS,"Serial Port Hog")) == NULL)
            {
            /* Wait for CTRL-C to be pressed */
            printf("\nWaiting for CTRL-C...\n");
            Wait(SIGBREAKF_CTRL_C);

            /* We're back */

            /* Deallocate the serial port register */
            FreeMiscResource(MR_SERIALBITS);
            }
        else
            printf("\nUnable to allocate MR_SERIALBITS because %s owns it\n",owner);

        /* Deallocate the serial port */
        FreeMiscResource(MR_SERIALPORT);
       }
    else
       printf("\nUnable to allocate MR_SERIALPORT because %s owns it\n",owner);
   }
}

The example below will try to open the serial device and execute the SDCMD_QUERY command. If it cannot open the serial device, it will do an AllocMiscResource() on the serial port and return the name of the owner.

boxTake Over Everything.There are two serial.device resources to take over, MR_SERIALBITS and MR_SERIALPORT. You should get both resources when you take over the serial port to prevent other tasks from using them. The parallel.device also has two resources to take over. See the resources/misc.h include file for the relevant definitions and structures.

Under V1.3 and earlier versions of the Amiga system software the MR_GETMISCRESOURCE routine will always fail if the serial device has been used at all by another task (even if that task has finished using the resource. In other words, once a printer driver or communication package has been activated, it will keep the associated resource locked up preventing your task from using it. Under these conditions, you must get the resource back from the system yourself.

You do this by calling the function FlushDevice():

/*
 * A safe way to expunge ONLY a certain device.  The serial.device holds
 * on to the misc serial resource until a general expunge occurs.
 * This code attempts to flush ONLY the named device out of memory and
 * nothing else.  If it fails, no status is returned since it would have
 * no valid use after the Permit().
 */

#include <exec/types.h>
#include <exec/execbase.h>

#include <clib/exec_protos.h>

void FlushDevice(char *);

extern struct ExecBase *SysBase;

void FlushDevice(char *name)
{
struct Device *devpoint;

Forbid();

if (devpoint=(struct Device *)FindName(&SysBase->DeviceList,name) )
    RemDevice(devpoint);

Permit();
}

Additional programming information on the misc resource can be found in the include files and the Autodocs for the misc resource.

|ll|

2cMisc Resource Information
Includes & resources/misc.h
& resources/misc.i
AutoDocs & misc.doc


Potgo Resource

The potgo resource is used to get control of the hardware POTGO register connected to the proportional I/O pins on the game controller ports. There are two registers, POTGO (write-only) and POTINP (read-only). These pins could also be used for digital I/O.

The potgo resource provides three functions for working with the POTGO hardware.

ll

2cPotgo Resource Functions
AllocPotBits() & 8.7cmAllocate bits in the POTGO register.
FreePotBits() & 8.7cmFree previously allocated bits in the POTGO register.
WritePotgo() & 8.7cmSet and clear bits in the POTGO register. The bits must have been allocated before calling this function.


The example program shown below demonstrates how to use the ptogo resource to track mouse button presses on port 1.

/*
 * Read_Potinp.c
 *
 * An example of using the potgo.resource to read pins 9 and 5 of
 * port 1 (the non-mouse port).  This bypasses the gameport.device.
 * When the right or middle button on a mouse plugged into port 1 is pressed,
 * the read value will change.
 *
 * Use of port 0 (mouse) is unaffected.
 *
 * Compile with SAS C 5.10  lc -b1 -cfistq -v -y -L
 *
 * Run from CLI only
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <resources/potgo.h>
#include <hardware/custom.h>

#include <clib/exec_protos.h>
#include <clib/potgo_protos.h>

#include <stdio.h>

#ifdef LATTICE
int CXBRK(void) {return(0);}  /* Disable SAS Ctrl-C checking */
int chkabort(void) { return(0); }  /* really */
#endif

struct PotgoBase *PotgoBase;
ULONG potbits;
UWORD value;

#define UNLESS(x) if(!(x))
#define UNTIL(x)  while(!(x))

#define OUTRY 1L<<15
#define DATRY 1L<<14
#define OUTRX 1L<<13
#define DATRX 1L<<12

extern struct Custom far custom;

void main(int argc,char **argv)
{
UNLESS (PotgoBase=(struct PotgoBase *)OpenResource("potgo.resource"))
        return;

potbits=AllocPotBits(OUTRY|DATRY|OUTRX|DATRX);

/* Get the bits for the right and middle mouse buttons on the alternate mouse port. */

if (potbits != (OUTRY|DATRY|OUTRX|DATRX))
    {
    printf("Pot bits are already allocated! %lx\n",potbits);
    FreePotBits(potbits);
    return;
    }

/* Set all ones in the register (masked by potbits) */
WritePotgo(0xFFFFFFFFL,potbits);

printf("\nPlug a mouse into the second port.  This program will indicate when\n");
printf("the right or middle button (if the mouse is so equipped) is pressed.\n");
printf("Stop the program with Control-C. Press return now to begin.\n");

getchar();

UNTIL (SIGBREAKF_CTRL_C & SetSignal(0L,0L))
      /* until CTRL-C is pressed */
      {
      /* Read word at $DFF016 */
        value = custom.potinp;

      /* Show what was read (restricted to our allocated bits) */
      printf("POTINP = $%lx\n",value & potbits);
      }

FreePotBits(potbits);
}

Additional programming information on the potgo resource can be found in the include files and the Autodocs for the potgo resource.

|ll|

2cPotgo Resource Information
Includes & resources/potgo.h
& resources/potgo.i
& utility/hooks.h
& utility/hooks.i
AutoDocs & potgo.doc