.include "pdlequ.h"

*
*       DEFINITIONS
*
dmadata equ     $ffff8604       ; /* dma control and status register */
dmahigh equ     $ffff8609       ; /* dma counter high */
dmamid  equ     $ffff860b       ; /* dma counter mid */
dmalow  equ     $ffff860d       ; /* dma counter low */
gpip    equ     $fffffa01       ; /* mfp general purpose i/o */
flock   equ     $43e            ; /* dma lock semaphore */
_hz_200 equ     $4ba            ; /* 200 hz timer */

*
* SLM804 print driver
*
CR	equ	$d
LF	equ	$a
FF	equ	$c
ESC	equ	$1b
DC2	equ	$12

	.text
***************************************************************
***************************************************************
***************************************************************
dumbentry:
	clr.l	d0
	rts

	dc.l	"PRNT"
	dc.w	201

*
* distribute the calls to the appropriate routines
*
slm804:	move.l	a0,table
	lsl.w	#2,d0
	lea	prntbl,a1
	move.l	0(a1,d0.w),a1
	jmp	(a1)


*
* identify who I am, and set up who I like to speak to.
*
p_ident:
	move.l	#driver,pdrvrnm(a0)	;pointer to string for driver name
	move.w	#$8000+PRT+ASCENDING,device(a0)
prtok:	moveq	#1,d0
rrts:	rts
rterr:	moveq	#0,d1
	rts
*
* initialize the table of printer specific routines
*
p_init:	clr.b	pdl(a0)			;not a page description language driver
	move.b	#1,pmult(a0)		;automatically print mulitiple copies?
	clr.b	pman(a0)		;handle manual feed?
	move.b	#PRT_BW,ptype(a0)	;printer type?

*
* pminlft and pmaxw must be evenly divisible by 16
*

	move.w	pdensity(a0),d0
	cmp.w	#7,d0
	bcs	pint1
	moveq	#6,d0
pint1:	lsl.w	#1,d0

	lea	scl_tbl,a1
	move.w	0(a1,d0.w),scale
	lea	xdpi_tbl,a1
	move.w	0(a1,d0.w),pxdpi(a0)	;x resolution
	lea	ydpi_tbl,a1
	move.w	0(a1,d0.w),pydpi(a0)	;y resolution
	lea	minl_tbl,a1
	move.w	0(a1,d0.w),pminlft(a0)	;pixels from the left
	lea	minr_tbl,a1
	move.w	0(a1,d0.w),pminrht(a0)	;pixels from the right
	lea	mint_tbl,a1
	move.w	0(a1,d0.w),pmintop(a0)	;pixels down from top
	lea	minb_tbl,a1
	move.w	0(a1,d0.w),pminbot(a0)	;pixels up from bottom
	lea	xover_tbl,a1
	move.w	0(a1,d0.w),pxover(a0)	;percentage of x overlap of dots
	lea	yover_tbl,a1
	move.w	0(a1,d0.w),pyover(a0)	;percentage of y overlap of dots
	lea	rowht_tbl,a1
	move.w	0(a1,d0.w),prowht(a0)	;rows height modula

	lsl.w	#1,d0
	lea	maxw_tbl,a1
	move.l	0(a1,d0.w),pmaxw(a0)	;maximum # pixels across
	lea	maxh_tbl,a1
	move.l	0(a1,d0.w),pmaxh(a0)	;maximum # pixels down
	bra	prtok

*
* going to begin printing a document
*
p_bgndoc:
	bra	prtok

*
* about to start printing of a page
*
p_bgnpage:
	bra	prtok

*
* about to print a new tile for the page
*
p_bgntile:
	bra	prtok

