****************************
**                        **
**  doctor64.device V1.0  **
**                        **
**                        **
**  CODE: SNIPER 11.07.98 **
**                        **
**                        **
****************************

        OUTPUT  'devs:doctor64.device'
        MC68000

        include 'exec/types.i'
        include 'exec/initializers.i'
        include 'exec/libraries.i'
        include 'exec/lists.i'
        include 'exec/nodes.i'
        include 'exec/resident.i'
        include 'exec/alerts.i'
        include 'exec/ables.i'
        include 'exec/devices.i'
        include 'exec/io.i'
        include 'exec/memory.i'
        include 'exec/errors.i'
        include 'libraries/dos.i'
        include 'libraries/dosextens.i'
        include 'lvo.i'
	include	'hardware/cia.i'

_LVOVPrintf     equ     -$3ba
_LVOVFPrintf    equ     -$162

VERSION     equ     1
REVISION    equ     0
PRIORITY    equ     0
MD_UNITS    equ     4
PROCSTACK   equ     512
PROCPRI     equ     4

IOERR_BADLEN	equ	-4
IOERR_BUSY	equ	-6
IOERR_SELFTEST	equ	-7
IOERR_NOANSWER	equ	-8
IOERR_TIMEOUT	equ	-9


        ; centronics definition

        ; umgloetet muss werden

        ; stobe->sel
        ; init ->paper out
	; sel  ->busy 


*
*  AMIGA                  DOC64		   
*
* d0-7 2-9 -------------- 2-9 d0-7
*
*
* busy  11 -------------- 17 sel-in
* pout  12 -------------- 16 init
* sel   13 --------------  1 strobe
*
*
*




;BIT_AUTOFEED	equ	0

BIT_SEL		equ	CIAB_PRTRBUSY
BIT_INIT	equ	CIAB_PRTRPOUT
BIT_STROBE	equ	CIAB_PRTRSEL
BIT_AUTOFEED	equ	CIAICRB_FLG





        ;BITDEF  PAR,BUSY,0
        ;BITDEF  PAR,POUT,1
        ;BITDEF  PAR,INIT,1
        ;BITDEF  PAR,SEL,2

    STRUCTURE   Doc64Dev,LIB_SIZE
        ULONG   md_SysLib
        ULONG   md_DosLib
        ULONG   md_SegList
        UBYTE   md_Flags
        UBYTE   md_pad
        STRUCT  md_Units,MD_UNITS*4
        LABEL   Doc64Dev_SIZE

    STRUCTURE   Doc64DevMsg,MN_SIZE
        APTR    mdm_Device
        APTR    mdm_Unit
        LABEL   Doc64DevMsg_SIZE

    STRUCTURE   Doc64DevUnit,UNIT_SIZE
        UBYTE   mdu_UnitNum
        UBYTE   mdu_pad
        STRUCT  mdu_Msg,Doc64DevMsg_SIZE
        APTR    mdu_Process
        LABEL   Doc64DevUnit_SIZE

    BITDEF  MDU,STOPPED,2
*****************************************

start:  moveq   #0,d0
        rts

InitTable:
        dc.w    RTC_MATCHWORD
        dc.l    InitTable
        dc.l    EndNode
        dc.b    RTF_AUTOINIT
        dc.b    VERSION
        dc.b    NT_DEVICE
        dc.b    PRIORITY
        dc.l    DeviceName
        dc.l    idString
        dc.l    Init

DeviceName  dc.b    'doctor64.device',0
            even
            dc.b    '$VER:'
idString    dc.b    'doctor64.device 1.0 (14-JUN-98)',13,10,0
            even

EndNode

Init:   dc.l    Doc64Dev_SIZE
        dc.l    FuncTable
        dc.l    DataTable
        dc.l    InitRoutine


FuncTable:
        dc.l    Open
        dc.l    Close
        dc.l    Expunge
        dc.l    Null
        dc.l    BeginIO
        dc.l    AbortIO
        dc.l    -1

