 lib environment
 lib bfhdr
 lib dtab
 lib macdefs
 data
 sttl Floppy Disk Drivers (DMF3)
 pag
 name dmf3drvr
 global dmf3opn,dmf3cls,dmf3io,dmf3int
 global fchop,fchcl,fchsp,fchio,fchrd,fchwr
 global fchgb,fchcn2,frechbf

*
* This file contains the drivers for the SWTPC
* DMF3 dual density floppy disk controller.
*
*
* driver constants
*
 info ***************************
 info *                         *
 info *  SPECIAL TEST VERSION   *
 info *  NOT FOR RELEASE        *
 info *  SWTPc - Walter Butler  *
 info *  12/18/85               *
 info *                         *
 info ***************************
SECLEN equ 512  sector length
RWOK equ %11011000 read write status mask
RNFD equ %00010000 record not found error
MAXTRK equ 76 maximum track number allowed
RDCMND equ $88 read block command
WTCMND equ $A8 write block command
DWTCMD equ $AC write block with head settle
SKCMND equ $18 seek command
RSCMND equ $08 restore command
WTTCMD equ $F4 write track command
FICMND equ $D0 force interrupt command
RDMSCM equ $98 read multiple command (swap in)
WTMSCM equ $B8 write multiple command (swap out)
DWTMSC equ $BC write multiple with head settle
SIDE1  equ $02 side 1 in read/write commands
BLKOPF equ 1 block open bit flag
CHROPF equ 2 character open bit flag


BDATA  equ 0 via b side data register offset
DDB    equ 2 via b side data direction register
PCR    equ 12 via peripheral control register
IER    equ 14 via interrupt enable register
IFR    equ 13 via interrupt flag register

 pag

*
* driver variable storage
*

dmf3drv fcb 0 current drive selected
dmf3hdr fcb 1 hardware compat drive number
dmf3trk fdb 0,0 track table
dmf3sts fdb 0,0 side table
dmf3std fdb 0,0 density table
dmf3den fcb 0 density flag
dmf3sid fcb 0 side flag
cmd_side fcb 0 side bit in WD command
dmasd fcb 0 current side select
dmf3tmp fdb 0 temp space for open
dmswop fcb 0 swap operation (read or write)
dmswdr fcb 0 swap direction for controller
dmswpt fdb 0 swap table pointer
dmf3skf fcb 0 seek flag
dmf3opt fdb 0,0 dmf3 open table
BDtable fdb 0 Block Device Table address
did_write fcb 0 Last I/O operation was a write
last_driv fcb 0 Last partial pattern to ds latch
wd_cnt fcb 0 wait for drive ready counter
WD_MAX equ 10 Number of 0.5 second time-outs

 pag

*
* dmf3opn
*
* Open DMF3 device.  This guy reads in the sir
* block (1) and sets up the density and side info.
*

dmf3opn
 pshs d save device number
 lda #BLKOPF set and check open table
 lbsr setopen
 bne dmf3op3 if already open, do nothing
dmf3op2 ldd 0,s reset device number
 jsr fchopn do char open stuff
 ldd 0,s get dev number
 bsr dmf3rbo read block one (sir)
 beq dmf3op4 error?
 clr uerror reset error status
 jsr freebf free the buffer
 ldx #dmf3std point to density table
 ldd 0,s get device number
 subb #DMF3minor compute relative drive #
 inc b,x set to double density
 ldd 0,s restore device number
 bsr dmf3rbo read sir again
 beq dmf3op4 error?
 lda #EIO set io error
 sta uerror
 lbsr freebf free the buffer
 ldx #dmf3opt point to open table
 ldd 0,s get device number
 subb #DMF3minor compute relative drive #
 clr b,x clear status
dmf3op3 puls d,pc return
dmf3op4 pshs y save buffer
 ldx 0,s get buffer
 ldy #dmf3tmp point to data block
 ldu #sdenf set density offset in sir
 ldd #2 set byte count to 2
 jsr cpybts get density & side info
 ldd 2,s get device number
 subb #DMF3minor compute relative drive #
 ldx #dmf3sts point to side table
 lda dmf3tmp+1 get side data
 sta b,x set in table
 leax 4,x bump to density table
 lda dmf3tmp get density info
 sta b,x set in table
 puls y get buffer
 jsr freebf free the buffer
 puls d,pc return