*
* print a block to the printer
*
p_block:
	move.l	m_alloc(a0),a0
	move.l	#40000,d0
	moveq	#0,d1
	jsr	(a0)
	beq	rrts
	move.l	a0,p1handle

	move.l	table,a0
	move.l	m_alloc(a0),a0
	move.l	#40000,d0
	moveq	#0,d1
	jsr	(a0)
	beq	rrts
	move.l	a0,p2handle

	move.l	(a0),p2ptr
	move.l	p1handle,a0
	move.l	(a0),p1ptr

	move.l	table,a0
	move.l	pblockptr(a0),a1
	move.l	(a1),_page_image
	move.l	pblockw(a0),d0
	move.w	d0,width		;width in bytes
	lsl.w	#3,d0
	move.w	d0,wbits		;width in bits
	move.l	pblockh(a0),d0
	move.w	d0,height		;height
	clr.l	pblockh(a0)

	move.w	pcopies(a0),tcopy

block1:	clr.l	-(sp)
	move.w	#$20,-(sp)		;set supervisor mode
	trap	#1
	addq.l	#6,sp
	move.l	d0,stack

	jsr	_print_page

	move.l	stack,-(sp)
	move.w	#$20,-(sp)		;return to user mode
	trap	#1
	addq.l	#6,sp

	subq.w	#1,tcopy
	bhi	block1

	move.l	table,a1
	move.l	m_delete(a1),a1
	move.l	p1handle,a0
	jsr	(a1)

	move.l	table,a1
	move.l	m_delete(a1),a1
	move.l	p2handle,a0
	jsr	(a1)
	bra	prtok

*
* just finished describing current tile
*
p_endtile:
	bra	prtok

*
* just finished describing all tiles for this page
*
p_endpage:
	bra	prtok

*
* finished printing the document
*
p_enddoc:
	bra	prtok


***************************************************
***	original assumed 300x3180		***
***						***
***************************************************
*
_print_page:
	move.l	p1ptr,a0
	move.w	#9999,d0
pp1:	clr.l	(a0)+
	dbf	d0,pp1

	move.l	p2ptr,a0
	move.w	#9999,d0
pp2:	clr.l	(a0)+
	dbf	d0,pp2

*
*
*
	lea	dmadata,a0	;
	tas.b	flock		; DMA channel currently in use?
	bne	rterr		; --> yes, don't use it right now

	move.l	#$e00000,cntrl

*
* INQUIRY - determine if the printer is happy, and what the controller # is
*
inquiry:
	move.w	#$198,2(a0)	;DMA select?
	move.w	#$88,2(a0)	;assert command signal
	move.l	#$12008a,d0	;MODE SENSE command byte 0
	or.l	cntrl,d0
	jsr	writcmnd	;to controller number (cntrl)
	bne	badinq		;
	move.l	#$00008a,d0	;command byte 1
	jsr	writcmnd	;
	bne	badinq
	move.l	#$00008a,d0	;command byte 2
	jsr	writcmnd	;
	bne	badinq
	move.l	#$00008a,d0	;command byte 3
	jsr	writcmnd	;
	bne	badinq
	move.l	#$00008a,d0	;command byte 4
	jsr	writcmnd	;
	bne	badinq
	move.l	#$800082,d0	;command byte 5
	move.l	d0,(a0)		;no acknowledge for byte 5

	moveq.l	#2,d1		;~ 5 millisecond delay
	add.l	_hz_200,d1	;NB MINIMUM DELAY IS 20 MICROSECONDS
indel:	cmp.l	_hz_200,d1	;
	bge	indel		;

	bsr	getstatus	;status byte- is everybody in?
	bne	badinq

	lea	identlist,a3	;the parade is about to begin...
	bsr	getstatus	;byte 0 - Device Type
	bne	badinq
	move.b	d0,(a3)+
	bsr	getstatus	;byte 1
	bne	badinq
	move.b	d0,(a3)+
	bsr	getstatus	;byte 2
	bne	badinq
	move.b	d0,(a3)+
	bsr	getstatus	;byte 3
	bne	badinq
	move.b	d0,(a3)+
	bsr	getstatus	;byte 4 - String Length
	bne	badinq
	move.b	d0,(a3)+

	moveq	#0,d7
	move.b	d0,d7
	bra	inidl2
inidl1:	bsr	getstatus	;get the next indentification list byte
	bne	badinq
	move.b	d0,(a3)+	;save it in the table
