	.TITLE	QADRV DR-11W DEVICE DRIVER
	.IDENT	/02/
 
;
; change to version 2, add set time out subfunction code
;
; 
;
; MACRO LIBRARY CALLS
;

	.MCALL	HWDDF$,PKTDF$,SCBDF$,UCBDF$,DEVDF$
	HWDDF$			;DEFINE HARDWARE REGISTERS
	PKTDF$			;DEFINE I/O PACKET OFFSETS
        SCBDF$  		;DEFINE SCB OFFSETS
        UCBDF$
        DEVDF$
;
;
;
;
; DRIVER DISPATCH TABLE
;	GENERATES THE DRIVER DISPATCH TABLE FOR A M-PLUS SYSTEM.
;	INCLUDES POWER FAIL, CONTROLLER ONLINE AND UNIT ONLINE
;	ENTRY POINTS.
;
	.list meb
	DDT$	QA,Q$$A11,,,,NEW=y ;GENERATE DISPATCH TABLE		
;

.even
	.ENABL	LSB
QAKRB::				;CONTROLLER ENTRY POINT
;	Entry will be for controller online/offline transitions
;	execute return on controller on line 
;	clear unit on offline
;	c=1 online to offline transition
;	c=0 offline to online transition
;	r3=ctb address
;	r2=krb address
;
        bcs	qaaofl		;if c set take controller offline
	return
qaaofl: mov 	k.csr(r2),r0	;get csr
      	clr	drcsr(r0)	;clear csr
        return
;
;		
QAucb:		
;	unit status change	
;	similar to device controller
;	for online, reset
;	for offline, clear csr
;	r5=ucb address
;	r4=scb address
;	r3=controller index
;	c=1	online to offline
;	c=0	offline to online
;
	bcs	QAofl			;if c set, take device offline
	bicb	#us.ofl,u.st2(r5)	;set device online
	mov	s.csr(r4),r2		;get csr base
	reset				;reset dr11-w
	return
;
QAofl:	mov	s.csr(r4),r2		;get csr
	dsabl	pr5			;;;disable interrupt
	clr	drcsr(r2)		;;;clear csr
	delay	5			;;;let settle
	enabl				;enable interrupt
	return
;
;	i/o initiation point
;
QAINI:
;
; INPUTS:
;
;	R5=ADDRESS OF THE UCB OF THE CONTROLLER TO BE INITIATED.
;
; OUTPUTS:
;
;	IF THE SPECIFIED CONTROLLER IS NOT BUSY AND AN I/O REQUEST IS WAIT-
;	ING TO BE PROCESSED, THEN THE REQUEST IS DEQUEUED AND THE I/O OPER-
;	ATION IS INITIATED.
;
; THE FOLLOWING ARGUMENTS ARE RETURNED BY $GTPKT:
;	R1=ADDRESS OF THE I/O REQUEST PACKET.
;	R2=PHYSICAL UNIT NUMBER OF THE REQUEST UCB.
;	R3=CONTROLLER INDEX.
;	R4=ADDRESS OF THE STATUS CONTROL BLOCK
;	R5=ADDRESS OF THE UCB OF THE CONTROLLER TO BE INITIATED.
;
;	DR11-W I/O PACKET STRUCTURE
;
;	WD. 00 -- I/O QUEUE THREAD WORD.
;	WD. 01 -- REQUEST PRIORITY, EVENT FLAG NUMBER.
;	WD. 02 -- ADDRESS OF THE TCB OF THE REQUESTOR TASK.
;	WD. 03 -- POINTER TO SECOND LUN WORD IN REQUESTOR TASK HEADER.
;	WD. 04 -- CONTENTS OF THE FIRST LUN WORD IN REQUESTOR TASK HEADER (UCB).
;	WD. 05 -- I/O FUNCTION CODE (IO.RLB, IO.WLB, IO.STC, OR IO.SEC)
;	WD. 06 -- VIRTUAL ADDRESS OF I/O STATUS BLOCK.
;	WD. 07 -- RELOCATION BIAS OF I/O STATUS BLOCK.
;	WD. 10 -- I/O STATUS BLOCK ADDRESS (DISPLACEMENT + 140000).
;	WD. 11 -- VIRTUAL ADDRESS OF AST SERVICE ROUTINE.
;		Start of parameter 6 word block
;	WD. 12 -- MEMORY EXTENSION BITS (BITS 4 AND 5) OF I/O TRANSFER.
;	WD. 13 -- BUFFER ADDRESS OF I/O TRANSFER
;	WD. 14 -- NUMBER OF BYTES TO BE TRANSFERED.
;	WD. 15 -- if io.sft subfunction, function bits
;	WD. 16 -- if io.sto subfunction, time out in seconds
;	WD. 17 --
;	WD. 20 -- Attachment descriptors, used by system for io
;	WD. 21 -- locking
;
;	DETERMINE FUNCTION
;
	GTPKT$	QA,Q$$A11,,,SUC			;GET NEXT PACKET
        cmpb	#5,i.fcn+1(r1)			;we doing set or sense
        beq	5$
        jmp 	25$				;must be someting else         
