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 27/07/94
-
- ; 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
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; Channel definition block
-
- PAR_TXQL EQU 81 ; Length of transmit buffer
- ; (odd!)
- PAR_DBGQL EQU 2048
-
- PAR_PROT EQU 24 ; EOL Protocol, -ve RAW
- ; 0 CR/LF, 1 CR, 2 LF
- PAR_EOF EQU 26 ; EOF (CLOSE) protocol
- ; -ve none, 0 FormFeed
- PAR_TXD EQU 28 ; last transmitted character
- PAR_FLGS EQU 30 ; Bit 0 0 = busy
- ; 1 = ready
- PAR_TXQ EQU 32 ; Transmit queue header
- PAR_END EQU PAR_TXQ+Q_QUEUE+PAR_TXQL+1 ; total memory
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; 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.07 ',$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,AV.PARV
- 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
-
- lea AV.LVL7link,a1
- lea PV.LVL7link(a3),a2
-
- move.l (a1),(a2)
- move.l a2,(a1)
-
- lea MY_LVL7(pc),a1
- move.l a1,$04(a2)
-
- ; --------------------------------------------------------------
- ; 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
-
- ; --------------------------------------------------------------
- ; 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.l AV.PARV,a3 ; address of PAR variables
-
- 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
-
- MOVE.B #$FF,CIAA_DDRB ; set DDRB to all output
-
- 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:
- movem.l (a7)+,d7/a3
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; poll interrupt server for parallel port.
- ; restarts interrupts by sending a byte.
-
- POLL_SERv:
- bsr PAR_SEND ; if port ready, send byte
-
- POLL_X:
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; external interrupt server
-
- 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 AV.PARV,a0 ; address of PAR variables
-
- move.l PV.PARTQ(a0),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 AV.PARV,a3 ; address of PAR variables
-
- 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
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- ; Here we start with the parallel interface. Although it would
- ; be possible to read from the hardware, I first write this
- ; driver for output only.
- ; I'm following the example from the advanced user guide to
- ; avoid any problems, and get the whole thing to work as quickly
- ; as possible!
- ; Rainer Kowallik
-
- PAR_OPEN:
- suba.w #4,a7 ; room for 5 words on
- movea.l a7,a3 ; stack.
-
- 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 #4,a7
- ANDI.W #$F8FF,SR
- RTS
-
- ; --------------------------------------------------------------
- PAR_O_CHK:
- move.l AV.PARV,a3 ; address of PAR variables
-
- 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_END),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 AV.PARV,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
-
- ; --------------------------------------------------------------
- PAR_O_NF:
- moveq #ERR.NF,d0 ; not found
- bra PAR_O_X
-
- ; --------------------------------------------------------------
- PAR_O_IU:
- moveq #ERR.IU,d0 ; in use
- bra PAR_O_X
-
- ; --------------------------------------------------------------
- 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
-
- ; --------------------------------------------------------------
- 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 initialise hardware
-
- MY_LVL7:
- bsr INIT_HW
-
- subq.l #4,a7
- movem.l a3,-(a7)
- move.l AV.PARV,a3
- move.l PV.LVL7link(a3),a3
- move.l 4(a3),4(a7) ; address of next routine
- movem.l (a7)+,a3
-
- rts
-
- ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- END
-