erickson@cbmvax.cbm.UUCP (Lee Erickson) (10/21/86)
The following source is intended to serve as a demo disk device driver.
Since I can't email you "demo" hardware, it functions as a RAM disk.
I don't really recommend that you USE it as a RAM disk, but it should be
very helpful to those of you trying to implement hard disk drivers....
Lee Erickson
#! /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:
# asmsupp.i
# messages.i
# mydev.i
# mydev.asm
# testdev.asm
# makefile
# This archive created: Mon Oct 20 17:20:51 1986
export PATH; PATH=/bin:$PATH
echo shar: extracting "'asmsupp.i'" '(1056 characters)'
if test -f 'asmsupp.i'
then
echo shar: will not over-write existing file "'asmsupp.i'"
else
sed 's/^ X//' << \SHAR_EOF > 'asmsupp.i'
X
X*************************************************************************
X* *
X* Copyright (C) 1985, Commodore Amiga Inc. All rights reserved. *
X* Permission granted for non-commercial use * *
X* *
X*************************************************************************
X
X
X*************************************************************************
X*
X* asmsupp.i -- random low level assembly support routines
X*
X* Source Control
X* ------ -------
X*
X* $Header: asmsupp.i,v 31.1 85/10/13 23:12:33 neil Exp $
X*
X* $Locker: $
X*
X*************************************************************************
X
XCLEAR MACRO ; quick way to clear a D register on 68000
X MOVEQ #0,\1
X ENDM
X
XBHS MACRO
X BCC.\0 \1
X ENDM
X
XBLO MACRO
X BCS.\0 \1
X ENDM
X
XEVEN MACRO ; word align code stream
X DS.W 0
X ENDM
X
XLINKSYS MACRO ; link to a library without having to see a _LVO
X LINKLIB _LVO\1,\2
X ENDM
X
XCALLSYS MACRO ; call a library without having to see _LVO
X CALLLIB _LVO\1
X ENDM
X
XXLIB MACRO ; define a library reference without the _LVO
X XREF _LVO\1
X ENDM
X
SHAR_EOF
if test 1056 -ne "`wc -c < 'asmsupp.i'`"
then
echo shar: error transmitting "'asmsupp.i'" '(should have been 1056 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'messages.i'" '(853 characters)'
if test -f 'messages.i'
then
echo shar: will not over-write existing file "'messages.i'"
else
sed 's/^ X//' << \SHAR_EOF > 'messages.i'
X
X*************************************************************************
X* *
X* Copyright (C) 1985, Commodore Amiga Inc. All rights reserved. *
X* Permission granted for non-commercial use *
X* *
X*************************************************************************
X
X
X*************************************************************************
X*
X* messages.i
X*
X* Source Control
X* ------ -------
X*
X* $Header: messages.i,v 31.1 85/10/13 23:12:48 neil Exp $
X*
X* $Locker: $
X*
X*************************************************************************
X
X XREF KPutFmt
X
XPUTMSG: MACRO * level,msg
X
X IFGE INFO_LEVEL-\1
X
X PEA subSysName(PC)
X MOVEM.L A0/A1/D0/D1,-(SP)
X LEA msg\@,A0
X LEA 4*4(SP),A1
X JSR KPutFmt
X MOVEM.L (SP)+,D0/D1/A0/A1
X ADDQ.L #4,SP
X BRA.S end\@
X
Xmsg\@ DC.B \2
X DC.B 10
X DC.B 0
X DS.W 0
Xend\@
X ENDC
X ENDM
SHAR_EOF
if test 853 -ne "`wc -c < 'messages.i'`"
then
echo shar: error transmitting "'messages.i'" '(should have been 853 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mydev.i'" '(4411 characters)'
if test -f 'mydev.i'
then
echo shar: will not over-write existing file "'mydev.i'"
else
sed 's/^ X//' << \SHAR_EOF > 'mydev.i'
X
X******************************************************************
X* *
X* Copyright (C) 1986, Commodore Amiga Inc. All rights reserved. *
X* Permission granted for non-commercial use * *
X* *
X******************************************************************
X
X
X*****************************************************************
X*
X* mydev.i -- external declarations for skeleton device
X*
X* SOURCE CONTROL
X* ------ -------
X* $Header: ramlib.i,v 31.1 85/10/13 23:12:51 neil Exp $
X*
X* $Locker: neil $
X*
X*****************************************************************
XINFO_LEVEL EQU 0 ; Specify amount of debugging info desired
X*INTRRUPT SET 1 ; Remove "*" to enable fake interrupt code
X
X; stack size and priority for the process we will create
XMYPROCSTACKSIZE EQU $800
XMYPROCPRI EQU 0
X
XSECTOR EQU 512 ; # bytes per sector
XSECSHIFT EQU 9 ; Shift count to convert byte # to sector #
XRAMSIZE EQU 512*200 ; Use this much RAM per unit
XIAMPULLING EQU 7 ; "I am pulling the interrupt" bit of INTCRL1
XINTENABLE EQU 4 ; "Interrupt Enable" bit of INTCRL2
XINTCTRL1 EQU $40 ; Interrupt control register offset on board
XINTCTRL2 EQU $42 ; Interrupt control register offset on board
XINTACK EQU $50 ; My board's interrupt reset address
X;-----------------------------------------------------------------------
X;
X; device command definitions
X;
X;-----------------------------------------------------------------------
X
X DEVINIT
X DEVCMD CMD_MOTOR ; control the disk's motor (NO-OP)
X DEVCMD CMD_SEEK ; explicit seek (NO-OP)
X DEVCMD CMD_FORMAT ; format disk - equated to WRITE for RAMDISK
X DEVCMD CMD_REMOVE ; notify when disk changes (NO-OP)
X DEVCMD CMD_CHANGENUM ; number of disk changes (always 0)
X DEVCMD CMD_CHANGESTATE ; is there a disk in the drive? (always TRUE)
X DEVCMD CMD_PROTSTATUS ; is the disk write protected? (always FALSE)
X DEVCMD CMD_RAWREAD ; Not supported
X DEVCMD CMD_RAWWRITE ; Not supported
X DEVCMD CMD_GETDRIVETYPE; Get drive type
X DEVCMD CMD_GETNUMTRACKS; Get number of tracks
X DEVCMD CMD_ADDCHANGEINT; Add disk change interrupt (NO-OP)
X DEVCMD CMD_REMCHANGEINT; Remove disk change interrupt ( NO-OP)
X DEVCMD MYDEV_END ; place marker -- first illegal command #
X
X;-----------------------------------------------------------------------
X;
X; Layout of parameter packet for MakeDosNode
X;
X;-----------------------------------------------------------------------
X
X STRUCTURE MkDosNodePkt,0
X APTR mdn_dosName ; Pointer to DOS file handler name
X APTR mdn_execName ; Pointer to device driver name
X ULONG mdn_unit ; Unit number
X ULONG mdn_flags ; OpenDevice flags
X ULONG mdn_tableSize ; Environment size
X ULONG mdn_sizeBlock ; # longwords in a block
X ULONG mdn_secOrg ; sector origin -- unused
X ULONG mdn_numHeads ; number of surfaces
X ULONG mdn_secsPerBlk ; secs per logical block -- unused
X ULONG mdn_blkTrack ; secs per track
X ULONG mdn_resBlks ; reserved blocks -- MUST be at least 1!
X ULONG mdn_prefac ; unused
X ULONG mdn_interleave ; interleave
X ULONG mdn_lowCyl ; lower cylinder
X ULONG mdn_upperCyl ; upper cylinder
X ULONG mdn_numBuffers ; number of buffers
X ULONG mdn_memBufType ; Type of memory for AmigaDOS buffers
X STRUCT mdn_dName,5 ; DOS file handler name "RAM0"
X LABEL mdn_Sizeof ; Size of this structure
X
X;-----------------------------------------------------------------------
X;
X; device data structures
X;
X;-----------------------------------------------------------------------
X
X; maximum number of units in this device
XMD_NUMUNITS EQU 4
X
X STRUCTURE MyDev,LIB_SIZE
X ULONG md_SysLib
X ULONG md_SegList
X ULONG md_Base ; Base address of this device's expansion board
X UBYTE md_Flags
X UBYTE md_pad
X STRUCT md_Units,MD_NUMUNITS*4
X LABEL MyDev_Sizeof
X
X STRUCTURE MyDevMsg,MN_SIZE
X APTR mdm_Device
X APTR mdm_Unit
X LABEL MyDevMsg_Sizeof
X
X STRUCTURE MyDevUnit,UNIT_SIZE
X UBYTE mdu_UnitNum
X UBYTE mdu_SigBit ; Signal bit allocated for interrupts
X APTR mdu_Device
X STRUCT mdu_stack,MYPROCSTACKSIZE
X STRUCT mdu_is,IS_SIZE ; Interrupt structure
X STRUCT mdu_tcb,TC_SIZE ; TCB for disk task
X STRUCT mdu_Msg,MyDevMsg_Sizeof
X ULONG mdu_SigMask ; Signal these bits on interrupt
X STRUCT mdu_RAM,RAMSIZE ; RAM used to simulate disk
X LABEL MyDevUnit_Sizeof
X
X ;------ state bit for unit stopped
X BITDEF MDU,STOPPED,2
X
XMYDEVNAME MACRO
X DC.B 'mydev.device',0
X ENDM
X
SHAR_EOF
if test 4411 -ne "`wc -c < 'mydev.i'`"
then
echo shar: error transmitting "'mydev.i'" '(should have been 4411 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mydev.asm'" '(30251 characters)'
if test -f 'mydev.asm'
then
echo shar: will not over-write existing file "'mydev.asm'"
else
sed 's/^ X//' << \SHAR_EOF > 'mydev.asm'
X
X*************************************************************************
X* *
X* Copyright (C) 1986, Commodore Amiga Inc. All rights reserved. *
X* Permission granted for non-commercial use * *
X* *
X*************************************************************************
X
X
X*************************************************************************
X*
X* mydev.asm -- Skeleton device code. Modified by Lee Erickson to be a
X* simple disk device, using RAM to simulate a disk.
X* 10/7/86
X*
X************************************************************************/
X SECTION section
X
X NOLIST
X include "exec/types.i"
X include "exec/nodes.i"
X include "exec/lists.i"
X include "exec/libraries.i"
X include "exec/devices.i"
X include "exec/io.i"
X include "exec/alerts.i"
X include "exec/initializers.i"
X include "exec/memory.i"
X include "exec/resident.i"
X include "exec/ables.i"
X include "exec/errors.i"
X include "exec/tasks.i"
X include 'libraries/expansion.i'
X include 'libraries/configvars.i'
X include 'libraries/configregs.i'
X
X include "asmsupp.i"
X include "messages.i"
X
X include "mydev.i"
X
X LIST
X
X ;------ These don't have to be external, but it helps some
X ;------ debuggers to have them globally visible
X XDEF Init
X XDEF Open
X XDEF Close
X XDEF Expunge
X XDEF Null
X XDEF myName
X XDEF BeginIO
X XDEF AbortIO
X
X XREF _AbsExecBase
X
X XLIB AddIntServer
X XLIB RemIntServer
X XLIB Debug
X XLIB InitStruct
X XLIB OpenLibrary
X XLIB CloseLibrary
X XLIB Alert
X XLIB FreeMem
X XLIB Remove
X XLIB AllocMem
X XLIB AddTask
X XLIB PutMsg
X XLIB RemTask
X XLIB ReplyMsg
X XLIB Signal
X XLIB GetMsg
X XLIB Wait
X XLIB WaitPort
X XLIB AllocSignal
X XLIB SetTaskPri
X XLIB GetCurrentBinding ; Get list of boards for this driver
X XLIB MakeDosNode
X XLIB AddDosNode
X
X INT_ABLES
X
X
X ; The first executable location. This should return an error
X ; in case someone tried to run you as a program (instead of
X ; loading you as a library).
XFirstAddress:
X CLEAR d0
X rts
X
X;-----------------------------------------------------------------------
X; A romtag structure. Both "exec" and "ramlib" look for
X; this structure to discover magic constants about you
X; (such as where to start running you from...).
X;-----------------------------------------------------------------------
X
X ; Most people will not need a priority and should leave it at zero.
X ; the RT_PRI field is used for configuring the roms. Use "mods" from
X ; wack to look at the other romtags in the system
XMYPRI EQU 0
X
XinitDDescrip:
X ;STRUCTURE RT,0
X DC.W RTC_MATCHWORD ; UWORD RT_MATCHWORD
X DC.L initDDescrip ; APTR RT_MATCHTAG
X DC.L EndCode ; APTR RT_ENDSKIP
X DC.B RTF_AUTOINIT ; UBYTE RT_FLAGS
X DC.B VERSION ; UBYTE RT_VERSION
X DC.B NT_DEVICE ; UBYTE RT_TYPE
X DC.B MYPRI ; BYTE RT_PRI
X DC.L myName ; APTR RT_NAME
X DC.L idString ; APTR RT_IDSTRING
X DC.L Init ; APTR RT_INIT
X ; LABEL RT_SIZE
X
X
X ; this is the name that the device will have
XsubSysName:
XmyName: MYDEVNAME
X
XExLibName EXPANSIONNAME ; Expansion Library Name
X
X ; a major version number.
XVERSION: EQU 1
X
X ; A particular revision. This should uniquely identify the bits in the
X ; device. I use a script that advances the revision number each time
X ; I recompile. That way there is never a question of which device
X ; that really is.
XREVISION: EQU 17
X
X ; this is an identifier tag to help in supporting the device
X ; format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
XidString: dc.b 'mydev 1.0 (31 Oct 1985)',13,10,0
X
X ; force word allignment
X ds.w 0
X
X
X ; The romtag specified that we were "RTF_AUTOINIT". This means
X ; that the RT_INIT structure member points to one of these
X ; tables below. If the AUTOINIT bit was not set then RT_INIT
X ; would point to a routine to run.
X
XInit:
X DC.L MyDev_Sizeof ; data space size
X DC.L funcTable ; pointer to function initializers
X DC.L dataTable ; pointer to data initializers
X DC.L initRoutine ; routine to run
X
X
XfuncTable:
X
X ;------ standard system routines
X dc.l Open
X dc.l Close
X dc.l Expunge
X dc.l Null
X
X ;------ my device definitions
X dc.l BeginIO
X dc.l AbortIO
X
X ;------ function table end marker
X dc.l -1
X
X
X ; The data table initializes static data structures.
X ; The format is specified in exec/InitStruct routine's
X ; manual pages. The INITBYTE/INITWORD/INITLONG routines
X ; are in the file "exec/initializers.i". The first argument
X ; is the offset from the device base for this byte/word/long.
X ; The second argument is the value to put in that cell.
X ; The table is null terminated
XdataTable:
X INITBYTE LH_TYPE,NT_DEVICE
X INITLONG LN_NAME,myName
X INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
X INITWORD LIB_VERSION,VERSION
X INITWORD LIB_REVISION,REVISION
X INITLONG LIB_IDSTRING,idString
X DC.L 0
X
X
X ; This routine gets called after the device has been allocated.
X ; The device pointer is in D0. The segment list is in a0.
X ; If it returns non-zero then the device will be linked into
X ; the device list.
XinitRoutine:
X
X; Register Usage
X; ==============
X; a3 -- Points to tempory RAM
X; a4 -- Expansion library base
X; a5 -- device pointer
X; a6 -- Exec base
X;
X;----------------------------------------------------------------------
X ;------ get the device pointer into a convenient A register
X PUTMSG 30,<'%s/Init: called'>
X movem.l d1-d7/a0-a5,-(sp) ; Preserve ALL modified registers
X move.l d0,a5
X
X ;------ save a pointer to exec
X move.l a6,md_SysLib(a5)
X
X ;------ save a pointer to our loaded code
X move.l a0,md_SegList(a5)
X
X lea.l ExLibName,A1 ; Get expansion lib. name
X moveq.l #0,D0
X CALLSYS OpenLibrary ; Open the expansion library
X tst.l D0
X bne.s init_OpSuccess
X
Xinit_OpFail:
X ALERT AG_OpenLib!AO_ExpansionLib
X
Xinit_OpSuccess:
X move.l D0,A4
X
X lea md_Base(A5),A0 ; Get the Current Bindings
X moveq #4,D0 ; Just get address (length = 4 bytes)
X LINKLIB _LVOGetCurrentBinding,A4
X move.l md_Base(A5),D0 ; Get start of list
X tst.l D0 ; If controller not found
X beq Init_End ; Exit and unload driver
X move.l D0,A0 ; Get config structure address
X move.l cd_BoardAddr(A0),md_Base(A5); Save board base address
X bclr.b #CDB_CONFIGME,cd_Flags(A0); Mark board as configured
X
XInit_End:
X;----------------------------------------------------------------------
X;
X; Here we build a packet describing the characteristics of our disk to
X; pass to AmigaDOS. This serves the same purpose as a "mount" command
X; of this device would. For disks, it might be useful to actually
X; get this information right from the disk itself. Just as mount,
X; it could be for multiple partitions on the single physical device.
X; For this example, we will simply hard code the appropriate parameters.
X;
X;-----------------------------------------------------------------------
X
X;!!!! Normally you would only do this if your card was successfully configured
X;!!!! up above. For the demo, it will always be done.
X
X ;------ Allocate tempory RAM to build MakeDosNode parameter packet
X move.l #MEMF_CLEAR!MEMF_PUBLIC,d1
X move.l #mdn_Sizeof,d0 ; Enough room for our parameter packet
X CALLSYS AllocMem
X move.l d0,a3
X
X ;----- Use InitStruct to initialize the constant portion of packet
X move.l d0,a2 ; Point to memory to initialize
X moveq.l #0,d0 ; Don't need to re-zero it
X lea.l mdn_Init(pc),A1
X CALLSYS InitStruct
X
X lea mdn_dName(a3),a0 ; Get addr of Device name
X move.l a0,mdn_dosName(a3) ; and save in environment
X
X moveq #1,d6 ; Now tell AmigaDOS about all units
XUloop:
X move.b d6,d0 ; Get unit number
X add.b #$2F,d0 ; Make ASCII, minus 1
X move.b d0,mdn_dName+3(a3) ; and store in name
X move.l d6,mdn_unit(a3) ; Store unit # in environment
X
X move.l a3,a0
X LINKLIB _LVOMakeDosNode,a4 ; Build AmigaDOS structures
X move.l d0,a0 ; Get deviceNode address
X moveq.l #0,d0 ; Set device priority to 0
X moveq.l #0,d1
X* moveq.l #ADNF_STARTPROC,d1 ; Have handler started
X LINKLIB _LVOAddDosNode,a4
X
X addq #1,d6 ; Bump unit number
X cmp.b #MD_NUMUNITS,d6
X ble.s Uloop ; Loop until all units installed
X
X move.l a3,a1 ; Return RAM to system
X move.l #mdn_Sizeof,d0
X CALLSYS FreeMem
X
X move.l a4,a1 ; Now close expansion library
X CALLSYS CloseLibrary
X ;
X ; You would normally set d0 to a NULL if your initialization failed,
X ; but I'm not doing that for this demo, since it is unlikely
X ; you actually have a board with this particular manufacturer ID
X ; installed when running this demo.
X ;
X move.l a5,d0
X movem.l (sp)+,d1-d7/a0-a5
X
X rts
X
X;----------------------------------------------------------------------
X;
X; here begins the system interface commands. When the user calls
X; OpenLibrary/CloseLibrary/RemoveLibrary, this eventually gets translated
X; into a call to the following routines (Open/Close/Expunge). Exec
X; has already put our device pointer in a6 for us. Exec has turned
X; off task switching while in these routines (via Forbid/Permit), so
X; we should not take too long in them.
X;
X;----------------------------------------------------------------------
X
X
X ; Open sets the IO_ERROR field on an error. If it was successfull,
X ; we should set up the IO_UNIT field.
X
XOpen: ; ( device:a6, iob:a1, unitnum:d0, flags:d1 )
X PUTMSG 30,<'%s/Open: called'>
X movem.l d2/a2/a3/a4,-(sp)
X
X move.l a1,a2 ; save the iob
X
X ;------ see if the unit number is in range
X subq #1,d0 ; Unit ZERO isn't allowed
X cmp.l #MD_NUMUNITS,d0
X bcc.s Open_Error ; unit number out of range
X
X ;------ see if the unit is already initialized
X move.l d0,d2 ; save unit number
X lsl.l #2,d0
X lea.l md_Units(a6,d0.l),a4
X move.l (a4),d0
X bne.s Open_UnitOK
X
X ;------ try and conjure up a unit
X bsr InitUnit
X
X ;------ see if it initialized OK
X move.l (a4),d0
X beq.s Open_Error
X
XOpen_UnitOK:
X move.l d0,a3 ; unit pointer in a3
X
X move.l d0,IO_UNIT(a2)
X
X ;------ mark us as having another opener
X addq.w #1,LIB_OPENCNT(a6)
X addq.w #1,UNIT_OPENCNT(a3)
X
X ;------ prevent delayed expunges
X bclr #LIBB_DELEXP,md_Flags(a6)
X moveq.l #0,d0
X
XOpen_End:
X
X movem.l (sp)+,d2/a2/a3/a4
X rts
X
XOpen_Error:
X move.b #IOERR_OPENFAIL,IO_ERROR(a2)
X move.b #IOERR_OPENFAIL,d0
X bra.s Open_End
X
X ; There are two different things that might be returned from
X ; the Close routine. If the device is no longer open and
X ; there is a delayed expunge then Close should return the
X ; segment list (as given to Init). Otherwise close should
X ; return NULL.
X
XClose: ; ( device:a6, iob:a1 )
X movem.l d1/a2-a3,-(sp)
X PUTMSG 30,<'%s/Close: called'>
X
X move.l a1,a2
X
X move.l IO_UNIT(a2),a3
X
X ;------ make sure the iob is not used again
X moveq.l #-1,d0
X move.l d0,IO_UNIT(a2)
X move.l d0,IO_DEVICE(a2)
X
X ;------ see if the unit is still in use
X subq.w #1,UNIT_OPENCNT(a3)
X
X;!!!!!! Since this example is a RAM disk (and we don't want the contents to
X;!!!!!! disappear between opens, ExpungeUnit will be skipped here. It would
X;!!!!!! be used for drivers of "real" devices
X;!!!!!! bne.s Close_Device
X;!!!!!! bsr ExpungeUnit
X
XClose_Device:
X ;------ mark us as having one fewer openers
X moveq.l #0,d0
X subq.w #1,LIB_OPENCNT(a6)
X
X ;------ see if there is anyone left with us open
X bne.s Close_End
X
X ;------ see if we have a delayed expunge pending
X btst #LIBB_DELEXP,md_Flags(a6)
X beq.s Close_End
X
X ;------ do the expunge
X bsr Expunge
X
XClose_End:
X movem.l (sp)+,d1/a2-a3
X rts
X
X
X ; There are two different things that might be returned from
X ; the Expunge routine. If the device is no longer open
X ; then Expunge should return the segment list (as given to
X ; Init). Otherwise Expunge should set the delayed expunge
X ; flag and return NULL.
X ;
X ; One other important note: because Expunge is called from
X ; the memory allocator, it may NEVER Wait() or otherwise
X ; take long time to complete.
X
XExpunge: ; ( device: a6 )
X PUTMSG 30,<'%s/Expunge: called'>
X
X movem.l d1/d2/a5/a6,-(sp) ; Best to save ALL modified registers
X move.l a6,a5
X move.l md_SysLib(a5),a6
X
X ;------ see if anyone has us open
X tst.w LIB_OPENCNT(a5)
X;!!!!! The following line is commented out for this RAM disk demo, since
X;!!!!! we don't want the RAM to be freed after FORMAT, for example.
X; beq 1$
X
X ;------ it is still open. set the delayed expunge flag
X bset #LIBB_DELEXP,md_Flags(a5)
X CLEAR d0
X bra.s Expunge_End
X
X1$:
X ;------ go ahead and get rid of us. Store our seglist in d2
X move.l md_SegList(a5),d2
X
X ;------ unlink from device list
X move.l a5,a1
X CALLSYS Remove
X
X ;
X ; device specific closings here...
X ;
X
X ;------ free our memory
X CLEAR d0
X CLEAR d1
X move.l a5,a1
X move.w LIB_NEGSIZE(a5),d1
X
X sub.w d1,a1
X add.w LIB_POSSIZE(a5),d0
X add.l d1,d0
X
X CALLSYS FreeMem
X
X ;------ set up our return value
X move.l d2,d0
X
XExpunge_End:
X movem.l (sp)+,d1/d2/a5/a6
X rts
X
X
XNull:
X PUTMSG 30,<'%s/Null: called'>
X CLEAR d0
X rts
X
X
XInitUnit: ; ( d2:unit number, a3:scratch, a6:devptr )
X PUTMSG 30,<'%s/InitUnit: called'>
X movem.l d2-d4/a2,-(sp)
X
X ;------ allocate unit memory
X move.l #MyDevUnit_Sizeof,d0
X move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
X LINKSYS AllocMem,md_SysLib(a6)
X
X tst.l d0
X beq InitUnit_End
X
X move.l d0,a3
X move.b d2,mdu_UnitNum(a3) ; initialize unit number
X move.l a6,mdu_Device(a3) ; initialize device pointer
X
X ;------ start up the unit process. We do a trick here --
X ;------ we set his message port to PA_IGNORE until the
X ;------ new process has a change to set it up.
X ;------ We cannot go to sleep here: it would be very nasty
X ;------ if someone else tried to open the unit
X ;------ (exec's OpenDevice has done a Forbid() for us --
X ;------ we depend on this to become single threaded).
X
X ;------ Initialize the stack information
X lea mdu_stack(a3),a0 ; Low end of stack
X move.l a0,mdu_tcb+TC_SPLOWER(a3)
X lea MYPROCSTACKSIZE(a0),a0 ; High end of stack
X move.l a0,mdu_tcb+TC_SPUPPER(a3)
X move.l a3,-(A0) ; argument -- unit ptr
X move.l a0,mdu_tcb+TC_SPREG(a3)
X ;------ initialize the unit's list
X lea MP_MSGLIST(a3),a0
X NEWLIST a0
X lea mdu_tcb(a3),a0
X move.l a0,MP_SIGTASK(a3)
X moveq.l #0,d0 ; Don't need to re-zero it
X move.l a3,a2 ; InitStruct is initializing the UNIT
X lea.l mdu_Init,A1
X LINKSYS InitStruct,md_SysLib(a6)
X
X move.l a3,mdu_is+IS_DATA(a3) ; Pass int. server unit addr.
X
X; Startup the task
X lea mdu_tcb(a3),a1
X lea Proc_Begin(PC),a2
X move.l a3,-(sp) ; Preserve UNIT pointer
X lea -1,a3 ; generate address error
X ; if task ever "returns"
X CLEAR d0
X LINKSYS AddTask,md_SysLib(a6)
X move.l (sp)+,a3 ; restore UNIT pointer
X
X ;------ mark us as ready to go
X move.l d2,d0 ; unit number
X lsl.l #2,d0
X move.l a3,md_Units(a6,d0.l) ; set unit table
X
X
XInitUnit_End:
X movem.l (sp)+,d2-d4/a2
X rts
X
X ;------ got an error. free the unit structure that we allocated.
XInitUnit_FreeUnit:
X bsr FreeUnit
X bra.s InitUnit_End
X
XFreeUnit: ; ( a3:unitptr, a6:deviceptr )
X move.l a3,a1
X move.l #MyDevUnit_Sizeof,d0
X LINKSYS FreeMem,md_SysLib(a6)
X rts
X
X
XExpungeUnit: ; ( a3:unitptr, a6:deviceptr )
X PUTMSG 30,<'%s/ExpungeUnit: called'>
X move.l d2,-(sp)
X
X;
X; If you can expunge you unit, and each unit has it's own interrups,
X; you must remember to remove its interrupt server
X;
X
X IFD INTRRUPT
X lea.l mdu_is(a3),a1 ; Point to interrupt structure
X moveq #3,d0 ; Portia interrupt bit 3
X LINKSYS RemIntServer,md_SysLib(a6) ;Now remove the interrupt server
X ENDC
X
X ;------ get rid of the unit's task. We know this is safe
X ;------ because the unit has an open count of zero, so it
X ;------ is 'guaranteed' not in use.
X lea mdu_tcb(a3),a1
X LINKSYS RemTask,md_SysLib(a6)
X
X ;------ save the unit number
X CLEAR d2
X move.b mdu_UnitNum(a3),d2
X
X ;------ free the unit structure.
X bsr FreeUnit
X
X ;------ clear out the unit vector in the device
X lsl.l #2,d2
X clr.l md_Units(a6,d2.l)
X
X move.l (sp)+,d2
X
X rts
X
X;----------------------------------------------------------------------
X;
X; here begins the device specific functions
X;
X;----------------------------------------------------------------------
X
X; cmdtable is used to look up the address of a routine that will
X; implement the device command.
Xcmdtable:
X DC.L Invalid ; $00000001
X DC.L MyReset ; $00000002
X DC.L RdWrt ; $00000004 Common routine for read/write
X DC.L RdWrt ; $00000008
X DC.L Update ; $00000010
X DC.L Clear ; $00000020
X DC.L MyStop ; $00000040
X DC.L Start ; $00000080
X DC.L Flush ; $00000100
X DC.L Motor ; $00000200 motor (NO-OP)
X DC.L Seek ; $00000400 seek (NO-OP)
X DC.L RdWrt ; $00000800 format -> WRITE for RAMDISK
X DC.L MyRemove ; $00001000 remove (NO-OP)
X DC.L ChangeNum ; $00002000 changenum (Returns 0)
X DC.L ChangeState ; $00004000 changestate (Returns 0)
X DC.L ProtStatus ; $00008000 protstatus (Returns 0)
X DC.L RawRead ; Not supported (INVALID)
X DC.L RawWrite ; Not supported (INVALID)
X DC.L GetDriveType ; Get drive type (Returns 1)
X DC.L GetNumTracks ; Get number of tracks (Returns NUMTRKS)
X DC.L AddChangeInt ; Add disk change interrupt (NO-OP)
X DC.L RemChangeInt ; Remove disk change interrupt ( NO-OP)
Xcmdtable_end:
X
X; this define is used to tell which commands should not be queued
X; command zero is bit zero.
X; The immediate commands are Invalid, Reset, Stop, Start, Flush
XIMMEDIATES EQU $000001c3
X
X; These commands can NEVER be done "immediately" if using interrupts,
X; since they would "wait" for the interrupt forever!
X; Read, Write, Format
XNEVERIMMED EQU $0000080C
X;
X; BeginIO starts all incoming io. The IO is either queued up for the
X; unit task or processed immediately.
X;
X
XBeginIO: ; ( iob: a1, device:a6 )
X PUTMSG 30,<'%s/BeginIO: called'>
X movem.l d1/a0/a3,-(sp)
X
X ;------ bookkeeping
X move.l IO_UNIT(a1),a3
X
X ;------ see if the io command is within range
X move.w IO_COMMAND(a1),d0
X cmp.w #MYDEV_END,d0
X bcc BeginIO_NoCmd
X
X DISABLE a0
X
X ;------ process all immediate commands no matter what
X move.w #IMMEDIATES,d1
X btst d0,d1
X bne.s BeginIO_Immediate
X
X IFD INTRRUPT ; if using interrupts,
X ;------ queue all NEVERIMMED commands no matter what
X move.w #NEVERIMMED,d1
X btst d0,d1
X bne.s BeginIO_QueueMsg
X ENDC
X
X ;------ see if the unit is STOPPED. If so, queue the msg.
X btst #MDUB_STOPPED,UNIT_FLAGS(a3)
X bne.s BeginIO_QueueMsg
X
X ;------ this is not an immediate command. see if the device is
X ;------ busy.
X bset #UNITB_ACTIVE,UNIT_FLAGS(a3)
X beq.s BeginIO_Immediate
X
X ;------ we need to queue the device. mark us as needing
X ;------ task attention. Clear the quick flag
XBeginIO_QueueMsg:
X BSET #UNITB_INTASK,UNIT_FLAGS(a3)
X bclr #IOB_QUICK,IO_FLAGS(a1)
X
X ENABLE a0
X
X move.l a3,a0
X LINKSYS PutMsg,md_SysLib(a6)
X bra BeginIO_End
X
XBeginIO_Immediate:
X ENABLE a0
X
X bsr PerformIO
X
XBeginIO_End:
X movem.l (sp)+,d1/a0/a3
X rts
X
XBeginIO_NoCmd:
X move.b #IOERR_NOCMD,IO_ERROR(a1)
X bra.s BeginIO_End
X
X
X;
X; PerformIO actually dispatches an io request. It expects a3 to already
X; have the unit pointer in it. a6 has the device pointer (as always).
X; a1 has the io request. Bounds checking has already been done on
X; the io request.
X;
X
XPerformIO: ; ( iob:a1, unitptr:a3, devptr:a6 )
X PUTMSG 30,<'%s/PerforIO: called'>
X move.l a2,-(sp)
X move.l a1,a2
X
X clr.b IO_ERROR(A2) ; No error so far
X move.w IO_COMMAND(a2),d0
X lsl #2,d0 ; Multiply by 4 to get table offset
X lea cmdtable(pc),a0
X move.l 0(a0,d0.w),a0
X
X jsr (a0)
X
X move.l (sp)+,a2
X rts
X
X;
X; TermIO sends the IO request back to the user. It knows not to mark
X; the device as inactive if this was an immediate request or if the
X; request was started from the server task.
X;
X
XTermIO: ; ( iob:a1, unitptr:a3, devptr:a6 )
X PUTMSG 30,<'%s/TermIO: called'>
X move.w IO_COMMAND(a1),d0
X move.w #IMMEDIATES,d1
X btst d0,d1
X bne.s TermIO_Immediate
X
X ;------ we may need to turn the active bit off.
X btst #UNITB_INTASK,UNIT_FLAGS(a3)
X bne.s TermIO_Immediate
X
X ;------ the task does not have more work to do
X bclr #UNITB_ACTIVE,UNIT_FLAGS(a3)
X
XTermIO_Immediate:
X ;------ if the quick bit is still set then we don't need to reply
X ;------ msg -- just return to the user.
X btst #IOB_QUICK,IO_FLAGS(a1)
X bne.s TermIO_End
X
X LINKSYS ReplyMsg,md_SysLib(a6)
X
XTermIO_End:
X rts
X
X
XAbortIO: ; ( iob: a1, device:a6 )
X;----------------------------------------------------------------------
X;
X; here begins the functions that implement the device commands
X; all functions are called with:
X; a1 -- a pointer to the io request block
X; a2 -- another pointer to the iob
X; a3 -- a pointer to the unit
X; a6 -- a pointer to the device
X;
X; Commands that conflict with 68000 instructions have a "My" prepended
X; to them.
X;----------------------------------------------------------------------
X
XRawRead: ; 10 Not supported (INVALID)
XRawWrite: ; 11 Not supported (INVALID)
XInvalid:
X move.b #IOERR_NOCMD,IO_ERROR(a1)
X bsr TermIO
X rts
X
XMyReset:
XAddChangeInt:
XRemChangeInt:
XMyRemove:
XSeek:
XMotor:
XChangeNum:
XChangeState:
XProtStatus:
X clr.l IO_ACTUAL(a1) ; Indicate drive isn't protected
X bsr TermIO
X rts
X
XGetDriveType:
X move.l #1,IO_ACTUAL(a1) ; Make it look like 3.5"
X bsr TermIO
X rts
X
XGetNumTracks:
X move.l #RAMSIZE/5120,IO_ACTUAL(a1) ; Number of 10 sector tracks
X bsr TermIO
X rts
X
XRdWrt:
X movem.l a2/a3,-(sp)
X clr.l IO_ACTUAL(a1) ; Initially, no data moved
X move.l IO_DATA(a1),a0
X move.l IO_LENGTH(a1),d0
X
X ;------ deal with zero length I/O
X beq.s RdWrt_end
X
X
X move.l IO_UNIT(a1),a3 ; Get unit pointer
X move.l a1,a2
X
X* check operation for legality
X
X move.l IO_OFFSET(a2),d0
X move.l d0,d1
X
X* check for being an even sector boundary
X and.l #SECTOR-1,d1
X bne IO_Err
X
X* check for IO within disc range
X add.l IO_LENGTH(a2),d0
X cmp.l #RAMSIZE,d0
X bgt IO_Err
X
X* We've gotten this far, it must be a valid request.
X
X IFD INTRRUPT
X move.l mdu_SigMask(a3),d0 ; Get signals to wait for
X LINKSYS Wait,md_SysLib(a6) ; Wait for interrrupt before proceeding
X ENDC
X
X move.l IO_OFFSET(a2),d0
X lea mdu_RAM(a3),a0 ; Point to RAMDISK "sector" for I/O
X add.l d0,a0 ; Can't use index, "out of range"
X move.l IO_LENGTH(a2),d0
X move.l d0,IO_ACTUAL(a2) ; Indicate we've moved all bytes
X subq.w #1,d0 ; Adjust byte count for DBRA loop
X move.l IO_DATA(a2),a1 ; Point to data buffer
X
X move.w IO_COMMAND(a2),d1 ; Now go to correct loop for
X cmp.b #CMD_READ,d1 ; Read or Write commands
X BEQ.S RdLp
X
XWrtLp: move.b (a1)+,(a0)+ ; Copy a byte
X dbra d0,WrtLp ; Move all requested bytes
X bra.s RdWrt_end
X
XRdLp: move.b (a0)+,(a1)+ ; Copy a byte
X dbra d0,RdLp ; Move all requested bytes
X bra.s RdWrt_end
X
XIO_Err:
X move.b #IOERR_BADLENGTH,IO_ERROR(a1)
X
XRdWrt_end:
X move.l a2,a1
X bsr TermIO
X movem.l (sp)+,a2/a3
X rts
X
X;
X; Update and Clear are internal buffering commands. Update forces all
X; io out to its final resting spot, and does not return until this is
X; done. Clear invalidates all internal buffers. Since this device
X; has no internal buffers, these commands do not apply.
X;
X
XUpdate:
X PUTMSG 30,<'%s/Update: called'>
X bra Invalid
XClear:
X PUTMSG 30,<'%s/Clear: called'>
X bra Invalid
X
X;
X; the Stop command stop all future io requests from being
X; processed until a Start command is received. The Stop
X; command is NOT stackable: e.g. no matter how many stops
X; have been issued, it only takes one Start to restart
X; processing.
X;
X
XMyStop:
X PUTMSG 30,<'%s/MyStop: called'>
X bset #MDUB_STOPPED,UNIT_FLAGS(a3)
X
X bsr TermIO
X rts
X
XStart:
X PUTMSG 30,<'%s/Start: called'>
X bsr InternalStart
X
X move.l a2,a1
X bsr TermIO
X
X rts
X
XInternalStart:
X ;------ turn processing back on
X bclr #MDUB_STOPPED,UNIT_FLAGS(a3)
X
X ;------ kick the task to start it moving
X move.l a3,a1
X CLEAR d0
X move.l MP_SIGBIT(a3),d1
X bset d1,d0
X LINKSYS Signal,md_SysLib(a3)
X
X rts
X
X;
X; Flush pulls all io requests off the queue and sends them back.
X; We must be careful not to destroy work in progress, and also
X; that we do not let some io requests slip by.
X;
X; Some funny magic goes on with the STOPPED bit in here. Stop is
X; defined as not being reentrant. We therefore save the old state
X; of the bit and then restore it later. This keeps us from
X; needing to DISABLE in flush. It also fails miserably if someone
X; does a start in the middle of a flush.
X;
X
XFlush:
X PUTMSG 30,<'%s/Flush: called'>
X movem.l d2/a6,-(sp)
X
X move.l md_SysLib(a6),a6
X
X bset #MDUB_STOPPED,UNIT_FLAGS(a3)
X sne d2
X
XFlush_Loop:
X move.l a3,a0
X CALLSYS GetMsg
X
X tst.l d0
X beq.s Flush_End
X
X move.l d0,a1
X move.b #IOERR_ABORTED,IO_ERROR(a1)
X CALLSYS ReplyMsg
X
X bra.s Flush_Loop
X
XFlush_End:
X
X move.l d2,d0
X movem.l (sp)+,d2/a6
X
X tst.b d0
X beq.s 1$
X
X bsr InternalStart
X1$:
X
X move.l a2,a1
X bsr TermIO
X
X rts
X
X;
X; Foo and Bar are two device specific commands that are provided just
X; to show you how to add your own commands. The currently return that
X; no work was done.
X;
X
XFoo:
XBar:
X CLEAR d0
X move.l d0,IO_ACTUAL(a1)
X
X bsr TermIO
X rts
X
X;----------------------------------------------------------------------
X;
X; here begins the process related routines
X;
X; A Process is provided so that queued requests may be processed at
X; a later time.
X;
X;
X; Register Usage
X; ==============
X; a3 -- unit pointer
X; a6 -- syslib pointer
X; a5 -- device pointer
X; a4 -- task (NOT process) pointer
X; d7 -- wait mask
X;
X;----------------------------------------------------------------------
X
X; some dos magic. A process is started at the first executable address
X; after a segment list. We hand craft a segment list here. See the
X; the DOS technical reference if you really need to know more about this.
X
X cnop 0,4 ; long word allign
X DC.L 16 ; segment length -- any number will do
Xmyproc_seglist:
X DC.L 0 ; pointer to next segment
X
X; the next instruction after the segment list is the first executable address
X
XProc_Begin:
X
X move.l _AbsExecBase,a6
X
X ;------ Grab the argument
X move.l 4(sp),a3 ; Unit pointer
X
X move.l mdu_Device(a3),a5 ; Point to device structure
X
X IFD INTRRUPT
X ;------ Allocate a signal for "I/O Complete" interrupts
X moveq #-1,d0 ; -1 is any signal at all
X CALLSYS AllocSignal
X move.b d0,mdu_SigBit(A3) ; Save in unit structure
X
X moveq #0,d7 ; Convert bit number signal mask
X bset d0,d7
X move.l d7,mdu_SigMask(A3) ; Save in unit structure
X
X lea.l mdu_is(a3),a1 ; Point to interrupt structure
X moveq #3,d0 ; Portia interrupt bit 3
X CALLSYS AddIntServer ; Now install the server
X
X move.l md_Base(a5),a0 ; Get board base address
X* bset.b #INTENABLE,INTCTRL2(a0) ; Enable interrupts
X ENDC
X
X ;------ Allocate the right signal
X
X moveq #-1,d0 ; -1 is any signal at all
X CALLSYS AllocSignal
X
X move.b d0,MP_SIGBIT(a3)
X move.b #PA_SIGNAL,MP_FLAGS(a3)
X
X ;------ change the bit number into a mask, and save in d7
X
X moveq #0,d7
X bset d0,d7
X
X ;------
X ;------ OK, kids, we are done with initialization. We now
X ;------ can start the main loop of the driver. It goes
X ;------ like this. Because we had the port marked PA_IGNORE
X ;------ for a while (in InitUnit) we jump to the getmsg
X ;------ code on entry.
X ;------
X ;------ wait for a message
X ;------ lock the device
X ;------ get a message. if no message unlock device and loop
X ;------ dispatch the message
X ;------ loop back to get a message
X ;------
X
X bra.s Proc_CheckStatus
X
X ;------ main loop: wait for a new message
XProc_MainLoop:
X move.l d7,d0
X CALLSYS Wait
X
XProc_CheckStatus:
X ;------ see if we are stopped
X btst #MDUB_STOPPED,UNIT_FLAGS(a3)
X bne.s Proc_MainLoop ; device is stopped
X
X ;------ lock the device
X bset #UNITB_ACTIVE,UNIT_FLAGS(a3)
X bne.s Proc_MainLoop ; device in use
X
X ;------ get the next request
XProc_NextMessage:
X move.l a3,a0
X CALLSYS GetMsg
X tst.l d0
X beq.s Proc_Unlock ; no message?
X
X ;------ do this request
X move.l d0,a1
X exg a5,a6 ; put device ptr in right place
X bsr PerformIO
X exg a5,a6 ; get syslib back in a6
X
X bra.s Proc_NextMessage
X
X ;------ no more messages. back ourselves out.
XProc_Unlock:
X and.b #$ff&(~(UNITF_ACTIVE!UNITF_INTASK)),UNIT_FLAGS(a3)
X bra Proc_MainLoop
X
X;
X; Here is a dummy interrupt handler, with some crucial components commented
X; out. If the IFD INTRRUPT is enabled, this code will cause the device to
X; wait for a level two interrupt before it will process each request
X; (pressing a key on the keyboard will do it). This code is normally
X; disabled, and must fake or omit certain operations since there isn't
X; really any hardware for this driver. Similiar code has been used
X; successfully in other, "REAL" device drivers.
X;
X
X IFD INTRRUPT
X; A1 should be pointing to the unit structure upon entry!
X
Xmyintr: move.l mdu_Device(a1),a0 ; Get device pointer
X move.l md_SysLib(a0),a6 ; Get pointer to system
X move.l md_Base(a0),a0 ; point to board base address
X* btst.b #IAMPULLING,INTCTRL1(a0);See if I'm interrupting
X* beq.s myexnm ; if not set, exit, not mine
X* move.b #0,INTACK(a0) ; toggle controller's int2 bit
X
X; ------ signal the task that an interrupt has occured
X
X move.l mdu_SigMask(a1),d0
X lea mdu_tcb(a1),a1
X CALLSYS Signal
X
X;
X; now clear the zero condition code so that
X; the interrupt handler doesn't call the next
X; interrupt server.
X;
X* moveq #1,d0 clear zero flag
X* bra.s myexit now exit
X;
X; this exit point sets the zero condition code
X; so the interrupt handler will try the next server
X; in the interrupt chain
X;
Xmyexnm moveq #0,d0 set zero condition code
X;
Xmyexit rts
X ENDC
X
Xmdu_Init:
X; ------ Initialize the device
X
X INITBYTE MP_FLAGS,PA_IGNORE
X INITBYTE LN_TYPE,NT_DEVICE
X INITLONG LN_NAME,myName
X INITBYTE mdu_Msg+LN_TYPE,NT_MSGPORT;Unit starts with MsgPort
X INITLONG mdu_Msg+LN_NAME,myName
X INITLONG mdu_tcb+LN_NAME,myName
X INITBYTE mdu_tcb+LN_TYPE,NT_TASK
X INITBYTE mdu_tcb+LN_PRI,5
X INITBYTE mdu_is+LN_PRI,4 ; Int priority 4
X IFD INTRRUPT
X INITLONG mdu_is+IS_CODE,myintr ; Interrupt routine addr
X ENDC
X INITLONG mdu_is+LN_NAME,myName
X DC.L 0
X
Xmdn_Init:
X* ;------ Initialize packet for MakeDosNode
X
X INITLONG mdn_execName,myName ; Address of driver name
X INITLONG mdn_tableSize,11 ; # long words in AmigaDOS env.
X INITLONG mdn_dName,$52414d00 ; Store 'RAM' in name
X INITLONG mdn_sizeBlock,128 ; # longwords in a block
X INITLONG mdn_numHeads,1 ; RAM disk has only one "head"
X INITLONG mdn_secsPerBlk,1 ; secs/logical block, must = "1"
X INITLONG mdn_blkTrack,10 ; secs/track (must be reasonable)
X INITLONG mdn_resBlks,1 ; reserved blocks, MUST > 0!
X INITLONG mdn_upperCyl,(RAMSIZE/5120)-1; upper cylinder
X INITLONG mdn_numBuffers,1 ; # AmigaDOS buffers to start
X DC.L 0
X
X;----------------------------------------------------------------------
X; EndCode is a marker that show the end of your code.
X; Make sure it does not span sections nor is before the
X; rom tag in memory! It is ok to put it right after
X; the rom tag -- that way you are always safe. I put
X; it here because it happens to be the "right" thing
X; to do, and I know that it is safe in this case.
X;----------------------------------------------------------------------
XEndCode:
X
X END
SHAR_EOF
if test 30251 -ne "`wc -c < 'mydev.asm'`"
then
echo shar: error transmitting "'mydev.asm'" '(should have been 30251 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'testdev.asm'" '(2021 characters)'
if test -f 'testdev.asm'
then
echo shar: will not over-write existing file "'testdev.asm'"
else
sed 's/^ X//' << \SHAR_EOF > 'testdev.asm'
X
X*************************************************************************
X* *
X* Copyright (C) 1985, Commodore Amiga Inc. All rights reserved. *
X* Permission granted for non-commercial use * *
X* *
X************************************************************************/
X
X
X*************************************************************************
X*
X* testdev.asm -- test the mylib.asm code
X*
X* Source Control
X* ------ -------
X*
X* $Header: amain.asm,v 31.3 85/10/18 19:04:04 neil Exp $
X*
X* $Locker: neil $
X*
X* $Log: amain.asm,v $
X*
X************************************************************************/
X
X INCLUDE 'exec/types.i'
X INCLUDE 'exec/libraries.i'
X INCLUDE 'exec/devices.i'
X INCLUDE 'exec/io.i'
X INCLUDE 'exec/tasks.i'
X INCLUDE 'exec/interrupts.i'
X
X INCLUDE 'asmsupp.i'
X INCLUDE 'mydev.i'
X
X
X
X XDEF _main
X
X XREF _printf
X XREF _AbsExecBase
X XREF _CreatePort
X XREF _DeletePort
X XREF _CreateStdIO
X XREF _DeleteStdIO
X
X XLIB OpenDevice
X XLIB CloseDevice
X
X
X_main:
X move.l _AbsExecBase,a6
X
X ;------ make a reply port
X pea 0
X pea myName
X jsr _CreatePort
X addq.l #8,sp
X
X move.l d0,Port
X beq.s main_end
X
X ;------ get an io request
X move.l d0,-(sp)
X jsr _CreateStdIO
X addq.l #4,sp
X
X move.l d0,Iob
X beq main_DeletePort
X
X move.l d0,a1
X move.l #myName,LN_NAME(a1)
X
X ;------ open the test device: this will bring it in from disk
X lea myDevName(pc),a0
X moveq.l #1,d0
X moveq.l #0,d1
X CALLSYS OpenDevice
X
X tst.l d0
X beq.s 1$
X
X ;------ couldn't find the library
X pea 0
X move.l d0,a0
X move.b IO_ERROR(a0),3(sp)
X pea myDevName(pc)
X pea nodevmsg(pc)
X jsr _printf
X addq.l #8,sp
X
X bra main_DeleteIob
X
X1$:
X
X ;------ close the device
X move.l Iob,a1
X CALLSYS CloseDevice
X
Xmain_DeleteIob:
X move.l Iob,-(sp)
X jsr _DeleteStdIO
X addq.l #4,sp
X
Xmain_DeletePort
X move.l Port,-(sp)
X jsr _DeletePort
X addq.l #4,sp
X
Xmain_end:
X rts
X
XmyDevName: MYDEVNAME
XmyName: dc.b 'testdev',0
Xnodevmsg: dc.b 'can not open device "%s": error %ld',10,0
Xtestmsg: dc.b 'function MYFUNC%ld returned %ld',10,0
X
XPort: dc.l 0
XIob: dc.l 0
X
X END
SHAR_EOF
if test 2021 -ne "`wc -c < 'testdev.asm'`"
then
echo shar: error transmitting "'testdev.asm'" '(should have been 2021 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'makefile'" '(968 characters)'
if test -f 'makefile'
then
echo shar: will not over-write existing file "'makefile'"
else
sed 's/^ X//' << \SHAR_EOF > 'makefile'
X
X#******************************************************************
X#* *
X#* Copyright (C) 1986, Commodore Amiga Inc. All rights reserved. *
X#* Permission granted for non-commercial use * *
X#* *
X#******************************************************************
X
XOBJ = mydev.o testdev.o
X
X.asm.o:
X echo "Assembling $*.asm"
X Assem $*.asm -o $@ -i :include -c S -c W150000 -v $*.err
X
Xtdev: mydev.device testdev
X echo "DONE!"
X
Xtestdev: testdev.o
X echo "Linking $*"
X alink FROM startup.obj+testdev.o to testdev LIBRARY SYS:lib/amiga.lib ver tlink.err
X
X$(OBJ) : mydev.i asmsupp.i
X
Xmydev.device: mydev.o
X echo "Linking $@"
X alink FROM mydev.o to mydev.device LIBRARY SYS:lib/amiga.lib+\
Xsys:lib/debug.lib ver mlink.err
X echo "Copying $@ to devs:"
X copy $@ devs:$@
X echo "Copying $* to df0:expansion:"
X copy mydev.device df0:expansion/$*
SHAR_EOF
if test 968 -ne "`wc -c < 'makefile'`"
then
echo shar: error transmitting "'makefile'" '(should have been 968 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
--
Lee Erickson - now working with, uucp: {ihnp4|seismo|caip}!cbmvax!erickson
but no way officially representing arpa: cbmvax!erickson@seismo.css.GOV
Commodore, Engineering Department