5$:     cmp	#io.stc,i.fcn(r1)		;set or sense characterisitcs
        beq	8$				;set characteristics
        cmp	#io.sec,i.fcn(r1)		;sense characteristics
        beq	12$
6$:	mov 	#ie.bad,r0			;flag bad parameter
        call	$iodon				;tell him about it
        jmp 	qaini				;go do some work
;++
; set characteristics function
;
;--
8$:	mov	s.csr(r4),r2			;get csr address
        mov	i.prm(r1),r0			;get bits
        bic	#177770,r0			;clear trash
        asl	r0				;shift	left
        dsabl	pr5				;don't bother me
        mov	drcsr(r2),r1			;;;get csr into r1
        bic	#qaerr!qafnt!qago,r1		;;;clear function and go bits
        bis	r0,r1				;;;set function bits
        mov	r1,drcsr(r2)			;;;reset reg
        enabl					;back 
;++
; sense characteristics function
;--
12$:	mov	s.csr(r4),r2			;get csr address
	mov	drcsr(r2),r1			;put csr in r1
        mov	#is.suc&377,r0			;flag we got the data
	call 	$iodon				;finish i/o
	jmp	QAini				;go see if more to do

;++
;
; 	read or write logical function at this point
;	must be a data transfer
;
;	get here with
;	r1=iopkt
;	r5=scb
;	r4=ucb
;
;--
25$:	cmpb	#<io.rlb/256.>,i.fcn+1(r1)	;read ?
        beq	27$
	cmpb	#<io.wlb/256.>,i.fcn+1(r1)	;write
        beq	27$
        jmp	6$				;bad params
27$:	bit	#1,u.cnt(r5)			;test for odd word count
        beq	28$				;eq 0, must be even
        jmp	6$

28$:	bit	#io.res,i.fcn(r1)		;reset needed
	beq	30$				;eq 0, no
	mov	s.csr(r4),r2			; get csr base , r2 had unit #
	reset					;reset dr11-w
;
;		we set up to do transfer
;
30$:	CALL	$STMAP				;GET UNIBUS MAPPING SET UP
	CALL	$MPUBM				;MAP UNIBUS TO MEM
      						;R3 PRESERVED ACCROSS CALL
        MOV	s.pkt(r4),R1			;RESTORE PACKET        
	MOV	s.csr(R4),R2			;POINT R2 TO CSR actually base
						;READ/WRITE DMA FUNCTION
;	convert byte to word count and load wcr
	MOV	U.CNT(R5),R3			;POINT R3 TO BYTE COUNT
	CLC					;CLEAR CARRY
	ROR	R3				;BYTE*2=WORD CNT
	NEG	R3				;- WORD COUNT
        dsabl	pr5				;don't bother me
	mov	r3,drwcr(r2)			;;;load wcr for dma operation
