home *** CD-ROM | disk | FTP | other *** search
- SECTION PAR
-
- INCLUDE '/INC/QDOS_inc'
- INCLUDE '/INC/AMIGA_inc'
- INCLUDE '/INC/AMIGQDOS_inc'
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; PAR1_asm - parallel device driver
- ; - last modified 03/01/97
-
- ; These are all the necessary parallel port related sources,
- ; required to implement a QDOS parallel device on the Amiga
- ; computer.
-
- ; Amiga-QDOS sources by Rainer Kowallik
- ; ...latest changes by Mark J Swift
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; device driver definitions
- ; (for the driver's own pseudo system vars)
-
- PV_PEND EQU $28 ; (long) pending test
- PV_FBYTE EQU $2C ; (long) fetch byte
- PV_SBYTE EQU $30 ; (long) send byte
- PV_RTS EQU $34 ; (word) RTS (4E75)
- PV_NOP EQU $36 ; (word)
- ; ...(necessary for IO.SERIO)
-
- PV_LLVL7 EQU $38 ; (long) next link
- PV_ALVL7 EQU $3C ; (long) address
- PV_LRSET EQU $40 ; (long) next link
- PV_ARSET EQU $44 ; (long) address
-
- PV_PARTQ EQU $48 ; (long) address of output queue
-
- PV.LEN EQU $4C ; length of PAR device driver defs.
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; Channel definition block
-
- PAR_PROT EQU $18 ; EOL Protocol, -ve RAW
- ; 0 CR/LF, 1 CR, 2 LF
- PAR_EOF EQU $1A ; EOF (CLOSE) protocol
- ; -ve none, 0 FormFeed
- PAR_TXD EQU $1C ; last transmitted character
- PAR_FLGS EQU $1E ; Bit 0 0 = busy
- ; 1 = ready
- PAR_TXQ EQU $20 ; Transmit queue header
- PAR.TXQL EQU 81 ; Transmit buffer len - odd!
-
- PAR.LEN EQU PAR_TXQ+Q_QUEUE+(PAR.TXQL+1)&$FFFE
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; ROM header
-
- BASE:
- dc.l $4AFB0001 ; ROM recognition code
- dc.w 0
- dc.w ROM_START-BASE
- dc.b 0,36,'Amiga-QDOS PAR device driver v1.08 ',$A
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; start of ROM code
-
- ROM_START:
- movem.l d0-d2/a0-a3,-(a7)
-
- ; --------------------------------------------------------------
- ; allocate memory for parallel device variables
-
- move.l #PV.LEN,d1
- moveq #MT.ALCHP,d0
- moveq #0,d2
- trap #1
-
- tst.l d0
- bne ROM_EXIT
-
- ; --------------------------------------------------------------
- ; address of PAR variables
-
- move.l a0,a3
-
- ; --------------------------------------------------------------
- ; enter supervisor mode and disable interrupts
-
- trap #0
-
- ori.w #$0700,sr ; disable interrupts
-
- ; --------------------------------------------------------------
- ; link a custom routine into level 7 interrupt server
- ifd dolvl7
- lea AV.LVL7link,a1
- lea PV_LLVL7(a3),a2
-
- move.l (a1),(a2)
- move.l a2,(a1)
-
- lea MY_LVL7(pc),a1
- move.l a1,$04(a2)
- endif
- ; --------------------------------------------------------------
- ; routines necessary for device driver
-
- lea PAR_IO(pc),a2 ; Input/Output routine
- move.l a2,SV_AIO(a3)
-
- lea PAR_OPEN(pc),a2 ; OPEN routine
- move.l a2,SV_AOPEN(a3)
-
- lea PAR_CLOSe(pc),a2 ; CLOSE routine
- move.l a2,SV_ACLOS(a3)
-
- ; --------------------------------------------------------------
- ; routines necessary for IO.SERIO. (used by PAR I/O routine)
-
- lea ERR_BP(pc),a2 ; test for pending input
- move.l a2,PV_PEND(a3) ; (not provided)
-
- lea ERR_BP(pc),a2 ; fetch byte
- move.l a2,PV_FBYTE(a3) ; (not provided)
-
- lea PAR_SBYT(pc),a2 ; send byte
- move.l a2,PV_SBYTE(a3)
-
- move.w #$4E75,PV_RTS(a3) ; RTS instruction at $34
-
- ; --------------------------------------------------------------
- ; set up hardware
-
- bsr.s INIT_HW
-
- clr.l PV_PARTQ(a3)
-
- ; --------------------------------------------------------------
- ; link in device driver
-
- lea SV_LIO(a3),a0 ; link address
- moveq #MT.LIOD,d0 ; link in IO device driver
- trap #1
-
- ; -------------------------------------------------------------
- ; link in external interrupt to act on port free
-
- lea XINT_SERv(pc),a2 ; address of routine
- move.l a2,SV_AXINT(a3)
- lea SV_LXINT(a3),a0
- moveq #MT.LXINT,d0
- trap #1
-
- ; -------------------------------------------------------------
- ; link in poll interrupt to re-enable parallel send
-
- lea POLL_SERv(pc),a2 ; address of routine
- move.l a2,SV_APOLL(a3)
- lea SV_LPOLL(a3),a0
- moveq #MT.LPOLL,d0
- trap #1
-
- ; --------------------------------------------------------------
- ; enable interrupts and re-enter user mode
-
- andi.w #$D8FF,sr
-
- ; --------------------------------------------------------------
- ROM_EXIT:
- movem.l (a7)+,d0-d2/a0-a3
-
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; set up hardware
-
- INIT_HW:
- movem.l d7/a3,-(a7)
-
- move.b CIAB_DDRA,d7
- andi.b #%11111000,d7
- move.b d7,CIAB_DDRA ; SEL,POUT,BUSY to inputs
-
- MOVE.B #$FF,CIAA_DDRB ; set PRB to all output
-
- move.b CIAA_ICR,d7 ; read & clear CIA-A ICR
- or.b AV.CIAA_ICR,d7
- bclr #4,d7 ; clear FLAG bit
- move.b d7,AV.CIAA_ICR ; store for another program
-
- move.w #%0000000000001000,INTREQ ; clear and enable
- move.w #%1000000000001000,INTENA ; CIA-A interrupts
-
- move.b #%10010000,CIAA_ICR ; enable FLAG interrupt
-
- ori.b #%00010000,AV.CIAA_MSK ; take note
-
- ifd dolvl7
- move.l AV.PARV,a3 ; address of PAR variables
- move.l PV_PARTQ(a3),d7 ; address of transmit Q
- beq.s INIT_HWX ; exit if Q doesn't exist
-
- move.l d7,a3
- bset #0,1+PAR_FLGS-PAR_TXQ(a3) ; port ready
-
- INIT_HWX:
- endif
- movem.l (a7)+,d7/a3
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; Poll interrupt server for parallel port.
- ;
- ; Enters: A3 = assumed start of driver definition block
- ; A6 = system variables
-
- POLL_SERv:
- bsr PAR_SEND ; if port ready, send byte
-
- POLL_X:
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; External interrupt server
- ;
- ; Enters: A3 = assumed start of driver definition block
- ; A6 = system variables
-
- XINT_SERv:
- movem.l d7/a0,-(a7)
-
- move.w INTENAR,d7 ; read interrupt enable reg
- btst #3,d7 ; branch if ints not on
- beq XINT_OTHer
-
- move.w INTREQR,d7 ; read interrupt request reg
- btst #3,d7 ; branch if from CIA-A or
- bne CIAA_SERv ; expansion ports
-
- ; --------------------------------------------------------------
- ; otherwise let another external interrupt server handle it
-
- XINT_OTHer:
- movem.l (a7)+,d7/a0
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; Interrupt from CIA-A or expansion port
-
- CIAA_SERv:
- move.b CIAA_ICR,d7 ; read CIA-A ICR
- or.b AV.CIAA_ICR,d7
- move.b d7,AV.CIAA_ICR ; store for another program
-
- bclr #4,d7 ; port ready? (FLAG bit=1)
- beq XINT_OTHer ; no
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; External interrupt server for acting on par port ready
- ; (CIAA FLAG bit=1).
-
- PAR_RDY:
- move.b d7,AV.CIAA_ICR
-
- and.b AV.CIAA_MSK,d7 ; don't clear INTREQ if
- bne.s PAR_RDY0 ; other CIAA ints occured
-
- move.w #%0000000000001000,INTREQ ; clear interrupts
-
- ; -------------------------------------------------------------
- PAR_RDY0:
- move.l PV_PARTQ(a3),d7 ; address of transmit Q
- beq.s XINT_EXIt ; exit if Q doesn't exist
-
- move.l d7,a0
- bset #0,1+PAR_FLGS-PAR_TXQ(a0) ; port ready
-
- bsr PAR_SEND
-
- ; -------------------------------------------------------------
- XINT_EXIt:
- bra XINT_OTHer
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; write next byte from queue to parallel port
-
- PAR_SEND:
- movem.l d1/d7/a2-a4,-(a7)
-
- moveq #ERR.NC,d0 ; assume no can do
-
- move.l PV_PARTQ(a3),d1 ; address of transmit Q
- beq PAR_S_X ; exit if Q doesn't exist
-
- move.l d1,a2
- btst #0,1+PAR_FLGS-PAR_TXQ(a2) ; port ready?
- beq.s PAR_S_X
-
- btst #0,CIAB_PRA ; printer busy?
- bne.s PAR_S_X
-
- btst #1,CIAB_PRA ; paper out?
- bne.s PAR_S_X
-
- btst #2,CIAB_PRA ; printer select?
- beq.s PAR_S_X
-
- moveq #0,d1
- move.w IO.QOUT,a4
- jsr (a4) ; get byte d1 from queue a2
- tst.l d0
- bne.s PAR_S_X ; exit if error
-
- bclr #0,1+PAR_FLGS-PAR_TXQ(a2) ; port busy
-
- move.b CIAA_ICR,d7 ; read CIA-A ICR
- or.b AV.CIAA_ICR,d7
- bclr #4,d7 ; clear FLAG bit
- move.b d7,AV.CIAA_ICR ; store for another program
- move.w #%0000000000001000,INTREQ ; clear interrupts
-
- move.b d1,CIAA_PRB ; write data to par port
-
- PAR_S_X:
- movem.l (a7)+,d1/d7/a2-a4
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; OPEN routine for parallel device.
- ;
- ; Enters: D3 = open type
- ; A0 = start of device name
- ; A3 = assumed start of driver definition block
- ; A6 = system variables
-
- PAR_OPEN:
- movem.l a3,-(a7)
- suba.w #4,a7 ; room for 2 words on stack
-
- movea.l a7,a3 ; address for parameters
- move.w IO.NAME,a4 ; decode device name
- JSR (A4)
-
- BRA.S PAR_O_X ; not found
- BRA.S PAR_O_X ; bad device name
- BRA.S PAR_O_CHK ; OK, name was PAR_
-
- dc.w 3 ; length of device name
- dc.b 'PAR',0 ; definition is PAR
- dc.w 2 ; 2 parameters
-
- dc.w 4 ; char value, 4 options
- dc.b 'RNCL' ; eol protocol
-
- dc.w 1 ; char value, 2 options
- dc.b 'F',0 ; eof protocol
-
- ; --------------------------------------------------------------
- PAR_O_X:
- adda.w #8,a7
- ANDI.W #$F8FF,SR
- RTS
-
- ; --------------------------------------------------------------
- PAR_O_IU:
- moveq #ERR.IU,d0 ; in use
- bra PAR_O_X
-
- ; --------------------------------------------------------------
- PAR_O_CHK:
- move.l 4(a7),a3 ; address of driver def blok
-
- move.l PV_PARTQ(a3),d0 ; address set?
- beq.s PAR_O_CHK1 ; no queue, no chan def blk
-
- movea.l d0,a0
- suba.w #PAR_TXQ,a0 ; addrs of old chan def blk
- bclr #7,PAR_TXQ(a0) ; output queue empty?
- bne.s PAR_O_CHK2 ; yes, so continue
- bra.s PAR_O_IU ; no, so exit with error
-
- PAR_O_CHK1:
- move.w #(PAR.LEN),d1 ; allocate chan def block
- move.w MM.ALCHP,a4 ; for first time
- JSR (A4)
- bne.s PAR_O_X ; exit if error occured
-
- moveq #PAR.TXQL,d1 ; length of transmit queue
- lea PAR_TXQ(a0),a2 ; address of transmit queue
- move.w IO.QSET,a4 ; set up queue (not used
- jsr (a4) ; before
-
- move.l 4(a7),a3 ; address of PAR variables
- move.l a2,PV_PARTQ(a3)
-
- PAR_O_CHK2:
- move.w (a7),PAR_PROT(a0) ; store handshake, protocol
- move.w 2(a7),PAR_EOF(a0) ; store EOF protocol
-
- subq.w #2,PAR_PROT(a0) ; -ve raw : 0 CR/LF : 1 CR : 2 LF
- subq.w #1,PAR_EOF(a0) ; -ve none : 0 FF : CTRL-Z
-
- bset #0,1+PAR_FLGS(a0) ; set 'port ready' flag
-
- ; --------------------------------------------------------------
- PAR_O_OK:
- moveq #ERR.OK,d0 ; signal "no error"
- bra PAR_O_X
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; CLOSE routine for parallel device.
- ;
- ; Enters: A0 = start of device name
- ; A3 = assumed start of driver definition block
- ; A6 = system variables
-
- PAR_CLOSe:
- tst.b 1+PAR_EOF(a0)
- blt.s PAR_C2 ; cont if no eof protocol
-
- move.w #12,d1 ; send Form Feed
-
- PAR_CLUP:
- bsr PAR_SBOK
- cmp.w #ERR.NC,d0
- beq.s PAR_CLUP
-
- PAR_C2:
- lea PAR_TXQ(a0),a2
- move.w IO.QEOF,a4 ; put EOF marker in queue
- jsr (a4)
-
- moveq #ERR.OK,d0 ; signal "no errors"
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; I/O routine for parallel device.
- ;
- ; Enters: A0 = start of device name
- ; A3 = assumed start of driver definition block
- ; A6 = system variables
- ; D0 = operation type
-
- PAR_IO:
- CMP.B #$7,D0 ; trap file operations
- BHI ERR_BP
-
- pea PV_PEND(a3) ; pretend call just before
- move.w IO.SERIO,a4
- JMP (A4)
-
- ; --------------------------------------------------------------
- PAR_SBYT:
- lea PAR_TXQ(a0),a2
-
- move.l d1,d3
- move.w IO.QTEST,a4
- jsr (a4)
- move.l d3,d1
-
- cmpi.w #ERR.EF,d0
- beq.s PAR_SB4
-
- moveq #ERR.OK,d0
-
- cmpi.w #$6,d2 ; reasonable space in Q?
- bge.s PAR_SB5
-
- moveq #ERR.NC,d0
-
- PAR_SB4:
- rts
-
- PAR_SB5:
- move.b 1+PAR_TXD(a0),d3 ; remember old TX code
- move.b d1,1+PAR_TXD(a0) ; save new TX code
-
- tst.b 1+PAR_PROT(a0)
- blt.s PAR_SBOK ; branch if no eol protocol
-
- cmpi.b #$0A,d1 ; Line Feed?
- beq.s PAR_SB1
-
- cmpi.b #$0D,d1 ; Carriage Return?
- bne.s PAR_SBOK ; branch if neither
-
- PAR_SB1:
- cmpi.b #$0A,d3 ; Line Feed?
- beq.s PAR_SB2
-
- cmpi.b #$0D,d3 ; Carriage Return?
- bne.s PAR_SB3
-
- PAR_SB2:
- cmp.b d1,d3
- beq.s PAR_SB3
-
- move.b #$FF,1+PAR_TXD(a0) ; ignore LF in CR/LF couple
- moveq #ERR.OK,d0
- rts
-
- PAR_SB3:
- tst.b 1+PAR_PROT(a0)
- beq.s PAR_SB6 ; branch if CR/LF protocol
-
- cmp.b #2,1+PAR_PROT(a0)
- beq.s PAR_SB7 ; branch if LF
-
- moveq #$0D,d1 ; else use CR
- bra.s PAR_SBOK
-
- PAR_SB6:
- moveq #$0D,d1
- bsr PAR_SBOK
-
- PAR_SB7:
- moveq #$0A,d1
-
- PAR_SBOK:
- lea PAR_TXQ(a0),a2
-
- move.w IO.QIN,a4 ; put byte d1 into queue a2
- jsr (a4)
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ERR_OK:
- moveq #ERR.OK,d0 ; "no error"
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ERR_NC:
- moveq #ERR.NC,d0 ; "not complete"
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ERR_BP:
- moveq #ERR.BP,d0 ; "bad parameter"
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; Custom LVL7 routine to re-initialise hardware
- ifd dolvl7
- MY_LVL7:
- bsr INIT_HW
-
- subq.l #4,a7
- movem.l a3,-(a7)
- move.l AV.PARV,a3
- move.l PV_LLVL7(a3),a3
- move.l 4(a3),4(a7) ; address of next routine
- movem.l (a7)+,a3
-
- rts
- endif
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- END
-