DataTable:
        INITBYTE    LH_TYPE,NT_DEVICE
        INITLONG    LN_NAME,DeviceName
        INITBYTE    LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
        INITWORD    LIB_VERSION,VERSION
        INITWORD    LIB_REVISION,REVISION
        INITLONG    LIB_IDSTRING,idString
        dc.l        0

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

; d0 = my devicepointer
; a0 = seglist
; a6 = execbase
InitRoutine:
        move.l  a5,-(sp)
        move.l  d0,a5           ; device pointer

        move.l  a6,md_SysLib(a5)
        move.l  a0,md_SegList(a5)

        lea     dosname,a1
        moveq   #0,d0
        jsr     _LVOOpenLibrary(a6)
        move.l  d0,md_DosLib(a5)
	move.l	d0,dosbase

        move.l  a5,d0
        move.l  (sp)+,a5
        rts


WAIT    macro
        move    #1024-1,d1
.wait\@ muls    d0,d0
        dbra    d1,.wait\@
        endm


Open: 	movem.l d2/a2-a4,-(sp)

WAITTIME    equ     100

; d0 = unit
; d1 = flags ; a1 = iorequest ; a6 = device Open:  movem.l d2/a2-a4,-(sp)


        ; syncronize to doc64
        movem.l d0-a6,-(sp)

	move.l	md_DosLib(a6),a4	; doslib
        ;move    #$4000,$dff09a

        moveq   #0,d0

        lea     $bfe001,a5              ; centronics data
        lea     $bfd000,a6              ; the centronics steuer leitung

        move.b	#%11000000|(1<<BIT_STROBE),$200(a6)
	move.b	#0,$200(a5)
	

	; bit 0 = busy
        ; bit 1 = paper out  = init
        ; bit 2 = select

        move.b  d0,$100(a5)             ; send 0 & strobe=0
	;clr.b	(a6)

	move.b	#$55,$100(a5)

	move.b	(a6),value
	bsr	output__	


        move    #WAITTIME-1,d7          ; max waittime
.sel0lp
        btst    #BIT_SEL,(a6)           ; wait for select = 0
	bne	.sel

	move.l	(a6),value
	bsr	output__	


        move.b  #$aa,$100(a5)           ; send %10101010 ... and strobe=0
	clr.b	(a6)			; strobe,init=0

	move.b	#BIT_INIT,(a6)

	;WAIT

	;move.l	(a6),value
	;bsr	output__	


        move    #WAITTIME-1,d6          ; max waittime
.sel1lp
	;WAIT
        
	btst    #BIT_SEL,(a6)           ; wait for select = 1
	beq    	.nosel

	move.l	(a6),value
	bsr	output__	

	clr.b	(a6)			; strobe=0


        move    #WAITTIME-1,d5          ; max waittime
.sel0lp1
	;WAIT
        
	btst    #BIT_SEL,(a6)           ; wait for select = 0
        bne.s   .sel1


	move.l	(a6),value
	bsr	output__	


        move.b  #$55,$100(a5)           ; send %01010101 ... and strobe=0
	clr.b	(a6)

	move.b	#BIT_INIT,(a6)		; init = 0


        move    #WAITTIME-1,d4          ; max waittime
.sel1lp1
	;WAIT

        btst    #BIT_SEL,(a6)           ; wait for select = 1
        beq.s   .nosel1


	move.l	(a6),value
	bsr	output__	

	clr.b	(a6)

        move    #WAITTIME-1,d3          ; max waittime

.sel0lp2
	;WAIT
        btst    #BIT_SEL,(a6)           ; wait for select = 0
        bne.s   .sel2

	move.l	(a6),value
	bsr	output__	


        bra.s   .found			; alles ok	

.sel2   WAIT
        ;dbra    d3,.sel0lp2
.nosel1 WAIT
        ;dbra    d4,.sel1lp1
.sel1   WAIT
        ;dbra    d5,.sel0lp1