;						;may differ for word mode
;	
;
;	first we must set up csr image in r0
	mov	drcsr(r2),r0			;;;get csr
	bic	#^c<QAfnt>,r0			;;;clear all but function bits
	bit	#io.sft,i.fcn(r1)		;;;set function ?
	beq	50$				;;;eq 0, no
	bic	#QAfnt,r0			;;;clear old bits
	mov	i.prm+6(r1),r3			;;;get new function bits ?
        bic	#177770,r3			;;;clear all but lower three
        asl 	r3				;;;shift to control position
        bis	r3,r0				;;;set into csr image
50$:	mov	u.buf+2(r5),drbar(r2)		;;;set buffer address reg
	bis	u.buf(r5),r0			;;;set address exentsion bits
;
;	r0 now has interrupt enable, function bits, address extension bits
;	attention bits all set
        bis	#qaie,r0			;;;interrupt enable
	mov	r0,drcsr(r2)			;;;set bits, let settle
	bis	#QAgo,r0			;;;set go and interrupt bits, 
        bitb	#io.sto,i.fcn(r1)		;;;new time out ? /02/
        bne	55$				;;; ne yes /02/
	movb	s.itm(r4),s.ctm(r4)		;;;set timeout to initial value
        br 	60$				;;;go on
55$:	movb	i.prm+10(r1),s.ctm(r4)		;;; set time out /02/
60$:	mov	#qaexp,u.exp(r5)		;;;flag interrupt expected
	mov	r0,drcsr(r2)			;;;set bits + go bit
        enabl
;
QACAN:						;CANCEL ENTRY
;
QAPWF:						;POWER FAIL IS RETURN
QARET:	RETURN					;go back to caller
;
;		INTERRUPT ENTRY POINT
$QAINT::
	intsv$	QA,pr5,Q$$A11,,			;;;load r5 with ucb address
        mov 	r4,-(sp)			;;;save r4
	mov	u.scb(r5),r4			;;;get scb
	mov	s.csr(r4),r4			;;;get register base for csr
;;;	we now get all register into ucb before clean up
        .if ne okdma
        mov	drwcr(r4),u.wcr(r5)		;;;save wcr
        .iif df deb,mov	drbar(r4),u.bar(r5)		;;;save bar
        .iff
        mov	dridr(r4),u.idr(r5)		;;;idr        
        .endc
        tst	drcsr(r4)			;;;error bit set
        bmi	errqa				;;;minus  yes
        mov	drcsr(r4),u.csr(r5)		;;;save csr
        br	qafork				;;;don't need eir
errqa::	mov	drcsr(r4),u.eir(r5)		;;;save eir
        bic	#qaerr,drcsr(r4)		;;;clear error bit
        mov	drcsr(r4),u.csr(r5)		;;;save csr
qafork: mov	(sp)+,r4			;;;restore r4
        tst	u.exp(r5)			;;;interrupt expected?
        bne	qaok				;;;if ne, yes
        return
qaok:   clr	u.exp(r5)			;;;clear expected interrupt
	call	$fork				;lower priority
	mov	u.cnt(r5),r1			;get byte count
	clc					;set up for word count
	ror	r1				;word count in r1
	add	u.wcr(r5),r1			;compute actuall transfer 
       						;count
	asl	r1				;back to byte count
	mov	#is.suc&377,r0			;indicate success

QAdone:
	call	$iodon				;indicate completion
	JMP 	QAINI				;get next operation
      
;	miscellaneous entry points
;
QAout:						;timeout entry
	mov	s.csr(r4),r2			;;;
	mov	drcsr(r2),u.csr(r5)		;;;get csr
	clr	drcsr(r2)			;;;clear csr
        clr	u.exp(r5)			;;;clear interrupt expected 
	mtps	#0				;enable intterupts
QAdnr:	mov	#ie.tmo,r0			;set not ready code
	mov	u.csr(r5),r1			;csr as iosb+2
	br	QAdone				;go back to caller
      .end