inidl2:	dbf	d7,inidl1	;loop ListLength times

	lea	identlist+5,a3
	cmp.b	#"P",(a3)+
	bne	badinq
	cmp.b	#"A",(a3)+
	bne	badinq
	cmp.b	#"G",(a3)+
	bne	badinq
	cmp.b	#"E",(a3)+
	beq	okinq

badinq:	move.w	#$80,2(a0)
	sub.l	#$200000,cntrl
	bcc	inquiry
	bra	prabrt
*
*  MODE SENSE - get the current print parameters
*
okinq:
	move.w	#$198,2(a0)	;DMA select?
	move.w	#$88,2(a0)	;assert command signal
	move.l	#$1a008a,d0	;MODE SENSE command byte 0
	or.l	cntrl,d0
	jsr	writcmnd	;to controller number n
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 1
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 2
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 3
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 4
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$000082,d0	;command byte 5
	move.l	d0,(a0)		;no acknowledge for byte 5

	moveq.l	#2,d1		;~ 5 millisecond delay
	add.l	_hz_200,d1	;NB MINIMUM DELAY IS 20 MICROSECONDS
msdel:	cmp.l	_hz_200,d1	;
	bge	msdel		;

	bsr	getstatus	;status byte- is everybody in?

	lea	paramlist,a3	;the parade is about to begin...
	bsr	getstatus	;List Length- num of bytes to follow
	move.b	d0,(a3)+
	moveq	#0,d7
	move.b	d0,d7
	bra	gtpml2
gtpml1:	bsr	getstatus	;get the next parameter list byte
	move.b	d0,(a3)+	;save it in the table
gtpml2:	dbf	d7,gtpml1	;loop ListLength times
	move.w	#$80,2(a0)

	move.b	paramlist+3,owidth
	move.b	paramlist+4,owidth+1
	move.w	owidth,d0
	lsr.w	#3,d0
	move.w	d0,owidth
	mulu	#128,d0
	move.l	d0,olength
	add.l	#32,olength
	divu	#512,d0
	addq.w	#1,d0
	swap	d0
	move.w	#$112,d0
	move.l	d0,ocount

*
* setup the new parameters in paramlist to be sent
*
;	move.b	wbits,paramlist+3
;	move.b	wbits+1,paramlist+4
	move.b	height,paramlist+1
	move.b	height+1,paramlist+2

	bclr	#0,paramlist+9
	move.l	table,a1
	tst.b	pmanual(a1)		;handle manual feed?
	beq	notmanual
	bset	#0,paramlist+9		;set manual feed bit
notmanual:

 IF 0
*
*  MODE SELECT - set the print parameters for the printer
*
	move.w	#$198,2(a0)	;DMA select?
	move.w	#$88,2(a0)	;assert command signal
	move.l	#$15008a,d0	;MODE SELECT command byte 0
	or.l	cntrl,d0
	jsr	writcmnd	;to controller number n
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 1
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 2
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 3
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 4
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 5 (was $8a, might be $80 or $82)
	jsr	writcmnd	;
	bne	prabrt		;

	lea	paramlist,a3	;the parade is about to leave...
	moveq	#0,d7
	move.b	(a3)+,d7
	move.w	d7,d0
	bra	ptpml2
ptpml1:	bsr	putstatus	;put the next parameter list byte
	bne	prabrt		;
	move.b	(a3)+,d0	;get next byte from the table
ptpml2:	dbf	d7,ptpml1	;loop ListLength times

	bsr	putstatus
;	swap	d0
;	move.w	#$0082,d0	;was 82-last byte in extended command
;	move.l	d0,(a0)		;no acknowledge for last byte
;	moveq.l	#2,d1		;~ 5 millisecond delay
;	add.l	_hz_200,d1	;NB MINIMUM DELAY IS 20 MICROSECONDS
;sedel:	cmp.l	_hz_200,d1	;
;	bge	sedel		;

	bsr	getstatus	;status byte- is everybody in?
	move.w	#$80,2(a0)

 ENDIF