.nosel  WAIT
        ;dbra    d6,.sel1lp
.sel    WAIT
        dbra    d7,.sel0lp


        ;move    #$c000,$dff09a
        movem.l (sp)+,d0-a6
        move.b  #IOERR_NOANSWER,IO_ERROR(a2)
        bra     .exit

.found

.skip   ;move    #$c000,$dff09a
        movem.l (sp)+,d0-a6


        move.l  a1,a2

        cmp.l   #MD_UNITS,d0            ; check max unit
        bhi     .OpenError

        move.l  d0,d2                   ; pointer to unit struct
        lsl.l   #2,d0
        lea     md_Units(a6,d0.l),a4

        move.l  (a4),d0
        bne     .Open_ok
        bsr     InitUnit
        move.l  (a4),d0
        beq     .OpenError
.Open_ok
        move.l  d0,a3
        move.l  d0,IO_UNIT(a2)
        moveq   #1,d1
        add     d1,LIB_OPENCNT(a6)
        add     d1,UNIT_OPENCNT(a3)
        bclr    #LIBB_DELEXP,md_Flags(a6)

.exit   movem.l (sp)+,d2/a2-a4
        rts

.OpenError:
        move.b  #IOERR_OPENFAIL,IO_ERROR(a2)
        bra     .exit

output__:
	movem.l	d0-a6,-(sp)

	moveq	#0,d0
	move.b	$bfe101,d0
	move.l	d0,value+12

	move.l	a4,a6			; doslib
	lea	string,a0
	lea	value,a1
	move.l	(a1),d0	
	swap	d0
	lsr	#8,d0
	
	clr.l	(a1)
	clr.l	4(a1)
	clr.l	8(a1)

	btst	#0,d0
	beq.s	.skip
	move.l	#1,(a1)
.skip
	btst	#1,d0
	beq.s	.skip1
	move.l	#1,4(a1)
.skip1
	btst	#2,d0
	beq.s	.skip2
	move.l	#1,8(a1)
.skip2


	move.l	a0,d1
	move.l	a1,d2
	jsr	-$3ba(a6)
	movem.l	(sp)+,d0-a6
	rts

test	rts


string: dc.b	10
	dc.b  	'select: %lx',10
	dc.b	'init  : %lx',10
	dc.b	'strobe: %lx',10
	dc.b	'data  : %lx',10
	dc.b	0
	even

value	dc.l	0,0,0,0

; a1 = ioreq
; a6 = device
; ->d0 = seglist
Close:  movem.l a2/a3,-(sp)

        move.l  a1,a2           ; ioreq
        move.l  IO_UNIT(a2),a3  ; unit
        moveq   #-1,d0
        move.l  d0,IO_UNIT(a2)
        move.l  d0,IO_DEVICE(a2)
        sub     #1,UNIT_OPENCNT(a3)
        bne.s   .close
        bsr     ExpungeUnit
.close  moveq   #0,d0
        sub     #1,LIB_OPENCNT(a6)
        bne.s   .exit
        btst    #LIBB_DELEXP,md_Flags(a6)
        beq.s   .exit
        bsr     Expunge
.exit   movem.l (sp)+,a2/a3
        rts


; a6 = device
;-> d0 = seglist
Expunge:
        movem.l d2/a5-a6,-(sp)
        move.l  a6,a5
        move.l  md_SysLib(a5),a6
        tst     LIB_OPENCNT(a5)
        beq.s   .ii
        bset    #LIBB_DELEXP,md_Flags(a5)
        moveq   #0,d0
        bra.s   .exit
.ii
        move.l  md_SegList(a5),d2
        move.l  a5,a1
        jsr     _LVORemove(a6)

        move.l  md_DosLib(a5),a1
        jsr     _LVOCloseLibrary(a6)

        move.l  a5,a1
        moveq   #0,d0
        move    LIB_NEGSIZE(a5),d0
        sub     d0,a1

        add     LIB_POSSIZE(a5),d0
        jsr     _LVOFreeMem(a6)
        move.l  d2,d0

