(c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
The information contained herein is subject to change without notice, and 
is provided "as is" without warranty of any kind, either expressed or implied.  
The entire risk as to the use of this information is assumed by the user.




                     Using the Serial and 
                    Parallel Port Resources

                         by Dan Baker 
                      and Bryce Nesbitt



In some Amiga applications, such as MIDI drivers, the need for high
performance throughput makes direct access to the serial or parallel
hardware desirable.  By going directly to the hardware, the normal overhead
of the serial.device or parallel.device can be eliminated.

In order to get direct access to the hardware in a way that is compatible
with multi-tasking, you should use the GetMiscResource() and
FreeMiscResource() routines.  These two routines let you temporarily bar
other tasks from using the resource.  You may then use the associated
hardware directly for your special purposes and then return the resource
back to the system for other tasks to use.

GetMiscResource() and FreeMiscResource() are described in Appendix C of the
ROM Kernel Manual: Libraries and Devices.  Since these two routines do not
have a library base pointer name, they can only be called from an assembly
language program.  Here's a working example that gets one of the two 
miscellaneous resources:

=======  LAUREN, CODE STARTS HERE!!  ===============================

* OPT L+
*
* 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.
*
* When a task has sucessfully obtained the serial resource, it "owns"
* the hardware registers that control the serial port.  No other tasks
* are allowed to interfere.
*
* This example must be linked with "amiga.lib"
*
*
* Wednesday 07-Dec-88 19:35:13 Bryce Nesbitt
*
*               INCDIR  "inc:"
                INCLUDE "exec/types.i"
                INCLUDE "resources/misc.i"
                INCLUDE "libraries/dos.i"

_AbsExecBase    EQU 4

JSRLIB  MACRO               ;Macro for easy use of system functions
        XREF    _LVO\1
        JSR     _LVO\1(A6)
        ENDM


                move.l  _AbsExecBase,a6 ;Prepare to use exec
                lea.l   MiscName(pc),a1
                JSRLIB  OpenResource    ;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
                JSRLIB  Wait                ;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


==========  LAUREN, CODE ENDS HERE!  ==============

Note that 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 C definitions and structures. 


Under V1.3 and earlier versions of the Amiga system software, there is a bug
in the way the the serial and parallel port resources are handled.  That is,
the GetMiscResource() routine will always fail if the serial.device has
been used at all by another task - even if that task is done using the
resource.  In other words, once a printer driver has been activated, it will
keep the associated resource locked up preventing your task from using it.


One way around this is to cause a 'memory panic' with the Exec call
AllocMem(0x7FFFFFFFL,0L).  This will cause libraries and resources not
currently in use to be flushed.  However this method has some drawbacks.  It
is unfriendly to other tasks that may be running in the system.  If the user
goes back to a library-based task after a general memory expunge, the user
might be required to reload large libraries from floppy disk.  What is
needed is a less drastic way to get a resource back from a device driver
which has a hold on it.  The code shown below will do this:



==============  LAUREN, THE REST IS CODE!  ===========
 
  /*
   * 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().  Code by Bryce Nesbitt.
   */
   #include "exec/types.h"
   #include "exec/execbase.h"

   void FlushDevice(char *);

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

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




