* scottdisk.asm Copyright 1987 by Scott Turner ALL RIGHTS RESERVED
*
* This is a MOUNTable device driver for the MicroForge SCSI buss interface.
* It may not chase yer mouse pointer around the screen, but I think someone
* will find it useful :-). The strict license below is not because I'm an
* asshole, but because there ARE assholes out there in the world. I've put
* alot of effort into the driver and it is my sincere wish that it be made
* available to ANYONE who wants it so long as the person or entity providing
* it to them doesn't make a profit off it. BE WARNED, THIS IS NOT A 'PLAY'
* LICENSE, I MEAN IT. (grrrr)
*
* This device driver supports 1 (ONE) SCSI buss device. This device can have
* 2 (TWO) hard disk units attached to it. This driver is currently tuned for
* use with an OMTI 5100 SCSI buss device.
*
* Please note that the OMTI needs a little breathing space after completion
* of one command before beginning another. This driver is tuned to work on a
* MC68000 or MC68010 running at the factory clock rate. If you jack the clock
* rate or use an MC68020 you may need to re-tune this driver.
*
* Please note that this device driver uses the power LED as a disk activity
* indicator.
*
* Formatting the hard disk seems to be a touchy area for most disk drivers
* I've seen or heard about. This driver uses the SCSI command #4 to format
* the drive if it is issued a format command for IO_OFFSET 0. I tried using
* the OMTI format track command but it didn't really seem to format the
* track because when I hit the un-formatted part of my test hard disk it
* didn't format it. (Reads would return error $94) So I fell back to my
* less than ideal solution of issuing the format command at offset 0. This
* allows you to format the hard disk with the CLI FORMAT command, but none
* of the other 'nifty' uses of a track by track formatter are available.
* This may seem like a total bummer but then again more than a few controllers
* can't format a single track. :) PLEASE NOTE: Unlike the MessyDOS FORMAT
* command, there IS NO CHANCE of recovering data from the drive! So let's be
* careful out there. ;)
*
* The MOUNT command can be used to partition the two hard disk drives into
* smaller pieces. (See hints below)
*
* Here is a sample mountlist entry for a Seagate ST-4051:
*	DH0:       Device = scottdisk.device
*	           Unit   = 0
*	           Flags  = 1
*	           Surfaces  = 5
*	           BlocksPerTrack = 17
*	           Reserved = 2
*	           Interleave = 0
*	           LowCyl = 0  ;  HighCyl = 976
*	           Buffers = 30
*	           BufMemType = 0
*	#
* Don't forget that the numbers used in the mountlist and used at the end of
* this driver DO NOT HAVE TO MATCH. HOWEVER, the total SIZE given in the
* mountlist MUST NOT exceed the size encoded at the end of this driver.
*
* To setup a system for operation:
*	1. Configure the driver for your hard disk drive(s).
*	2. Construct this driver and place the result in df0:devs/scottdisk.device
*	3. Insert entry(s) into df0:devs/mountlist
*	4. For each drive:
*		A. mount <entryname>
*		B. format drive <entryname> name <somename>
*		C. Insert 'mount <entryname>' into your df0:s/startup-sequence
*	5. Enjoy! :-)
*
* Hints:
* If like me you hate using a slow 2nd floppy drive to copy disks, then setup
* a partition on your hard disk using mountlist. Make it the same as an
* amiga floppy: 11 sectors per track, 2 sides, 80 tracks. Then mount it and
* you can diskcopy to/from a floppy to/from it! You can even call it DF1! :)
* Rather than use the CLI AddBuffers command just tweak the 'Buffers =' line in
* the mountlist entry.
*
* Please note that this driver could have tons of things done to it to improve
* performance. And I am currently continuing work to make all sorts of changes
* to this driver to improve performance. This version is being released at this
* time so that others can get some use from it while I labor on.
*
* If you have questions/comments/requests concerning this source code, please
* direct them in WRITING (no I don't mean via phone!) to:
*
* Scott Turner
* L5 Computing
* 12311 Maplewood Avenue
* Edmonds, WA. 98020-1115 USA
*
* I may also be reached via:
*
* JST on GEnie
* scotty@l5comp.UUCP or stride!l5comp!scotty
*
* I am NOT releasing this source code into the public domain. However, I here
* by grant a license for distribution via AmigaDOS format 3.5" diskette or via
* an online telecommunications medium provided that the party charges less than
* the following to do so:
*
* USA $10 for a copy on an AmigaDOS 3.5" disk.
* USA $10 an hour for 1200 baud connection at 18:00 PST from Seattle, WA USA.
*
* You may not use this source code to make object code if you intend to charge
* anything above the above limits for the object code alone. ie you may not
* sell the object code for more than the above stated limits for the source.
*
* I also hereby grant a license for converting this source code for the
* following purposes:
*	1. To change the hard disk drive parameters.
*	2. To work with other SCSI buss interface cards.
*	3. To work with other SCSI buss devices.
*	4. Re-tune time delays.
*
* HOWEVER, under this license you may NOT:
*	1. Remove my copyright.
*	2. Modify or make additions to this license.
*	3. Change the name of the device from 'scottdisk.device'.
*	4. Change the limitation on charges for object code.
*
* (If you wonder if I'm egotistical, please note that 'scott' is the same
* length as 'track'. This is handy for patching disk editors to use this device
* driver rather than trackdisk.device.)
*
* I reserve all other rights. This source code is made available "AS IS" and I
* make no warranties for it's fitness for any purpose.
*
***************************************************************************
*
* ok, now it's my turn!  i have taken scottdisk.device and changed it from
* a SCSI driver to a parallel port to ibm pc driver.  it's still a disk
* driver, but the "disk" happens to be an ibm pc running a small assembly
* program to enslave it to this driver.
*
* i have included all of Scott Turner's warnings/disclaimers/threats, for
* what it's worth.  i have none to add other than don't use my code for
* commercial purposes without letting me at least know about it.  i'd be
* interested (or maybe amused?).  if Scott or anyone else wants to get in
* touch with me (i tried, Scott, honest i did - the net doesn't seem to
* know you anymore!), here i am:
*
* Scott Drysdale
* 100 East 6th St, Apt 3
* Frederick, MD 21701
* (301) 694-4915
*
* i should be there at least another 4 months 8-).
*
* i have kept scott turner's style (or lack of it) as far as includes and
* references to library offsets and structure offsets.  it's rude, crude,
* and disgusting, but at least the metakumquat assember doesn't take three
* weeks to assemble it this way.  i started to fix it, and was appalled at
* the 3 minute or more assembly times, with hardly any hard disk access!
* you'll note that i gave in when it came to the interrupt disable/enable
* stuff since i didn't wanna play detective to find out what the offset for
* the IDNestCount was.
*
* see the docs provided with this thing for info on how to make the cable
* and modify the ibm pc's parallel port for bidirectional use.
*
* oh - one little thing.  there seems to be a very intermittent reliablity
* problem with this thing.  the symptom is that either the amiga or the PC
* hang as if they are in the middle of a byte handshake, and the other
* side can't see the handshake anymore or has falsely detected one.  i'm
* at a loss.  the NOINTS flag in the code will allow you to disable
* interrupts during transfer if set to 1, and allow them if set to 0.
* this is a stopgap measure, as it doesn't CURE the problem but at least
* reduces it greatly.  a long time ago when i first wrote this thing,
* the problem seemed to be that someone in exec was reprogramming the 
* CIA data direction registers occasionally.  i haven't done any real
* tracking down since i don't really have a use for this stuff anymore
* (it was more of a curiosity - "yeah, yeah - let's write a device
* driver!").  if you find the problem, i'd like to hear about it.
* another warning - sometimes using serial.device will knock out the CIA
* also (ie, using your favorite terminal program).  flame CBM.  and for
* heaven's sake, DON'T use parallel.device while this driver is operating.
* rename it to something like parallel.dev to prevent accidental use.
*
*------------------------------------------------------------------------------
*
* I hate assembling 3,000 lines of include files. How about you?
*

********************** stuff for resources

OpenResource		equ	-6*83	* exec lib offset
MR_PARALLELPORT		equ	2	* resource type
MR_PARALLELBITS		equ	3	* resource type
MR_ALLOCMISCRESOURCE	equ	-6*1	* resource lib offset
MR_FREEMISCRESOURCE	equ	-6*2	* resource lib offset
CIAICRF_FLG		equ	(1<<4)	* flag int bit

**********************


* Definition of our base variables
* This first part is cast in concrete
LibNegSize	EQU	16
LibPosSize	EQU	18
OpenCount	EQU	32
*
* End of pre-defined lib-base structure, we can now do as we damn well please.
CurUnit		EQU	34
CurIOReq	EQU	36
CurBlock	EQU	40
CurBuffer	EQU	44
NotifyIRQ	EQU	48
NeedNotify	EQU	52
DosBase		EQU	56
BaseVarSize	EQU	60
*
* External references to EXEC
_MakeLibrary	EQU	-6*14
_Forbid		EQU	-6*22
_Permit		EQU	-6*23
_Cause		EQU	-6*30
_AddPort	EQU	-6*59
_PutMsg		EQU	-6*61
_GetMsg		EQU	-6*62
_ReplyMsg	EQU	-6*63
_WaitPort	EQU	-6*64
_OpenLibrary	EQU	-6*68
_CloseLibrary	EQU	-6*69
_AddDevice	EQU	-6*72
*
* External AmigaDOG reference
_CreateProc	EQU	-6*23
*
* Address of SCSI port
ciaadata	equ	$bfe001
ciaaddra	equ	$bfe201
ciaadatb	equ	$bfe101
ciaaddrb	equ	$bfe301
ciabdata	equ	$bfd000
ciabddra	equ	$bfd200
ciabdatb	equ	$bfd100
ciabddrb	equ	$bfd300
*

_intena equ $dff09a

	include "exec/execbase.i"

DISABLE     MACRO   * [scratchReg]
            IFC     '\1',''
            MOVE.W  #$04000,_intena     *(NOT IF_SETCLR)+IF_INTEN
            ADDQ.B  #1,IDNestCnt(A6)
            ENDC
            IFNC    '\1',''
            MOVE.L  4,\1
            MOVE.W  #$04000,_intena     *(NOT IF_SETCLR)+IF_INTEN
            ADDQ.B  #1,IDNestCnt(\1)
            ENDC
            ENDM


ENABLE      MACRO   * [scratchReg]
            IFC     '\1',''
            SUBQ.B  #1,IDNestCnt(A6)
            BGE.S   ENABLE\@
            MOVE.W  #$0C000,_intena     *IF_SETCLR+IF_INTEN
ENABLE\@:
            ENDC
            IFNC    '\1',''
            MOVE.L  4,\1
            SUBQ.B  #1,IDNestCnt(\1)
            BGE.S   ENABLE\@
            MOVE.W  #$0C000,_intena
ENABLE\@:
            ENDC
            ENDM

NOINTS equ 1


*.
* Device version
MajorVersion	EQU	1
MinorVersion	EQU	1
*
* Driver header
DriverIDString	DC.B	'ScottDisk 1.1 (23 May 1987)',13,10,0
MatchTag	DC.W	$4AFC		; RT_MATCHWORD
		DC.L	MatchTag	; RT_MATCHTAG
		DC.L	EndOfDriver	; RT_ENDSKIP
		DC.B	1		; RT_FLAGS
		DC.B	MajorVersion	; RT_VERSION
		DC.B	3		; RT_TYPE
		DC.B	30		; RT_PRI (30)
		DC.L	DeviceName	; RT_NAME
		DC.L	DriverIDString	; RT_IDSTRING
		DC.L	DriverInit	; RT_INIT
*
* NOTE: This table is up here so the entries are positive in value. I don't
* know if this is important or not.
VectorTable	DC.W	-1	; Entries are relative to VectorTable
		DC.W	DeviceOpen-VectorTable		; Open
		DC.W	DeviceClose-VectorTable		; Close
		DC.W	DeviceNull-VectorTable		; Expunge
		DC.W	DeviceNull-VectorTable		; NULL
		DC.W	DeviceBeginIO-VectorTable	; BeginIO
		DC.W	DeviceNull-VectorTable		; AbortIO
		DC.W	-1	; End of the table

DeviceOpen	CMPI.L	#0,D0		; Unit number = 0 or 1?
		BHI.S	0$
		MOVE.L	D0,24(A1)	; Then AOK
		CLR.B	31(A1)		; IO_ERR := 0
		ADDQ.W	#1,32(A6)	; Bump open count
		RTS       
*
* Illegal unit # requested
0$		MOVE.B	#32,31(A1)	; Return bad unit number error
		RTS

DeviceClose	MOVEQ	#-1,D0
		MOVE.L	D0,24(A1)	; Kill unit #
		MOVE.L	D0,20(A1)	; Kill device pointer
*
* Dec open counter, but don't let it go negative
		MOVE.W	OpenCount(A6),D0
		BEQ.S	0$
		SUBQ.W	#1,D0
		MOVE.W	D0,OpenCount(A6)
		bne	0$
		jsr	shutcontroller
0$		MOVEQ	#0,D0
		RTS       

DeviceBeginIO	MOVEM.L	D1/A0-A1,-(A7)
		CMPI.L	#0,24(A1)	; Legal unit #?
		BHI.S	3$
		CLR.B	31(A1)		; IO_ERR := 0
		MOVE.B	29(A1),D0	; Get command
		SUBI.B	#12,D0		; Standard command?
		BLT.S	2$
		CMPI.B	#4,D0		; Special command?
		BGE.S	2$
		TST.B	D0
		BNE.S	0$
*
* Record notify info
		MOVE.L	40(A1),NotifyIRQ(A6)
		SNE	NeedNotify(A6)
		BRA.S	1$
*
* Return command packet now
3$		MOVE.B	#32,31(A1)	; IO_ERR := bad unit you nerd!
0$		CLR.L	32(A1)
1$		BSET	#7,30(A1)
		MOVE.B	#5,8(A1)
		MOVEM.L	(A7)+,D1/A0-A1
		MOVEQ	#0,D0
		RTS       

*
* Post command to the handler
2$		ANDI.B	#$7E,30(A1)	; Clear status flags
		LEA	OurPort,A0
		MOVE.L	A6,-(A7)
		MOVEA.L	4,A6
		JSR	_PutMsg(A6)
		MOVEA.L	(A7)+,A6
		MOVEM.L	(A7)+,D1/A0-A1
		MOVEQ	#0,D0
DeviceNull	RTS       

DriverInitStructure
		DC.B	%11100000
		DC.B	0
		DC.W	$8	; LN_TYPE
		DC.B	3	; Device
		DC.B	0	; Pad
		DC.B	%11000000
		DC.B	0
		DC.W	$A	; LN_NAME
		DC.L	DeviceName
		DC.B	%11100000
		DC.B	0
		DC.W	$E	; LIB_FLAGS
		DC.B	6	; Value for LIB_FLAGS, JustChanged, and please sum
		DC.B	0	; Padding
		DC.B	%11000000
		DC.B	0
		DC.W	20	; LIB_VERSION
		DC.W	MajorVersion
		DC.W	MinorVersion
		DC.L	0

DogName		DC.B	'dos.library',0
NewProcRecord	DC.L	DeviceName
		DC.L	5
		DC.L	SegList
		DC.L	256

DriverInit	MOVEM.L	A2/A6,-(SP)
		MOVEA.L	4,A6
*
* Build library structure
		LEA	VectorTable,A0	; Vectors
		LEA	DriverInitStructure,A1	; InitStructure
		SUBA.L	A2,A2		; InitRoutine, NULL we're already running!
		MOVEQ	#BaseVarSize,D0	; Our data seg size
		JSR	_MakeLibrary(A6)
		TST.L	D0
		BEQ.S	TwilightZone	; Go there if we didn't get created
*
* We were created
* Save library base for the new process
		MOVE.L	D0,LibraryBase
		MOVEA.L	D0,A2
*
* Create a process for our handler
		LEA	DogName(PC),A1
		MOVEQ	#0,D0
		JSR	_OpenLibrary(A6)
		MOVE.L	D0,DosBase(A2)
		MOVEA.L	D0,A2
*
* Create the handler process
		MOVEM.L	NewProcRecord(PC),D1-D4
		LSR.L	#2,D3		; Linker won't do this :)
		JSR	_CreateProc(A2)
		SUBI.L	#$5C,D0		; Convert DOS process to Exec process
		MOVE.L	D0,PortTask	; Patch message port
*
* Add our communications port to the system list
		LEA	OurPort,A1
		JSR	_AddPort(A6)
*
* Add us to the system device list
		MOVEA.L	LibraryBase,A1	; Position parameter for call
		JSR	_AddDevice(A6)
		MOVEQ	#1,D0		; Indicate that we opened
		MOVEM.L	(SP)+,A2/A6
		RTS

TwilightZone	MOVEQ	#0,D0		; Indicate that we didn't open
		MOVEM.L	(SP)+,A2/A6
		RTS
*
* Here begins the code for the handler process
		CNOP	0,4	; MUST be on longword boundary
		DC.L	16	; Segment length, value doesn't matter
SegList		DC.L	0	; Pointer to next segment (ie none)
*
* Initialize some registers with some handy values
		MOVEA.L	4,A6
		MOVEA.L	LibraryBase,A5
*
* Configure the SCSI hard disk controller
		JSR	_Forbid(A6)
		BSR	InitController
		JSR	_Permit(A6)
*
* Start waiting for commands on our port
		CLR.W	NeedNotify(A5)
LoopTop		TST.W	NeedNotify(A5)
		BEQ.S	0$
		MOVEA.L	NotifyIRQ(A5),A1
		JSR	_Cause(A6)
		CLR.W	NeedNotify(A5)
0$		LEA	OurPort,A0
		JSR	_WaitPort(A6)
		MOVE.L	D0,CurIOReq(A5)
		LEA	OurPort,A0		; Delink the message
		JSR	_GetMsg(A6)
		TST.L	CurIOReq(A5)
		BEQ	LoopTop
*
* We have a packet, process it
		BCHG	#1,$BFE001		; Dim the LED
		MOVEA.L	CurIOReq(A5),A0
		MOVE.W	24+2(A0),D1		; Get unit #
		LSL.W	#5,D1			; Convert to LUN
		MOVE.B	D1,CurUnit(A5)		; Store for use later
		MOVE.L	44(A0),D0		; Get IO_OFFSET
		MOVEQ	#9,D1
		LSR.L	D1,D0
		MOVE.L	D0,CurBlock(A5)
		MOVE.L	36(A0),D7		; Get IO_LENGTH
		LSR.L	D1,D7
		MOVE.L	40(A0),CurBuffer(A5)	; Move IO_BUFFER
		MOVEQ	#0,D1			; Get IO_COMMAND
		MOVE.B	29(A0),D1
		CMPI.W	#12,D1			; In range?
		BCC.S	CmdDone
		ADD.W	D1,D1
		JMP	DispatchTable(PC,D1.W)

MotorCmd	MOVE.L	#1,32(A0)	;Return motor as ON
		BRA.S	CmdDone

ReturnAOK	MOVE.L	#0,32(A0)
CmdDone		BCHG	#1,$BFE001	; Bring LED back up
		MOVEA.L	CurIOReq(A5),A1	; Send request back
		JSR	_ReplyMsg(A6)
		BRA	LoopTop		; Back to loop top

DispatchTable	BRA	ReturnAOK	;Invalid
		BRA	ReturnAOK	;Reset
		BRA.S	ReadCmd		;Read
		BRA.S	WCmd		;Write
		BRA	ReturnAOK	;Update buffers
		BRA	ReturnAOK	;Clear buffers
		BRA	ReturnAOK	;Stop
		BRA	ReturnAOK	;Start
		BRA	ReturnAOK	;Abort
		BRA	MotorCmd	;Motor
		BRA	ReturnAOK	;Seek
*
* Save one BRA by placing this here (Can I shave code or what? :)
FormatCmd	
*		bra	ReturnAOK	;uncomment to have "null" formatting

WCmd		bra	WriteCmd

ReadCmd		SUBQ.W	#1,D7
		blt	rdend

	IFGE NOINTS
		DISABLE
		jsr setbits
	ENDC

		lea.l	ciaadatb,a1
		lea.l	ciabdata,a2
		lea.l	ciaaddrb,a3

		moveq	#1,d2
		moveq	#2,d3

		MOVEA.L	CurBuffer(A5),A0

rl0		moveq	#0,d0
		BSR	SendCmd
1$		move.b	#0,(a3)
		MOVE.w	#128-1,D1

2$		btst	d2,(a2)		* wait for ind
		bne	2$
		move.b	(a1),(a0)+	* get data
		bclr	d3,(a2)		* set ack
3$		btst	d2,(a2)		* wait for ind to clr
		beq	3$
		bset	d3,(a2)		* clr ack

4$		btst	d2,(a2)		* wait for ind
		bne	4$
		move.b	(a1),(a0)+	* get data
		bclr	d3,(a2)		* set ack
5$		btst	d2,(a2)		* wait for ind to clr
		beq	5$
		bset	d3,(a2)		* clr ack

6$		btst	d2,(a2)		* wait for ind
		bne	6$
		move.b	(a1),(a0)+	* get data
		bclr	d3,(a2)		* set ack
7$		btst	d2,(a2)		* wait for ind to clr
		beq	7$
		bset	d3,(a2)		* clr ack

8$		btst	d2,(a2)		* wait for ind
		bne	8$
		move.b	(a1),(a0)+	* get data
		bclr	d3,(a2)		* set ack
9$		btst	d2,(a2)		* wait for ind to clr
		beq	9$
		bset	d3,(a2)		* clr ack

		dbra	d1,2$

		addq.l	#1,CurBlock(a5)
		DBRA	D7,rl0

	IFGE NOINTS
		ENABLE
	ENDC

rdend		MOVEA.L	CurIOReq(A5),A0
		MOVE.L	36(A0),32(A0)
		BRA	CmdDone

WriteCmd	SUBQ.W	#1,D7
		blt	wrend

	IFGE NOINTS
		DISABLE
		jsr setbits
	ENDC

		lea.l	ciaadatb,a1
		lea.l	ciabdata,a2
		lea.l	ciaaddrb,a3

		moveq	#1,d2
		moveq	#2,d3

		MOVEA.L	CurBuffer(A5),A0

wl0		moveq	#1,d0
		BSR	SendCmd
		MOVE.w	#128-1,D1

1$		MOVE.B	(A0)+,(a1)	* send data
		bclr	d3,(a2)		* set indicator
2$		btst	d2,(a2)		* wait for ack
		bne	2$
		bset	d3,(a2)		* clr indicator
3$		btst	d2,(a2)		* wait for ack to clr
		beq	3$

		MOVE.B	(A0)+,(a1)	* send data
		bclr	d3,(a2)		* set indicator
4$		btst	d2,(a2)		* wait for ack
		bne	4$
		bset	d3,(a2)		* clr indicator
5$		btst	d2,(a2)		* wait for ack to clr
		beq	5$

		MOVE.B	(A0)+,(a1)	* send data
		bclr	d3,(a2)		* set indicator
6$		btst	d2,(a2)		* wait for ack
		bne	6$
		bset	d3,(a2)		* clr indicator
7$		btst	d2,(a2)		* wait for ack to clr
		beq	7$

		MOVE.B	(A0)+,(a1)	* send data
		bclr	d3,(a2)		* set indicator
8$		btst	d2,(a2)		* wait for ack
		bne	8$
		bset	d3,(a2)		* clr indicator
9$		btst	d2,(a2)		* wait for ack to clr
		beq	9$

		dbra	d1,1$

		addq.l	#1,CurBlock(a5)
		DBRA	D7,wl0

	IFGE NOINTS
		ENABLE
	ENDC

wrend		MOVEA.L	CurIOReq(A5),A0
		MOVE.L	36(A0),32(A0)
		BRA	CmdDone


SendCmd		move.b	#$ff,(a3)
		move.b	d0,(a1)		* send data
		bclr	d3,(a2)		* set indicator
1$		btst	d2,(a2)		* wait for ack
		bne	1$
		bset	d3,(a2)		* clr indicator
2$		btst	d2,(a2)		* wait for ack to clr
		beq	2$

sc3		move.b	CurBlock+3(a5),(a1)		* send data
		bclr	d3,(a2)		* set indicator
1$		btst	d2,(a2)		* wait for ack
		bne	1$
		bset	d3,(a2)		* clr indicator
2$		btst	d2,(a2)		* wait for ack to clr
		beq	2$

sc2		move.b	CurBlock+2(a5),(a1)		* send data
		bclr	d3,(a2)		* set indicator
1$		btst	d2,(a2)		* wait for ack
		bne	1$
		bset	d3,(a2)		* clr indicator
2$		btst	d2,(a2)		* wait for ack to clr
		beq	2$

sc1		move.b	CurBlock+1(a5),(a1)		* send data
		bclr	d3,(a2)		* set indicator
1$		btst	d2,(a2)		* wait for ack
		bne	1$
		bset	d3,(a2)		* clr indicator
2$		btst	d2,(a2)		* wait for ack to clr
		beq	2$

sc0		move.b	CurBlock+0(a5),(a1)		* send data
		bclr	d3,(a2)		* set indicator
1$		btst	d2,(a2)		* wait for ack
		bne	1$
		bset	d3,(a2)		* clr indicator
2$		btst	d2,(a2)		* wait for ack to clr
		beq	2$

		rts


InitController
	lea.l	MiscName,a1		* MiscRes = OpenRes(MISCNAME)
	jsr	OpenResource(a6)
	move.l	d0,MiscResource
	beq	opnerr

	lea.l	CIAName,a1		* CIAARes = CIAARes = OpenRes(CIAANAME)
	jsr	OpenResource(a6)
	move.l	d0,CIAAResource
	beq	opnerr

*	bra	prgbits

	move.l	MiscResource,a0		* GetMiscRes(MiscRes,MR_PPRT,myname)
	move.l	#MR_PARALLELPORT,d0
	lea.l	DeviceName,a1
	jsr	GetMiscResource
	tst.l	d0
	bne	opnerr

	move.l	MiscResource,a0		* GetMiscRes(MiscRes,MR_PBTS,myname)
	move.l	#MR_PARALLELBITS,d0
	lea.l	DeviceName,a1
	jsr	GetMiscResource
	tst.l	d0
	beq	opnxt

	move.l	MiscResource,a0
	move.l	#MR_PARALLELPORT,d0
	jsr	FreeMiscResource
	bra	opnerr

opnxt	
*	move.l	CIAAResource,d0		* disable ACK int
*	move.l	#CIAICRF_FLG,d1
*	jsr	AbleICR(a6)

*	move.l	CIAAResource,a0		* clear pending interrupts
*	move.l	CIAICRF_FLG,d0
*	jsr	SetICR(a6)

prgbits	jsr setbits
	moveq	#0,d0		* ok
	rts

setbits	move.b	#0,ciaaddrb	* make port an input
	bclr	#1,ciabddra	* make ind an input
	bset	#2,ciabdata	* set ack (inactive)
	bset	#2,ciabddra	* make ack an output
	rts

opnerr	moveq	#1,d0		* err
	rts


shutcontroller
	move.b	#0,ciaaddrb	* make port an input
	bclr	#1,ciabddra	* make ind an input
	bclr	#2,ciabddra	* make ack an input

	move.l	MiscResource,a0		* free parallel port
	move.l	#MR_PARALLELPORT,d0
	jsr	FreeMiscResource

	move.l	MiscResource,a0		* free bits
	move.l	#MR_PARALLELBITS,d0
	jsr	FreeMiscResource

	rts


GetMiscResource:
	movem.l	a6,-(sp)
	move.l	a0,a6	; misc resource pointer
	jsr	MR_ALLOCMISCRESOURCE(a6)
	movem.l	(sp)+,a6
	rts

FreeMiscResource:
	movem.l	a6,-(sp)
	move.l	a0,a6		; misc resource pointer
	jsr	MR_FREEMISCRESOURCE(a6)
	movem.l	(sp)+,a6
	rts

	CNOP	0,4

MiscName		dc.b	'misc.resource',0
CIAName			dc.b	'ciaa.resource',0

*
* End driver on a long word boundary
		CNOP	0,4
EndOfDriver

*
* NOTE: I use a DATA section so that I can reach some of these variables via
* absolute addressing. I COULD hang them off (A5) but it was just simpler to
* hack them in down here as I needed them...

	DATA

	CNOP	0,4

DeviceName	DC.B	'scottdisk.device',0
		CNOP	0,4
LibraryBase	DC.L	0
OurPort		DC.L	0
		DC.L	0
		DC.B	4
		DC.B	0
		DC.L	DeviceName
		DC.B	0
		DC.B	24
PortTask	DC.L	0	;TaskHandle
LH1		DC.L	LH2
LH2		DC.L	0
		DC.L	LH1
		DC.B	5
		DC.B	0
MiscResource	dc.l	0
CIAAResource	dc.l	0

	CNOP	0,4


		END