.exit   movem.l (sp)+,d2/a5-a6
        rts

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

InitUnit:
        movem.l d2-d4,-(sp)

        move.l  #Doc64DevUnit_SIZE,d0
        move.l  #MEMF_PUBLIC|MEMF_CLEAR,d1
        move.l  a6,-(sp)
        move.l  md_SysLib(a6),a6
        jsr     _LVOAllocMem(a6)
        move.l  (sp)+,a6
        tst.l   d0
        beq     .exit
        move.l  d0,a3
        move.b  d2,mdu_UnitNum(a3)

        move.l  #PROCSTACK,d4
        move.l  #proc_seglist,d3
        lsr.l   #2,d3
        moveq   #PROCPRI,d2
        move.l  #procname,d1
        move.l  a6,-(sp)
        move.l  md_DosLib(a6),a6
        jsr     _LVOCreateProc(a6)
        move.l  (sp)+,a6
        tst.l   d0
        beq     .free

        move.l  d0,mdu_Process(a3)
        move.l  d0,a0
        lea     -pr_MsgPort(a0),a0
        move.l  a0,MP_SIGTASK(a3)
        move.b  #PA_IGNORE,MP_FLAGS(a3)
        lea     MP_MSGLIST(a3),a1

        NEWLIST a1
        lea     mdu_Msg(a3),a1

        move.l  a3,mdm_Unit(a1)
        move.l  a6,mdm_Device(a1)
        move.l  d0,a0
        move.l  a6,-(sp)
        move.l  md_SysLib(a6),a6
        jsr     _LVOPutMsg(a6)
        move.l  (sp)+,a6
        moveq   #0,d0
        move.b  mdu_UnitNum(a3),d0
        lsl.l   #2,d0

        move.l  a3,md_Units(a6,d0.l)

.exit   movem.l (sp)+,d2-d4
        rts

.free   bsr     FreeUnit
        bra.s   .exit

FreeUnit
        move.l  a3,a1
        move.l  #Doc64DevUnit_SIZE,d0
        move.l  a6,-(sp)
        move.l  md_SysLib(a6),a6
        jsr     _LVOFreeMem(a6)
        move.l  (sp)+,a6
        rts


ExpungeUnit:
        move.l  d2,-(sp)
        move.l  mdu_Process(a3),a1
        lea     -pr_MsgPort(a1),a1
        move.l  a6,-(sp)
        move.l  md_SysLib(a6),a6
        jsr     _LVORemTask(a6)
        move.l  (sp)+,a6
        moveq   #0,d2
        move.b  mdu_UnitNum(a3),d2
        bsr     FreeUnit
        lsl.l   #2,d2

        clr.l   md_Units(a6,d2.l)

        move.l  (sp)+,d2
        rts

Null    moveq   #0,d0
        rts

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

cmdtable:
        dc.l    Invalid         ; $1
        dc.l    Doc64Reset      ; $2
        dc.l    Read            ; $4
        dc.l    Write           ; $8
        dc.l    Update          ; $10
        dc.l    Clear           ; $20
        dc.l    Doc64Stop       ; $40
        dc.l    Start           ; $80
        dc.l    Flush           ; $100

        dc.l    Status          ; $200
cmdtable_end:


DIREKTBEFEHLE   equ $1|$2|$40|$80|$100|$200
FUNKANZ         equ 10

; a1 = ioreq
; a6 = device
BeginIO:
        move.l  a3,-(sp)
        move.l  IO_UNIT(a1),a3
        move    IO_COMMAND(a1),d0
        cmp     #FUNKANZ,d0
        bcc     BeginIO_NoCmd

        move    #$4000,$dff09a

        move.l  #DIREKTBEFEHLE,d1
        btst    d0,d1
        bne.s   BeginIO_Immediate