*
* read sir
*

dmf3rbo ldx #1 set block 1
 ldy #0
 lda #DMF3major
 jsr rdbuf read in the block
 lda bfflag,y get flags
 bita #BFERR error?
 rts return

*
* dmf3cls
*
* Close DMF3 device.  Nothing to do right now.
*

dmf3cls lda #BLKOPF indicate "character device close"
devcls subb #DMF3minor compute relative drive #
 coma negate the mask
 ldx #dmf3opt point to open table
 anda b,x clear open flag
 sta b,x update flag byte
dmf3cl2 rts return

 pag

*
* dmf3io
*
* Start dmaf3 executing a requested operation.
*

dmf3io stx BDtable save Block Device Table address
dmf3io2 inc dmf3dt+dtbusy set busy status
 lda bfdvn+1,y get device number
 clrb
 suba #DMF3minor compute relative device #
 cmpa dmf3drv is it the current drive?
 bne dmf3cd if not - change drives
 ldx #dmf3sts point to side table
 leax a,x point to entry
 lda 0,x get side
 sta dmf3sid set flag
 lda 4,x get density
 sta dmf3den set flag
 bra dmf3sk go seek

 pag

*
* dmf3cd
*
* Change drives.  Select the drive specified in
* the A accumulator.  This routine is entered by
* falling through from above.
*

dmf3cd bsr dmf3ftr find the track number
 sta dmf3drv save the drive number
 ldb DMF3TRK get track from wd
 stb 0,x save in table
 bsr dmf3ftr find entry
 ldb 0,x get old track number
 stb DMF3TRK set into wd
 ldb 4,x get side info
 stb dmf3sid
 ldb 8,x get density info
 stb dmf3den
 ldb #1 calculate hardware drive spec
 tsta
 beq dmf3cd4
dmf3cd2 aslb raise dr to power
 deca
 bne dmf3cd2
dmf3cd4 stb dmf3hdr save hardware drive number
 ldd #20 delay some here
dmf3cd5 subd #1 before drive change
 bne dmf3cd5
 ldb dmf3hdr reset drive number
* tst dmf3den
* bne dmf3cd6
* orb #%00100000
*dmf3cd6
 lbsr drvb
 tst hld_toggle reset head load timer in WD chip
 bra dmf3sk go do seek

*
* dmf3ftr
*
* Find old value of the track register in wd.
* Also set the new value since changing drives.
*

dmf3ftr ldx #dmf3trk point to track table
 ldb dmf3drv get drive number
 abx point to entry
 rts return

 pag

*
* dmf3sk
*
* Seek the head to the desired track.  Calculate
* the track and sector numbers from the block
* number passed in the transaction record.  The
* track is blkno>>3, and the sector is (blkno&3)+1.
* This is step one of the drivers and is indicated
* by the dtbusy flag set to 1.
*

dmf3sk
 clrb set status
 tst bfblch,y check high block number
 lbne dmf3er2 show error if set
 ldd bfxfc,y get xfr count
 cmpd #512 doing block transfer?
 beq dmf3sk2
 cmpd #16 is it a swap?
 lbhi dmcsk if not - do character
dmf3sk2 ldd bfblck,y get low block number
 tst dmf3den double density?
 bne dmf3dd if so - go handle it
 pshs b
 lsra divide by 8
 rorb which is sectors per track
 lsra
 rorb
 lsra
 rorb all done now
 tsta check track too big
 beq dmf3sk3
 puls b clean up stack
 bra dmf3sk8 go report error
dmf3sk3 tfr b,a put track number in a
 puls b get original
 andb #7 mask sector number
 incb adjust (no sector 0)
 clr dmasd clear side flag
 tst dmf3sid is this drive double sided?
 beq dmf3sk4
 lsra adjust track number
 bcc dmf3sk4 switch sides?
* added to support OMTI double sided disks (WLB)
* bit 1 of dmf3sid set means OMTI
 pshs a
 lda dmf3sid
 bita #$02
 bne omti1
 addb #8 adjust sector for 2nd side