*
* setup for first DMA cycle
*
	move.w	width,d0	;copy width
	lsr.w	#1,d0
	subq.w	#1,d0
	move.w	d0,cpwdth

	move.l	_page_image,a2	; /* load initial band base */

	move.l	p1ptr,a5
	move.w	#128,d4
cpd1:	move.l	a2,a3		;don't want to advance on second row
	move.l	a5,a4
	move.w	cpwdth,d3
cpd2:	move.w	(a2)+,(a4)+
	dbf	d3,cpd2
	add.w	owidth,a5
;	lea	300(a5),a5	;skip white space (could precalc this)
	dbf	d4,cpd1
	move.l	a3,a2

*
*  COMMAND PHASE
*
	move.w	#$198,2(a0)	;DMA select?
	move.w	#$88,2(a0)	;assert command signal
	move.l	#$0a008a,d0	;PRINT command byte 0
	or.l	cntrl,d0
	jsr	writcmnd	;to controller number n
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 1
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 2
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 3
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$00008a,d0	;command byte 4
	jsr	writcmnd	;
	bne	prabrt		;
	move.l	#$000082,d0	;command byte 5
	move.l	d0,(a0)		;no acknowledge for byte 5
	moveq.l	#2,d1		;~ 5 millisecond delay
	add.l	_hz_200,d1	;NB MINIMUM DELAY IS 20 MICROSECONDS
codel:	cmp.l	_hz_200,d1	;
	bge	codel		;

*
*  DATA OUT PHASE
*
	move.l	p1ptr,d0
	move.l	d0,-(sp)
	move.b	3(sp),dmalow	;initialize dma base address
	move.b	2(sp),dmamid
	move.b	1(sp),dmahigh
	addq.l	#4,sp

	move.w	#$192,2(a0)	;select sector count register
	move.l	ocount,(a0)	;write sector count, start dma

	moveq	#0,d7
	move.w	height,d7
	add.w	#127,d7
	divu	#128,d7
	subq.w	#1,d7
	bra	bottom

bdloop:	add.l	olength,d0	;get final address to stop at
	move.w	sr,d1		; /* save status register */
	ori.w	#$700,sr	; /* no interrupts, please */

	move.l	p2ptr,a5	; swap p1ptr <-> p2ptr
	move.l	p1ptr,p2ptr
	move.l	a5,p1ptr

	move.w	#128,d4
cpd3:	move.l	a2,a3		;don't want to advance on second row
	move.l	a5,a4
	move.w	cpwdth,d3
cpd4:	move.w	(a2)+,(a4)+
	dbf	d3,cpd4
	add.w	owidth,a5
;	lea	300(a5),a5	;skip white space (could precalc this)
	dbf	d4,cpd3
	move.l	a3,a2

bdwait:	btst.b	#5,gpip		;check for premature status phase
	beq	fuckoff		;stwait		;abort and get status byte
	movep.w	7(a0),d2	;get current DMA mid and low
	cmp.w	d2,d0		;compare to final address
	bne	bdwait		;not there yet?

	move.l	p1ptr,d0
	addq.l	#2,d0		;compensate for FIFO
	move.l	d0,-(sp)
	move.b	3(sp),dmalow	;reinitialize DMA base address
	move.b	2(sp),dmamid	;
	move.b	1(sp),dmahigh	;
	addq.l	#4,sp		;
	move.w	#$92,2(a0)	;reset FIFO
	move.w	#$192,2(a0)	;
	move.l	ocount,(a0)	;reload sector count register

	move.w	d1,sr		;restore status register
bottom:	dbra	d7,bdloop	;more bands?

*
*  STATUS PHASE
*
fuckoff:

stwait:	btst.b	#5,gpip		;wait for status byte
	bne	stwait		;
stbyte:	move.w	d1,sr		;restore status register
	move.w	#$8a,2(a0)	;select status register
	move.w	(a0),d0		;read status byte
	moveq.l	#2,d1		;~ 5 millisecond delay
	add.l	_hz_200,d1	;NB MINIMUM DELAY IS 20 MICROSECONDS
stdel:	cmp.l	_hz_200,d1	;
	bge	stdel		;
	bra	prexit		;return status byte