BeginIO_QueueMsg:
        bset    #UNITB_INTASK,UNIT_FLAGS(a3)
        bclr    #IOB_QUICK,IO_FLAGS(a1)

        move    #$c000,$dff09a

        move.l  a3,a0
        move.l  a6,-(sp)
        move.l  md_SysLib(a6),a6
        jsr     _LVOPutMsg(a6)
        move.l  (sp)+,a6
        bra.s   BeginIO_end

BeginIO_Immediate:
        move    #$c000,$dff09a
        bsr     PerformIO
BeginIO_end:
        move.l  (sp)+,a3
        rts

BeginIO_NoCmd:
        move.b  #IOERR_NOCMD,IO_ERROR(a1)
        bra.s   BeginIO_end

; a1 = ioreq
; a3 = unit
; a6 = device
PerformIO:
        move.l  a2,-(sp)
        move.l  a1,a2
        move    IO_COMMAND(a2),d0
        lsl     #2,d0
        lea     cmdtable(pc),a0
        move.l  (a0,d0.w),a0
        jsr     (a0)
        move.l  (sp)+,a2
        rts

TermIO: move    IO_COMMAND(a1),d0
        move.l  #DIREKTBEFEHLE,d1
        btst    d0,d1
        bne.s   TermIO_Direkt
        btst    #UNITB_INTASK,UNIT_FLAGS(a3)
        bne.s   TermIO_Direkt
        bclr    #UNITB_ACTIVE,UNIT_FLAGS(a3)
TermIO_Direkt:
        btst    #IOB_QUICK,IO_FLAGS(a1)
        bne.s   .exit
        move.l  a6,-(sp)
        move.l  md_SysLib(a6),a6
        jsr     _LVOReplyMsg(a6)
        move.l  (sp)+,a6
.exit   rts



AbortIO:
        moveq   #0,d0
        rts

*************** Commands ****************
; a1 = ioreq
; a3 = unit
; a6 = device

Update:
Clear:
Invalid:
        move.b  IOERR_NOCMD,IO_ERROR(a1)
        bra     TermIO


Doc64Reset:
        bra     TermIO

Read:
        bra     TermIO

Write:
        movem.l d0-a6,-(sp)

	move.l	#dosbase,a0
	move.l	(a0),a4

        ;move    #$4000,$dff09a

        lea     $bfe001,a5              ; centronics data
        lea     $bfd000,a6              ; the centronics steuer leitung


        move.l  IO_DATA(a1),a0		; daten
        move.l  IO_LENGTH(a1),d7	; laenge
	ble	.badlenerror		; muell

.lp



	move.l	(a0),value
	move.l	4(a0),value+4
	move.l	8(a0),value+8
	;jsr	output__	

	; check ~storbe

	move.b	#%11000000,$200(a6)

	btst	#BIT_STROBE,(a6)
	bne.s	.nosel


	;bsr	.waitautofeed0		; autofeed=0	
	;bne.s	.exit	

	

	move.b	#%11000000|BIT_STROBE,$200(a6)

	move.b  (a0)+,$100(a5)          ; send one byte
	move.b	#(1<<BIT_STROBE),(a6)	; strobe = 1


.nosel	
	;bsr	.waitautofeed1		; autofeed=1	
	;bne.s	.exit	

	nop
	nop
	nop
	nop
	nop
	nop
	nop
	
	move.b	#%11000000|BIT_STROBE,$200(a6)

	move.b  (a0)+,$100(a5)          ; send one byte
	clr.b	(a6)			; strobe = 0


        subq.l  #1,d7
        bne.s   .lp


.exit   ;move    #$c000,$dff09a
        movem.l (sp)+,d0-a6
        bra     TermIO

.waitautofeed0:
	; wait for autofeed=0

	move	#100-1,d0
	move	#WAITTIME-1,d0
.autofeedlp0
	btst	#BIT_AUTOFEED,ciaicr(a6)		
	beq.s	.exitfeed
	dbra	d0,.autofeedlp0		
	bsr	.writeerror		; wenn maximale wartezeit ueberschritten	
	moveq	#-1,d0
	rts