omti1
 inc dmasd set side 2 flag
 puls a
dmf3sk4 cmpa #MAXTRK is it in range?
 bhi dmf3sk8 if not - error
 clr dmf3skf clear seek flag
 bsr dmf3sd do side and density setting
 tst DMF3COM check for 'ready'
 lbmi dmf3wd if not, go wait
 cmpa DMF3TRK same track as before?
 lbeq dmf3rw if so, skip seek
 sta DMF3DAT set track number in wd
 mul delay some
 mul delay some more
 tst did_write just do a write?
 beq nnn
 bsr wait_wrt
nnn lda #0 long way for delay!
 sta DMF3LAT enable interrupts
 lda #SKCMND set up seek command
 ora FD_SRT set up seek rate
 sta DMF3COM send to wd command register
 inc dmf3skf set seek flag
 rts return
dmf3sk8 clrb set status
 lbra dmf3er2 report error

 pag

*
* dmf3dd
*
* Do seek calculations for double density disk.
* Same as above, except 15 sectors per track.
*

dmf3dd pshs b save low byte block number
 lsra divide block number by 16
 rorb by shifting 4 times
 lsra
 rorb
 lsra
 rorb
 lsra
 rorb
 tsta in range?
 beq dmf3dd2
 puls b clean stack
 bra dmf3sk8 report error
dmf3dd2 tfr b,a put track in a
 puls b
 andb #$f get remainder
 incb adjust sector by 1 (no sec 0)
 clr dmasd reset side status
 tst dmf3sid double sided disk?
 beq dmf3sk4
 lsra adjust track count
 bcc dmf3sk4 on to side 2?
* added to support OMTI double sided disks (WLB)
* bit 1 of dmf3sid set means OMTI
 pshs a
 lda dmf3sid
 bita #$02
 bne omti1
 addb #16 adjust sector for 2nd side
 bra omti1

 pag

*
* dmf3sd
*
* Do density and side select.  Also set sector in B.
*

dmf3sd stb DMF3SEC set in wd
 clr cmd_side assume command side 0
 ldb dmf3hdr get drive number
 orb #$80 set for controller
 tst dmasd set 2nd side?
 beq dmf3sd2
 orb #$10 set 2nd side
 pshs a save register
 lda dmf3sid get side flags
 bita #$10 side bits valid on disk?
 beq 10f no - jump
 lda #SIDE1 yes - must set bit in command byte
 sta cmd_side
10 puls a restore register
dmf3sd2 tst dmf3den double density?
 bne dmf3sd4
 orb #$20 set single density
dmf3sd4 lbsr drvb
 rts return

*
* wait_wrt
*
* Last I/O operation was a write and now the state
* of the drive must change in some way:
*  1) Change drives
*  2) Change tracks
*  3) Change sides
* If any of these take place, we must be assured that
* at least 590 us have elapsed since the I/O completion
* interrupt.
*
wait_wrt pshs d,x save registers
 clr did_write clear flag
 ldx #167 do a little counting
10 leax -1,x
 bne 10b
99 puls d,x,pc return

 pag
*
* dmcsk
*
* Do character device type seek.  If sector
* oriented (xfrc=128, 256, or 1024), then bfblck has
* track and sector.  If track oriented then
* bfblck has track<<1 with low bit being the
* side select bit.
*

dmcsk cmpd #1024 check count
 bhi dmcsk4 >1024 xfr count
 beq useden
 tst bfblck,y get track number
 bne useden
 clr dmf3den single density for trk zero
useden clr dmasd set side zero
* tst dmf3sid check if possible side 1
* beq dmcsk2
 cmpd #128 check for IBM format
 beq isIBM
 cmpd #1024 check for IBM S38
 beq isS38
 lda #15 set SD changover
 tst dmf3den
 beq doscmp
isIBM lda #26 set DD changover
 bra doscmp
isS38 lda #4
 tst dmf3den check dden
 beq doscmp
 asla
doscmp ldb bfblck+1,y get sector number
 bmi expsid
 pshs a push breakover
 subb 0,s+
 bls dmcsk2 on size zero
 lda dmf3sid
 bita #$20 check separate sides
 beq ssoflg
