****************************
**                        **
**  doctor64.device V1.0  **
**                        **
**                        **
**  CODE: SNIPER 14.06.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'

_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


        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  a5,d0
        move.l  (sp)+,a5
        rts

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


WAITTIME    equ     1024

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


        ; syncronize to doc64
        movem.l d0-a6,-(sp)
        move    #$4000,$dff09a

        moveq   #0,d0

        lea     $bfe001,a5              ; centronics data
        lea     $bfd000,a6              ; the centronics steuer leitung
        move.b  #%11000010,$200(a6)     ; set datadirection sel=in pout=out busy=in
        ; bit 0 = busy
        ; bit 1 = paper out  = init
        ; bit 2 = select
        move.b  d0,$100(a5)             ; send 0 ... and strobe=0
        move    #WAITTIME-1,d7          ; max waittime
.sel0lp
        btst    #PARB_SEL,(a6)          ; wait for select = 0
        bne.s   .sel

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

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

        move.b  d0,$100(a5)             ; strobe=0

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

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

        move    #WAITTIME-1,d4          ; max waittime
.sel1lp1
        btst    #PARB_SEL,(a6)          ; wait for select = 1
        beq.s   .nosel1

        move.b  d0,$100(a5)             ; strobe=0

        move    #WAITTIME-1,d3          ; max waittime
.sel0lp2
        btst    #PARB_SEL,(a6)          ; wait for select = 0
        bne.s   .sel2
        bra.s   .found
.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  #13,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


; 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    #$4000,$dff09a

        lea     $bfe001,a5              ; centronics data
        lea     $bfd000,a6              ; the centronics steuer leitung
        move.b  #%11000010,$200(a6)     ; set datadirection sel=in pout=out busy=in


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

.lp

	; check ~storbe
	
	btst	#PARB_SEL,(a6)
	bne.s	.nosel


	bsr	.waitautofeed0		; autofeed=0	
	bne.s	.exit	
	move.b  (a0)+,$100(a5)          ; send one byte
	bset	#PARB_SEL,(a6)		; stobe=1
.nosel	
	bsr	.waitautofeed1		; autofeed=1	
	bne.s	.exit	
	move.b  (a0)+,$100(a5)          ; send one byte
	bclr	#PARB_SEL,(a6)		; stobe=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	#WAITTIME-1,d0
.autofeedlp0
	btst	#PARB_BUSY,(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	#WAITTIME-1,d0
.autofeedlp1
	btst	#PARB_BUSY,(a6)		
	bne.s	.exitfeed
	dbra	d0,.autofeedlp1		
	bsr	.writeerror		; wenn maximale wartezeit ueberschritten	
	moveq	#-1,d0
	rts

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

.badlenerror
        move.b  #IOERR_BADLEN,IO_ERROR(a2)
	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