.exitfeed
	moveq	#0,d0	
	rts

.waitautofeed1:
	; wait for autofeed=1

	move	#100-1,d0
	move	#WAITTIME-1,d0
.autofeedlp1
	btst	#BIT_AUTOFEED,ciaicr(a6)		
	bne.s	.exitfeed
	dbra	d0,.autofeedlp1		
	bsr	.writeerror		; wenn maximale wartezeit ueberschritten	
	moveq	#-1,d0
	rts


.writeerror
        move.b  #IOERR_TIMEOUT,IO_ERROR(a1)
	rts

.badlenerror
        move.b  #IOERR_BADLEN,IO_ERROR(a1)
	bra.s	.exit



Doc64Stop:
        bset    #MDUB_STOPPED,UNIT_FLAGS(a3)
        bra     TermIO

Start:
        bsr     InternalStart
        move.l  a2,a1
        bra     TermIO

InternalStart:
        bclr    #MDUB_STOPPED,UNIT_FLAGS(a3)
        move.l  MP_SIGTASK(a3),a1
        moveq   #0,d0
        move.b  MP_SIGBIT(a3),d1
        bset    d1,d0
        move.l  a6,-(sp)
        move.l  md_SysLib(a6),a6
        jsr     _LVOSignal(a6)
        move.l  (sp)+,a6
        rts

Flush:  movem.l d2/a6,-(sp)
        move.l  md_SysLib(a6),a6

        FORBID
.loop
        move.l  a3,a0
        jsr     _LVOGetMsg(a6)
        tst.l   d0
        beq.s   .end
        move.l  d0,a1
        move.b  #IOERR_ABORTED,IO_ERROR(a1)
        jsr     _LVOReplyMsg(a6)
        bra.s   .loop

.end    PERMIT
        movem.l (sp)+,d2/a6
        move.l  a2,a1
        bra     TermIO

Status:
        bra     TermIO


****************** DATA *****************


dosbase dc.l    0
dosname dc.b    'dos.library',0
        even
procname
        dc.b    'doctor64.device process',0
        even


************** Process ******************

        cnop    0,4

proc_seglist:
        dc.l    0
Proc_Begin:
        move.l  4.w,a6
        sub.l   a1,a1
        jsr     _LVOFindTask(a6)
        move.l  d0,a0
        move.l  d0,a4
        lea     pr_MsgPort(a0),a0
        jsr     _LVOWaitPort(a6)
        move.l  d0,a1
        move.l  d0,a2
        jsr     _LVORemove(a6)
        move.l  mdm_Device(a2),a5
        move.l  mdm_Unit(a2),a3
        moveq   #-1,d0
        jsr     _LVOAllocSignal(a6)
        move.b  d0,MP_SIGBIT(a3)
        move.b  #PA_SIGNAL,MP_FLAGS(a3)

        moveq   #0,d7
        bset    d0,d7
        bra     Proc_CheckStatus

Proc_MainLoop:
        move.l  d7,d0
        jsr     _LVOWait(a6)
Proc_CheckStatus:
        btst    #MDUB_STOPPED,UNIT_FLAGS(a3)
        bne.s   Proc_MainLoop

        bset    #UNITB_ACTIVE,UNIT_FLAGS(a3)        ;?????????
        bne.s   Proc_MainLoop

Proc_NextMsg:
        move.l  a3,a0
        jsr     _LVOGetMsg(a6)
        tst.l   d0
        beq.s   Proc_UnLock
        move.l  d0,a1
        exg     a5,a6
        bsr     PerformIO
        exg     a5,a6
        bra     Proc_NextMsg

Proc_UnLock:
        bclr    #UNITB_ACTIVE,UNIT_FLAGS(a3)
        bclr    #UNITB_INTASK,UNIT_FLAGS(a3)
        bra     Proc_MainLoop

*****************************************
        END