expsid andb #$7F strip high bit
 stb bfblck+1,y
ssoflg inc dmasd
dmcsk2 ldd bfblck,y get track & sector
dmcsk6 jmp dmf3sk4

* track oriented seek

dmcsk4 clr dmf3den clear density
 clr dmasd clear side flag
 cmpd #10200 double density count?
 blo dmcsk5
 inc dmf3den set double density flag
dmcsk5 lda bfblck+1,y get track number
 ldb #1 set bogus sector
 lsra strip off side bit
 bcc dmcsk6 if side zero, do seek
 inc dmasd set side 2
 bra dmcsk6

 pag

*
* dmf3rw
*
* Read write routine for DMF3.  By the time
* control has gotten here, a successful seek
* has been performed.
*

dmf3rw inc dmf3dt+dtbusy set to next mode of busy (r/w)
dmf3rw2 ldd bfxfc,y get transfer count
 cmpd #16 is it a swap?
 lbls dmswp if so - go do it
 lda bfflag,y get buffer flags
 bita #BFSPC special i/o?
 bne dmf3wtt
 bita #BFRWF are we reading?
 beq dmf3wt go do write

*
* dmf3rd
*
* Do dmaf read.  Read 512 bytes bytes into the buffer
* specified by y.
*

dmf3rd ldb #$00 set status for CCR
 bsr dmf3cn configure controller
 clr dmf3skf reset seek flag
 lda #RDCMND set up read command
 stb DMF3PRI set priority register
 ora cmd_side set side bit as needed
 sta DMF3COM set command
 rts return

*
* dmf3wt
*
* Do dmaf write.  Write 512 bytes to disk from the
* buffer pointed to by y.
*

dmf3wt ldb #$01 set status for CCR
 bsr dmf3cn configure controller
 lda #WTCMND set up command
 tst dmf3skf did we seek?
 beq dmf3wt2
 clr dmf3skf reset flag
 lda #DWTCMD use head settle write
dmf3wt2 stb DMF3PRI set priority
 ora cmd_side set side flag as appropriate
 sta DMF3COM set command
 sta did_write set 'just did a write' flag
 rts return

 pag
*
* dmf3wtt
*
* Do dma write track.
*

dmf3wtt ldb #$01 set status for CCR
 bsr dmf3cn configure dma controller
 clr dmf3skf reset seek flag
 lda #WTTCMD set up command
 bra dmf3wt2

*
* dmf3cn
*
* Configure the dmaf controller.  Essentially all
* that is done is setting up the dma count and
* address registers.
*

dmf3cn pshs b save status
 lda bfxadr,y get extended part of address
 anda #$0f mask bottom half
 sta DMF3LAT set address latch
 ldd bfadr,y get low 16 bits of address
 std DMF3ADR set address register
 ldd bfxfc,y  get byte count
 std DMF3CNT set counter register
 puls b restore status for CCR
 stb DMF3CCR
 ldb #8 set four channel DMA mode
 stb DMF3INT+1
 ldb #$01 set status
 stb DMF3INT enable ints
 rts return


*
* dmf3rs
*
* Restore drive to track zero.  This is done every-
* time a record not found error is detected.  The
* busy status is set to 3 which the interrupt handler
* recognizes as a reseek attempt and will re-issue
* the requested operation.
*

dmf3rs ldb dmf3dt+dtbusy get status
 cmpb #4 swapping?
 beq dmf3rs2
dmf3rs1 ldb #3 set busy status to 3
 stb dmf3dt+dtbusy
 lda #RSCMND get restore command
 ora FD_SRT set up seek rate
 sta DMF3COM send to controller
 rts return
dmf3rs2 ldx dmswpt get swap pointer
 leax -1,x back it up
 stx dmswpt save new
 stx bfadr,y
 bra dmf3rs1 go restore
 pag

*
* dmf3int
*
* Interrupt entry for disk drivers.  There are two
* possible entry times.  If 'dtbusy' is 1, then
* the controller has just finished a seek operation.
* If it is 2, we have just finished a read or write.
*

dmf3int
 ldy dmf3dt+dtqfl get current transaction
 beq dmf3int0 jump if nothing happening
 lda bfdvn+1,y get minor device #
 cmpa #DMF3minor check legal range
 blo dmf3int0
 cmpa #DMF3minor+3
 bhi dmf3int0
 bra dmf3in2 go process interrupt
