[net.micro.amiga] An Example of a AmigaDOS Handler in 'C'

phillip@cbmvax.cbm.UUCP (Phillip Lindsay) (10/15/86)

[]

An example that implements a AmigaDos Handler (device) in non-BCPL format by
using a new feature introduced in system software release 1.2.

What follows is a shar file which contains the following files:

makefile        ... guess...make for both my-handler and ihand
my-handler.c    ... this is the main handler module 
misc.c          ... this module contains support routines (packet handling)

ihand.c         ... a program to install your device node 
AddDosNode.asm  ... some interface code for Aztec people who don't have
                    a library that supports 1.2                    

Phillip Lindsay - Amiga Technical Support 


my-handler.shar:

***CUT HERE [ I HOPE MY SIGNATURE DIDN'T SNEAK IN ]
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	makefile
#	my-handler.h
#	ihand.c
#	misc.c
#	my-handler.c
#	adddosnode.asm
# This archive created: Wed Oct 15 16:29:52 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'makefile'" '(538 characters)'
if test -f 'makefile'
then
	echo shar: will not over-write existing file "'makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'makefile'
	X# MY-HANDLER - Phillip Lindsay - (C) Commodore 1986
	X#
	X#
	X
	X#DEBUG  = -dDEBUG
	X
	X#DFILE  =  df0:lib/myprintf.o
	X#DFILE  =  df0:lib/debug.o
	X
	XCFLAGS = +lcd -dMANX $(DEBUG)
	X
	XLIBS   =  $(DFILE) -lc32 
	X
	XOFILES = my-handler.o misc.o
	XHFILES = my-handler.h
	X
	X
	X.asm.o:
	X	as $*.asm
	X
	Xall: allhand ihand
	X
	Xallhand: $(OFILES)
	X	ln -w $(OFILES) $(LIBS)
	X
	Xmy-handler.o: my-handler.c $(HFILES)
	X
	Xmisc.o : misc.c $(HFILES)
	X
	X# here is the install program
	X
	Xihand: ihand.o adddosnode.o
	X	ln -w ihand.o adddosnode.o -lc32
	X
	Xihand.o: ihand.c  
	X
	Xadddosnode.o: adddosnode.asm
SHAR_EOF
if test 538 -ne "`wc -c < 'makefile'`"
then
	echo shar: error transmitting "'makefile'" '(should have been 538 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'my-handler.h'" '(325 characters)'
if test -f 'my-handler.h'
then
	echo shar: will not over-write existing file "'my-handler.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'my-handler.h'
	X/* my-handler.h - Phillip Lindsay (C) Commodore 1986
	X *  You may freely distribute this source and use it for Amiga Development -
	X *  as long as the Copyright notice is left intact.
	X *
	X *  globals and misc. data structures 
	X */
	X
	X
	X/* global functions */
	X
	X#ifdef DEBUG
	X
	Xextern long kprintf();
	X
	X#endif
	X
	X/* EOF - my-handler.h */
SHAR_EOF
if test 325 -ne "`wc -c < 'my-handler.h'`"
then
	echo shar: error transmitting "'my-handler.h'" '(should have been 325 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ihand.c'" '(2803 characters)'
if test -f 'ihand.c'
then
	echo shar: will not over-write existing file "'ihand.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'ihand.c'
	X/* ihand.c
	X *
	X * Install a AmigaDos Handler - ( dependent release 1.2 )
	X *
	X * 20-SEP-86 - Phillip Lindsay - (C) Commodore 1986  
	X *  You may freely distribute this source and use it for Amiga Development -
	X *  as long as the Copyright notice is left intact.
	X *
	X * (! Please don't make using this routine a habit, release 1.2 WORKBENCH
	X *    greater than >33.43 offers a new mount command that will allow 
	X *    specification of GlobalVec for non-BCPL modules - Thanks to Andy Finkel !)
	X * 
	X * Example "DEVS:MOUNTLIST" :
	X *------------------------------------------------------------------------------
	X * MY0:	    Handler   = l:my-handler
	X *          Stacksize = 5000
	X *          Priority  = 5
	X *          GlobVec   = 1
	X * #
	X *------------------------------------------------------------------------------
	X */
	X
	X 
	X#include <exec/types.h>
	X#include <exec/memory.h>
	X#include <libraries/dos.h>
	X#include <libraries/dosextens.h>
	X#include <libraries/expansion.h>
	X#include <libraries/filehandler.h>
	X#include <functions.h>
	X
	X#define OVER         0x02L                 /* BSTR overhead for size+NULL  */
	X
	X#define HANDNAMESIZE (0x0cL+OVER)          /* size of BSTR+NULL            */
	X#define HANDNAME     "\x0cl:my-handler\0"  /* BSTR format handler name     */
	X
	X#define DEVNAMESIZE  (0x03L+OVER)          /* size of BSTR+NULL            */
	X#define DEVNAME      "\x03MY0\0"           /* BSTR of device name          */
	X
	X#define PRIORITY	5L
	X#define STACKSIZE	5000L
	X#define GLOBALVEC	-1L
	X
	XULONG ExpansionBase;                        /* for expansion library (1.2) */
	X
	Xmain()
	X{
	X 
	X struct DeviceNode *mynode;
	X
	X UBYTE *handname; 
	X
	X UBYTE  *devname;
	X 
	X
	X handname = AllocMem((ULONG)(HANDNAMESIZE),MEMF_PUBLIC | MEMF_CLEAR);
	X if(!handname) 
	X   exit(TRUE);
	X strcpy(handname,HANDNAME);
	X
	X devname =   AllocMem((ULONG)(DEVNAMESIZE),MEMF_PUBLIC | MEMF_CLEAR);
	X if(!devname)
	X  { 
	X   FreeMem(handname,(ULONG)(HANDNAMESIZE));
	X   exit(TRUE);
	X  }
	X strcpy(devname,DEVNAME);
	X
	X mynode = AllocMem((ULONG)sizeof(*mynode),MEMF_PUBLIC | MEMF_CLEAR); 
	X
	X if(!mynode) 
	X  {
	X   FreeMem(handname,(ULONG)(HANDNAMESIZE));
	X   FreeMem(devname,(ULONG)(DEVNAMESIZE));
	X   exit(TRUE);
	X  }
	X 
	X mynode->dn_Priority     = PRIORITY;
	X mynode->dn_StackSize    = STACKSIZE;
	X mynode->dn_GlobalVec    = GLOBALVEC;   /* (-1) the trick for non-bcpl module */
	X mynode->dn_Name         = (BSTR) ((ULONG)devname  >> 2); /* to BPTR */
	X mynode->dn_Handler      = (BSTR) ((ULONG)handname >> 2); /* ""  ""  */
	X 
	X/* This will fail if your not 1.2 */
	X ExpansionBase = (ULONG) OpenLibrary(EXPANSIONNAME,0L); 
	X
	X if(!ExpansionBase) 
	X  {
	X   FreeMem(handname,(ULONG)(HANDNAMESIZE+2)); 
	X   FreeMem(devname,(ULONG)(DEVNAMESIZE+2));
	X   FreeMem(mynode,(ULONG)sizeof(*mynode));
	X   exit(TRUE);
	X  }
	X 
	X  AddDosNode(0L,0L,mynode);
	X
	X  CloseLibrary(ExpansionBase);  
	X  
	X}
	X
	X/* EOF - ihand.c */
SHAR_EOF
if test 2803 -ne "`wc -c < 'ihand.c'`"
then
	echo shar: error transmitting "'ihand.c'" '(should have been 2803 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'misc.c'" '(1704 characters)'
if test -f 'misc.c'
then
	echo shar: will not over-write existing file "'misc.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'misc.c'
	X/* misc.c  - support routines - Phillip Lindsay (C) Commodore 1986  
	X *  You may freely distribute this source and use it for Amiga Development -
	X *  as long as the Copyright notice is left intact.
	X *
	X * 30-SEP-86
	X */
	X
	X#include <exec/types.h>
	X#include <exec/nodes.h>
	X#include <exec/lists.h>
	X#include <exec/ports.h>
	X#include <libraries/dos.h>
	X#include <libraries/dosextens.h>
	X
	X#ifdef MANX
	X#include <functions.h>
	X#endif
	X
	X/* returnpkt() - packet support routine 
	X * here is the guy who sends the packet back to the sender...
	X * 
	X * (I modeled this just like the BCPL routine [so its a little redundant] )
	X */
	X 
	Xvoid returnpkt(packet,res1,res2)
	X
	Xstruct DosPacket *packet;
	XULONG  res1,res2;
	X
	X{
	X struct Message *mess;
	X struct MsgPort *replyport;
	X struct Process *myproc;
	X 
	X packet->dp_Res1          = res1;
	X packet->dp_Res2          = res2; 
	X replyport                = packet->dp_Port;
	X mess                     = packet->dp_Link;
	X myproc                   = (struct Process *) FindTask(0L);
	X packet->dp_Port          = &myproc->pr_MsgPort;
	X mess->mn_Node.ln_Name    = (char *) packet;
	X mess->mn_Node.ln_Succ    = NULL;
	X mess->mn_Node.ln_Pred    = NULL;
	X 
	X PutMsg(replyport,mess); 
	X
	X}
	X
	X
	X/*
	X * taskwait() ... Waits for a message to arrive at your port and 
	X *   extracts the packet address which is returned to you.
	X */
	X
	Xstruct DosPacket *taskwait()
	X{
	X struct Process *myproc;
	X struct MsgPort *myport;
	X struct Message *mymess;
	X
	X myproc = (struct Process *) FindTask(0L);
	X myport = &myproc->pr_MsgPort;
	X
	X WaitPort(myport); /* wait for packet */
	X mymess = (struct Message *) GetMsg(myport);
	X
	X/* give them the pointer to the packet */
	Xreturn((struct DosPacket *) mymess->mn_Node.ln_Name);
	X} 
	X
	X/* end of misc.c */
SHAR_EOF
if test 1704 -ne "`wc -c < 'misc.c'`"
then
	echo shar: error transmitting "'misc.c'" '(should have been 1704 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'my-handler.c'" '(7856 characters)'
if test -f 'my-handler.c'
then
	echo shar: will not over-write existing file "'my-handler.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'my-handler.c'
	X/*  my-handler.c 
	X *
	X *  This is a "dumb" handler that can be used as a model. 
	X *  Functionally this handler does nothing but "play pretend" so I suppose 
	X *  you could classify my-handler as a NIL: AmigaDOS device.
	X * 
	X *  Phillip Lindsay  (C) 1986 Commodore 
	X *  You may freely distribute this source and use it for Amiga Development -
	X *  as long as the Copyright notice is left intact.
	X *   
	X *  (! Please note that support of non-BCPL modules  
	X *                                          is a new feature in release 1.2 !) 
	X *
	X * A sample "devs:mountlist" entry for a non-bcpl module:
	X * 
	X * (! PLEASE NOTE: that this is supported ONLY by the MOUNT command on
	X *     1.2 WORKBENCH release greater than 33.43 THANKS TO ANDY FINKEL !)     
	X *----------------------------------------------------------------------------- 
	X *   MY0:       Handler   = l:my-handler
	X *              Stacksize = 5000
	X *              Priority  = 5
	X *              GlobVec   = 1
	X *   #
	X * ----------------------------------------------------------------------------
	X * Since most people will not have the new MOUNT command I have included
	X *  a program that uses the expansion.library to install the device node. 
	X * 
	X * But PLEASE don't distribute AmigaDOS device handlers that use a 
	X * "install program." The "mountlist" in almost all cases (except AUTOCONFIG) 
	X *  should be taken advantage of for AmigaDOS device installation.
	X *
	X * I have done this under MANX, but I don't see too much trouble getting
	X * it to work with Lattice...just don't use any startup code and
	X * disable the stack checking on LC2 with '-v'. 
	X * 
	X */
	X
	X#include <exec/types.h>
	X#include <exec/nodes.h>
	X#include <exec/lists.h>
	X#include <exec/ports.h>
	X#include <exec/libraries.h>
	X#include <exec/devices.h>
	X#include <exec/io.h>
	X#include <exec/memory.h>
	X#include <devices/console.h>
	X#include <intuition/intuition.h>
	X#include <libraries/dos.h>
	X#include <libraries/dosextens.h>
	X#include <libraries/filehandler.h>
	X
	X#ifdef MANX
	X#include <functions.h>
	X#endif
	X
	X#include "my-handler.h"
	X
	X/* my version of BADDR() has no problems with casting */
	X#undef  BADDR
	X#define BADDR(x)	((APTR)((long)x << 2))
	X
	X#define ACTION_FIND_INPUT       1005L /* please refer to DOS Tech. Ref. */
	X#define ACTION_FIND_OUTPUT      1006L
	X#define ACTION_END              1007L
	X
	X#define DOS_FALSE	 0L
	X#define DOS_TRUE	-1L           /* BCPL "TRUE" */
	X
	X#ifdef MANX
	XULONG              SysBase, /* these are here to make the startup code happy */
	X                   _savsp;  /* (this is unique to Manx Aztec C startup)      */ 
	X#endif
	X
	X_main() 
	X{
	X
	X /* handler support routines */
	X
	X extern void           returnpkt(); /* sends a packet back to sender          */
	X struct DosPacket      *taskwait(); /* waits for packet from the world        */
	X
	X
	X /* handler related data structures */
	X
	X struct Process        *myproc;     /* my process                             */
	X struct DosPacket      *mypkt;      /* a pointer to the dos packet sent       */
	X BSTR                  parmdevname; /* pointer to device name in parmpkt Arg1 */
	X long                  parmextra;   /* extra info passed in parmpkt      Arg2 */
	X struct DeviceNode     *mynode;     /* our device node passed in parmpkt Arg3 */
	X struct FileHandle     *fh;         /* a pointer to our file handle           */
	X long                  open;        /* handler open flag                      */
	X long                  run;         /* handler main loop flag                 */
	X
	X/* I have left all my debug's in...you'll see how they save you headaches
	X * the first time you try to debug your handler...
	X */
	X 
	X#ifdef DEBUG
	X  kprintf("**** Start my-handler ****\n");
	X#endif
	X
	X/* misc. init. */
	X myproc          = (struct Process *) FindTask(0L);  /* find myself        */
	X open            = DOS_FALSE;                       /* not open            */
	X run             = TRUE;                           /* handler loop flag    */
	X
	X/* since we were started as a non-BCPL module we get sent the parameter pkt */
	X/* (ie. parameter packet not in D1) */
	X
	Xmypkt = taskwait();  /* wait for parameter packet */
	X
	X#ifdef DEBUG
	X kprintf("Got Parmeter Packet.\n");
	X#endif
	X
	X parmdevname     = (BSTR)  mypkt->dp_Arg1;  /* BSTR name passed to handler   */
	X parmextra       = mypkt->dp_Arg2;          /* Extra Info passed             */
	X
	X /* get pointer to our device node */
	X mynode = (struct DeviceNode *) BADDR(mypkt->dp_Arg3); /* ptr to device node */
	X
	X /*
	X  * This is where you do your handler initialization
	X  *  Open what ever devices ... parse the device name passed in
	X  *  the parameter packet...etc...
	X  */
	X
	X
	X/* if initialzation was possible then we... */
	X 
	X mynode->dn_Task = &myproc->pr_MsgPort; /* install our taskid ...
	X                             * if we don't...for every reference to our handler
	X                             * a NEW process will be created.  This is fine for
	X                             * things like CON: (console handler) but if you
	X                             * plan to be the only dude on block ( like the
	X                             * file-system handler or SER: ) you should fill
	X                             * the task field with your taskid 
	X                             * (ie. &(pr_MsgPort) )
	X                             * Note: remember that shared code has to be
	X                             *  reentrant. (like CON: handler) 
	X                             *  ( keep your variables on the stack [autos],
	X                             *    and allocate memory for larger data
	X                             *  structures and "FLAG" global data structures
	X                             *  that need only be intialized once ) 
	X                             */
	X#ifdef DEBUG
	X kprintf("Returning parmeter packet...A-O-K.\n");
	X#endif
	X 
	Xreturnpkt(mypkt,DOS_TRUE,mypkt->dp_Res2);    /* everything a-o-k */
	X
	X#ifdef DEBUG
	X kprintf("Waiting for packet..\n");
	X#endif
	X
	X while(run)   /* start of the real work */
	X  {
	X   mypkt = taskwait();  /* wait for a packet */
	X 
	X   switch(mypkt->dp_Type)
	X    {
	X     case ACTION_FIND_INPUT:     /* opening your device */
	X     case ACTION_FIND_OUTPUT: 
	X
	X#ifdef DEBUG
	X kprintf("Action FindInput/Ouput : %ld\n",mypkt->dp_Type);
	X#endif
	X 
	X          fh = (struct FileHandle *) BADDR(mypkt->dp_Arg1);  
	X          fh->fh_Port = DOS_TRUE;
	X          open++;
	X          returnpkt(mypkt,DOS_TRUE,mypkt->dp_Res2);
	X          break;
	X     
	X     case ACTION_END:
	X
	X#ifdef DEBUG
	X kprintf("Action End : %ld\n",mypkt->dp_Type);
	X#endif
	X
	X/* we want to fall out of the loop if not OPEN.
	X */
	X
	X          if((--open) <= 0)  run = FALSE;
	X         
	X          returnpkt(mypkt,DOS_TRUE,mypkt->dp_Res2);
	X          break;
	X
	X     case ACTION_READ:
	X
	X#ifdef DEBUG
	X kprintf("Action Read : %ld\n",mypkt->dp_Type);
	X#endif
	X
	X/* we *always* read nothing */
	X
	X          returnpkt(mypkt,0L,mypkt->dp_Res2);
	X          break;
	X
	X     case ACTION_WRITE:
	X#ifdef DEBUG
	X kprintf("Action Write : %ld\n",mypkt->dp_Type);
	X#endif
	X
	X/* we *always* write everything */
	X
	X          returnpkt(mypkt,mypkt->dp_Arg3,mypkt->dp_Res2);   
	X          break;
	X
	X     default:
	X#ifdef DEBUG
	X kprintf("Unknown packet type %ld\n",mypkt->dp_Type);
	X#endif
	X/* say what? */
	X          returnpkt(mypkt,DOS_FALSE,ERROR_ACTION_NOT_KNOWN);
	X
	X    } /* end of switch(mypkt->dp_Type) */   
	X    
	X  } /* end of while(run) */
	X
	X
	X mynode->dn_Task = FALSE; /* zero the taskid field of device node */
	X
	X /* INSERT HERE -> do some clean up and leave */
	X 
	X/* we are a process "so we fall off the end of the world" */
	X
	X/*  If we are reentrant we can't rely on our initial stack being saved.
	X *  Which means NO exit()'s ... We must just fall through....If your
	X *  not reentrant then don't worry about ending here.
	X *
	X * BTW, you don't necessarlly have to leave...You could stick around and
	X * wait all day for packets....its all according to what your handler
	X * is set-up to do. 
	X */
	X
	X} /* end of _main() */
	X
	X
	X
	X/* EOF - end of my-handler */
SHAR_EOF
if test 7856 -ne "`wc -c < 'my-handler.c'`"
then
	echo shar: error transmitting "'my-handler.c'" '(should have been 7856 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'adddosnode.asm'" '(602 characters)'
if test -f 'adddosnode.asm'
then
	echo shar: will not over-write existing file "'adddosnode.asm'"
else
sed 's/^	X//' << \SHAR_EOF > 'adddosnode.asm'
	X* AddDosNode.asm 
	X*
	X* Interface code for AddDosNode() ... 
	X* 19-SEP-86 - Phillip Lindsay - (C) Commodore 1986 
	X*  You may freely distribute this source and use it for Amiga Development -
	X*  as long as the Copyright notice is left intact.
	X*
	X* This is for AZTEC people who don't have a library that supports new functions
	X*
	X
	X_LVOAddDosNode	EQU	-150
	X
	X	XREF	_ExpansionBase
	X
	X        XDEF    _AddDosNode 	
	X       
	X
	X_AddDosNode:
	X
	X	move.l 	a6,-(sp)
	X        move.l  _ExpansionBase,a6
	X        movem.l 8(sp),d0-d1/a0
	X        jsr	_LVOAddDosNode(a6)	
	X        move.l (sp)+,a6
	X        rts
	X        
	X        END
	X
	X* EOF
SHAR_EOF
if test 602 -ne "`wc -c < 'adddosnode.asm'`"
then
	echo shar: error transmitting "'adddosnode.asm'" '(should have been 602 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
-- 

==============================================================================
  Phillip Lindsay - Commodore Business Machines - Amiga Technical Support
    Dirt: 1200 Wilson Drive, West Chester  PA 19380                
    uucp: {ihnp4|seismo|caip}!cbmvax!phillip
    arpa: cbmvax!phillip@seismo -or- phillip@cbmvax.UUCP@{seismo | harvard}
    Tel.: (215) 431-9180
Disclaimer: [someone said I needed this] No warranty is implied or otherwise
   given in the form of suggestion or example. Any opinions found here are of
   my making. [unless Fred pops up (my other self)] 
==============================================================================