prabrt:	moveq.l	#-1,d0		;return error flag
prexit:	move.w	#$80,2(a0)
	sf	flock		;unlock dma channel
	rts			;



***************************************************
***						***
***************************************************
getstatus:
	moveq.l	#100,d1		;500 millisecond timeout
	add.l	_hz_200,d1	;
gstime:	btst.b	#5,gpip		;
	beq	gsbyte		;command byte acknowledged
	cmp.l	_hz_200,d1	;
	bge	gstime		;
	moveq.l	#-1,d1		;timeout - set error flag
	rts			;

gsbyte:	move.w	#$8a,2(a0)	;select status register
	move.w	(a0),d0		;read status byte
	moveq.l	#2,d1		;~ 5 millisecond delay
	add.l	_hz_200,d1	;NB MINIMUM DELAY IS 20 MICROSECONDS
gsdel:	cmp.l	_hz_200,d1	;
	bge	gsdel		;
	moveq	#0,d1
	rts


***************************************************
***						***
***************************************************
*
*       WRITCMND
*       Write command byte to DMA controller.
*
*       Inputs:         d0.L = Data/control words
*                       a0   = Pointer to DMA controller (ff8604)
*       Outputs:        EQ = Successful command write
*                       NE = Error occurred
*       Modified:       d1
*
putstatus:
	swap	d0
	move.w	#$8a,d0

writcmnd:
	move.l	d0,(a0)		;write command byte
	moveq.l	#2,d1		;~ 5 millisecond delay
	add.l	_hz_200,d1	;NB MINIMUM DELAY IS 20 MICROSECONDS
wrdel:	cmp.l	_hz_200,d1	;
	bge	wrdel		;
	moveq.l	#40,d1		;200 millisecond timeout
	add.l	_hz_200,d1	;
writlp:	btst.b	#5,gpip		;
	beq	writok		;command byte acknowledged
	cmp.l	_hz_200,d1	;
	bge	writlp		;
	moveq.l	#-1,d1		;timeout - set error flag
writok:	rts			;


***********************************
***				***
***********************************
	.data

prntbl:	dc.l	prtok,prtok,prtok,prtok,p_init
	dc.l	p_bgndoc,p_bgnpage,p_bgntile
	dc.l	p_block
	dc.l	p_endtile,p_endpage,p_enddoc
	dc.l	prtok,p_ident

scl_tbl:	dc.w	1,1,1,1,1,1,1
xdpi_tbl:	dc.w	300,300,300,300,300,300,300
ydpi_tbl:	dc.w	300,300,300,300,300,300,300
minl_tbl:	dc.w	75,75,75,75,75,75,75
minr_tbl:	dc.w	75,75,75,75,75,75,75
mint_tbl:	dc.w	56,56,56,56,56,56,56
minb_tbl:	dc.w	56,56,56,56,56,56,56
maxw_tbl:	dc.l	2400,2400,2400,2400,2400,2400,2400
maxh_tbl:	dc.l	0,0,0,0,0,0,0
xover_tbl:	dc.w	0,0,0,0,0,0,0
yover_tbl:	dc.w	0,0,0,0,0,0,0
rowht_tbl:	dc.w	1,1,1,1,1,1,1

driver:	dc.b	"Atari SLM804 v2.0.3-3",0

	.bss
temp:		ds.l	1
tcopy:		ds.w	1
scale:		ds.w	1
_page_image:	ds.l	1
stack:		ds.l	1
height:		ds.w	1
width:		ds.w	1
wbits:		ds.w	1
owidth:		ds.w	1
olength:	ds.l	1
ocount:		ds.l	1

table:		ds.l	1
cpwdth:		ds.w	1
cntrl:		ds.l	1

paramlist:	ds.b	50
identlist:	ds.b	50

p1handle:	ds.l	1
p1ptr:		ds.l	1
p2handle:	ds.l	1
p2ptr:		ds.l	1

;
; 2.0.1 - added support for manual feed
; 2.0.2 - changed timing
;         added support for variable length bitmaps
;         removed 75,100,& 150 dpi options (they didn't do anything)