dmf3int0 ldb DMF3COM reset hardware interrupt
dmf3in1 rts and return
dmf3in2 lda dmf3dt+dtbusy get busy status
 cmpa #4 were we swapping?
 bne dmf3in3
 ldb DMF3COM get status
 rorb get 'busy' bit
 bcc dmf3i25
 ldb #FICMND force interrupt to WD
 stb DMF3COM
 ldx #32 wait for command completion
dmf3in21 leax -1,x
 bne dmf3in21
dmf3i25 ldy dmf3dt+dtqfl get buffer header
 bra dmf3i35
dmf3in3 ldb DMF3COM check if busy
 rorb get busy into carry
 bcs dmf3in1
 ldy dmf3dt+dtqfl get first transaction
 ldb DMF3COM clear interrupt status
dmf3i35 cmpa #1 were we seeking?
 lbeq dmf3rw if so, now go read/write
 cmpa #3 were we reseeking?
 bne dmf3in4
 clr dmf3dt+dtbusy clear out for retry
 lbra dmf3io2 start all over
dmf3in4 ldd #$0000 clear dma
 std DMF3PRI
 ldb DMF3COM get status
 bitb #RWOK any errors?
 bne dmf3er
 ldb dmf3dt+dtbusy get status
 cmpb #4 are we swapping
 lbeq dswpdo go do swap
dmf3in6 clr dmf3dt+dtbusy clear busy status
 clr dmf3dt+dtrtry clear error count
 ldx BDtable restore Block Device Table address
 jmp BDioend end of I/O operation


 pag

*
* dmf3er
*
* Handle an error from the controller.  If the
* error count is not max value, bump the count
* and try again.
*

dmf3er lda dmf3dt+dtrtry get error count
 cmpa #8 is it max?
 bhs dmf3er2
 bitb #RNFD is it 'record not found'?
 bne dmf3er1
 inc dmf3dt+dtrtry bump the error count
 cmpa #4 should we reseek?
 lbeq dmf3rs if so, call restore
 lda dmf3dt+dtbusy get status
 cmpa #4 are we swapping?
 lbne dmf3rw2 if not - repeat r/w op
 ldx dmswpt get swap table ptr
 lda -1,x get last segment tried
 lbra dswpd2 go retry swap
dmf3er1 adda #4 bump retry by 4
 sta dmf3dt+dtrtry so do this max of 4 times!
 lbra dmf3rs go restore
dmf3er2 stb bfstat,y save status
 lda #FICMND do force int command
 sta DMF3COM send do wd chip
 pshs b keep the b register????
 ldb #$20 clear out the drive select
 lbsr drvb
 puls b
 lda bfflag,y get flags
 ora #BFERR set error status
 sta bfflag,y
 bra dmf3in6

*
* dmf3wd
*
* Wait for drive ready.
*

dmf3wd lda #WD_MAX set up counter
 sta wd_cnt
dmf3wd00 tfr y,x save parameter
 ldb #5 set delay (0.5 seconds)
 ldy #dmf3ch set routine address
 lbsr timout do a timeout
 rts return

*
* dmf3ch
*
* Check if drive is really not ready.
*

dmf3ch tfr x,y get pointer
 ldb DMF3COM get status
 bpl 10f if not busy, go start
 dec wd_cnt tried max times?
 bne dmf3wd00 no - try again
 bra dmf3er2 report error

10 clr dmf3dt+dtbusy clear status
 lbra dmf3io2 go start

*
* setopen - set device open table entry
*
* entry (b) = minor device number
*       (a) = flag for open table
* exit  ne if device already open

setopen subb #DMF3minor determine table offset
 ldx #dmf3opt point to open table
 abx point to entry
 ldb 0,x get original entry
 ora 0,x merge open flag
 sta 0,x update entry
 tstb check original entry
 rts return

*
* swap to DMF3
*

dmswp lda #4 set status to 4
 sta dmf3dt+dtbusy
 ldd bfadr,y get swap table pointer
 std dmswpt save it
 lda bfflag,y check for read or write
 bita #BFRWF
 beq dmswp2 ahead if writing
 ldb #$00 set controller direction
 stb dmswdr
 ldb #RDMSCM setup command
 tst dmf3skf did we seek?
 beq dmswp1
 orb #$04 set head settle bit
dmswp1 stb dmswop
 bra dswpd1 go do swap
dmswp2 ldb #$01 set controller direction
 stb dmswdr
 ldb #WTMSCM setup command
 tst dmf3skf did we seek?
 beq dmswp4
 clr dmf3skf reset seek flag
 ldb #DWTMSC set head settle command
dmswp4 stb dmswop
 stb did_write set 'just did a write' flag
 bra dswpd1 go do swap

*
* dswpdo
*
* Perform a swap operation.
*

dswpdo ldd bfblck,y get block number
 addd #8 advance by 8 blocks (4K a crack)
 std bfblck,y save it
 bcc dswpd0 hit hi byte?
 inc bfblch,y prop cary
dswpd0 clr dmf3dt+dtrtry
 clr dmf3dt+dtbusy
 lda [dmswpt] get next segment
 cmpa DSKTRM end of list?
 lbne dmf3io2 if not - repeat
 jmp dmf3in6 else - exit
dswpd1 ldx dmswpt get swap pointer
 lda 0,x+ get a segment
 stx dmswpt save pointer
 stx bfadr,y
 cmpa DSKTRM end of list?
 lbeq dmf3in6 if so - exit
dswpd2 pshs a save segment
 lsra calc latch value
 lsra
 lsra
 lsra
 sta DMF3LAT set latch
 puls a
 eora DATsense get hi nibble
 asla
 asla
 asla
 asla
 clrb make 16 bits
 std DMF3ADR save as address in dma
 ldd #(512*8) set data count
 std DMF3CNT save in dma
 ldb dmswdr get direction
 stb DMF3CCR
 ldb #$01
 stb DMF3INT set interrupt status
 lda dmswop get operation (r/w)
 stb DMF3PRI prime dma
 ora cmd_side set side bit in command as needed
 sta DMF3COM issue command
 clr dmf3skf reset seek flag
 rts return

* do the actual drive/side select ... delay before if necessary

drvb andb #%00111111 fix up for data sep
 bitb #%00100000 double density?
 beq dpat leave data sep bits alone if so
 orb #%01000000 set sing dens bits
dpat pshs b retain the whole select value
 andb #%00011111 drive sel and side sel only
 cmpb last_driv is the side or drive number changed?
 beq nowr if not, no write delay
 tst did_write last operation a write?
 beq nowr if not, dont delay
 lbsr wait_wrt
nowr stb last_driv keep the new value
 puls b get the whole contents back
 stb DMF3DRV cram the drive/side select register
 rts

 sttl Floppy Disk Character Drivers
 pag

*
* The routines in this file make up the character
* device drivers for the floppy disks.  The driver
* code for the drives is shared by the block device
* drivers.
*

*
* fchop
*
* Character disk open routine.  Device number in D.
*

fchop pshs d save device number
 lda #CHROPF get indicate "character open"
 lbsr setopen check open table
 puls d restore device number
 bne fchop3 if already open
fchopn subb #DMF3minor compute relative drive #
 cmpb #3 check for valid drive number
 bhi fchop4
 ldx #dmf3trk point to track table
 abx point to drives entry
 clr 4,x clear out side info
 clr 8,x clear out density
fchop3 rts

fchop4 lda #EBARG set error
 sta uerror
 rts return


*
* fchcl
*
* Character disk close routine
*

fchcl lda #CHROPF indicate "character device close"
 jmp devcls do dmf3 close

 pag

*
* fchrd
*
* Character read routine for floopy disks.
*

fchrd pshs d save device number
 jsr fchgb get device buffer
 puls d reset device number
 jsr fchcn configure buffer
 tst uerror test for errors
 beq fchrd4
 bsr frechbf release buffer
 rts error return
fchrd4 pshs a save task modes byte
 orb #BFRWF set read status
 stb bfflag,y save in buffer hdr
 bra fchio go do io


*
* fchwr
*
* Character write routine for floppy disks.
*

fchwr pshs d save device number
 bsr fchgb get device buffer
 puls d reset device number
 jsr fchcn configure buffer
 tst uerror check for errors
 beq fchwr4
 bsr frechbf release buffer
 rts error return
fchwr4 pshs a save task mode byte
 bra fchio go do io

*
* frechbf - free Floppy Diskette Character buffer
*
frechbf pshs d,x,y,u save registers
 ldy #fchbuf point to header
 lda bfflag,y get flags
 anda #!(BFALOC|BFREQ|BFSPC)&$ff clear out busy bits
 sta bfflag,y save new flags
 jsr wakbuf awake buffer sleepers
 puls d,x,y,u,pc return

*
* fchsp
*
* Special routine. Returns side as byte 0, density as 1.
*

fchsp tfr x,y save pointer
 ldx #dmf3sts point to side table
 subb #DMF3minor compute relative drive #
 abx point to entry
 cmpy #0 doing set or get?
 bne fchsp4
fchsp2 cmpb dmf3drv current drive?
 beq fchsp6
 ldd usarg0 get arg
 sta 0,x set side
 stb 4,x set density
 rts return
fchsp4 lda 0,x get side
 ldb 4,x get density
 std 0,y save in buffer
 rts return
fchsp6 ldd usarg0 get arg
 sta 0,x set side
 stb 4,x set density
 sta dmf3sid set current side
 stb dmf3den set current density
 rts return

 pag

*
* fchio
*
* Perform the io specified by the buffer header
* pointed at by Y.  ** This routine assumes the
* floppy disks are major device 0 for the block
* type drivers **
*

fchio pshs y save buffer
 ldx #blktab Major Device 0
 jsr [blkio,x] call block io routine
 ldy 0,s reset buffer
 jsr fnshio finish io
 jsr wakbuf awakeb buffer sleepers
 puls y reset ptr
 lda bfflag,y get flags
 anda #!(BFALOC|BFREQ|BFSPC)&$ff clear out busy bits
 sta bfflag,y save new flags
 puls a get task modes
 ldx utask get task entry location
 sta tsmode,x save task modes
 clra -- ldd #0 reset data count to 0
 clrb
 std uicnt
fchio6 rts return


*
* fchgb
*
* Get the character buffer header.  If it is busy,
* sleep on it.
*

fchgb ldy #fchbuf point to header
 pshs cc save status
 seti
 lda bfflag,y get buffer flags
 bita #BFALOC is buffer busy?
 beq fchgb2
 ora #BFREQ set request buffer bit
 sta bfflag,y
 puls cc reset status
 ldb #BUFPR set priority
 jsr sleep go sleep for buffer
 bra fchgb repeat
fchgb2 lda #BFALOC set busy status
 sta bfflag,y
 puls cc,pc return

 pag

*
* fchcn
*
* Configure the buffer header pointed at by Y.
* This routine sets up the character device info
* from the user block and puts it in the buffer
* header such that the device drivers can use
* the information for the data transfer.
*

fchcn std bfdvn,y save device number
 ldd uicnt get xfr count
 std bfxfc,y save in header
 cmpd #128 check for valid number
 beq fchcn4
 cmpd #256 is it a sector operation?
 beq fchcn4
 cmpd #512 is it 512 byte op?
 beq fchcn4
 cmpd #1024 is it 1024 byte op
 beq fchcn4
 cmpd #5100 is it a write track?
 beq fchcn2
 cmpd #10200 is it dd write track?
 bne fchcn8 if not - error
fchcn2 lda bfflag,y get flags
 ora #BFSPC set special bit for drivers
 sta bfflag,y save new flags
fchcn4 ldd uipos2 get file position
 std bfblck,y save as block number
 lda uipos+1 store upper part
 sta bfblch,y
 ldd uistrt get start address of xfr
 std bfadr,y save in header
 jsr mapupg find user page
 std bfxadr,y save in header
 ldx utask point to task entry
 lda tsmode,x get mode bits
 pshs a save
 ora #TLOCK set lock bit (keep in mem)
 sta tsmode,x save new mode
 ldb bfflag,y get flags
 puls a,pc return
fchcn8 lda #EBARG set error
 sta uerror
 rts return
