; IDE Device read/write-routines     version 1.01 November 1996

; parameters for Conner Peripherals CP3044 (40 MB) 
SECTORS_PER_TRACK equ 40
HEADS equ 4
; find parameters for your drive (from drive manual) and change accordingly


;; interrupt routines do not work, don't use them

   xref  _LVOAllocSignal
   xref  _LVOSignal
   xref  _LVOWait
   xref  _LVOFindTask
   xref  _LVOAddIntServer

   include "atid600.i"  ;
;   include     "exec/types.i"
   include     "exec/io.i"
   include     "exec/devices.i"
   include     "exec/errors.i"
   include "hardware/intbits.i"
;   include     "exec/tasks.i"
;   include     "exec/interrupts.i
;   include     "devices/scsidisk.i"
;   include     "mydev.i"
;   include     "scsi.i"
   Public      ATIDRdWt

ATIDRdWt:
   ;a0 io data address
   ;a1 iob 
   ;a2 == a1
   ;d0 io length
   ;d1 io offset
   ;d2 unit number
   move.b   #8+nIEN,TF_DEVICE_CONTROL; no interupts ;nIEN=2
   move.b   TF_STATUS,d3   ;clear interrupt line
   movem.l  d1-d7/a0-a6,-(sp)
   move.l   d0,d3
   move.l   d0,a3
   move.l   #IOERR_UNITBUSY,d0
   cmp.l    #0,d2
   bne      Quits
   move.l   #IOERR_BADLENGTH,d0
   move.l   d3,d4
   and.l    #$1ff,d4
   bne      Quits
   lsr.l    #8,d3
   lsr.l    #1,d3; number of sectors
   move.l   #IOERR_BADLENGTH,d0
   cmp.l    #0,d3
   beq      Quits
   lsr.l    #8,d1
   lsr.l    #1,d1; start block
   move.l   a0,a5
   move.l   d1,d6
   move.l   d3,d7
   cmp.l    #0,interruptserverinstalled
   bne      alreadyinstalled
   bsr      installinterruptserver
   cmp.l    #0,d0
   bne      Quits
alreadyinstalled
   bsr      doblocks
Quits
   cmp.l    #0,d0
   beq      okcode
   bset.b   #1,$bfe001;led off
okcode
   movem.l  (sp)+,d1-d7/a0-a6
   rts

LBASELECTED equ 0 ;; Logical Block Addressing - mode
CHSSELECTED equ 1
LBAorCHS dc.l  CHSSELECTED;LBASELECTED

interruptserverinstalled dc.l 0

installinterruptserver
   movem.l  d1/a0-a1,-(sp)
   move.l   #-1,d0 ;any signalbit
   move.l   4,a6
   jsr      _LVOAllocSignal(a6)
   cmp.l    #-1,d0 ;no signalbit
   bne      oosb
   move.l   #12,d0;error
   movem.l  (sp)+,d1/a0-a1
   rts
oosb
   move.l   #0,d1
   bset.l   d0,d1
   move.l   d1,signalmask
   move.l   #0,a1
   move.l   4,a6
   jsr      _LVOFindTask(a6)
   move.l   d0,the_task
   move.w   #0,enableflag
   lea      interruptserver,a0
   move.l   a0,is_code
   lea      interruptserverdata,a0
   move.l   a0,is_data
   ;nimi yms. (node-struc)
   lea.l    interruptname,a0
   move.l   a0,is_node_ln_namepointer
;  INTB_EXTER equ 13
;  INTB_PORTS equ 3
   move.l   #INTB_PORTS,d0
   lea      interruptstructure,a1
   move.l   4,a6
   jsr      _LVOAddIntServer(a6)
   move.l   #1,interruptserverinstalled
   move.l   #0,d0 ;0=okay
   movem.l  (sp)+,d1/a0-a1
   rts

signalmask  ds.l  1

the_task    ds.l  1

interruptstructure
is_node  ;node_structure
is_node_ln_succ dc.l 0
is_node_ln_pred dc.l 0
is_node_ln_type      dc.b  NT_INTERRUPT;=2
is_node_ln_priority  dc.b  20
is_node_ln_namepointer  ds.l  1
is_data  ds.l  1; data
is_code  ds.l  1; code

interruptname dc.b  "IDE-interrupt-server",0,0

interruptserverdata
enableflag  dc.w  0

interruptserver
;   move.b   TF_STATUS,d0   ;clears drive interrupt line
   cmp.w    #0,(a1)  ;a1=interruptserverdata=enableflag
   bne      cinb     ;jos <>0 niin tutkitaan signalloidaanko
   rts      ;Zero-lippu asettunut , seuraavat serverit jatkaa
cinb
   move.w   #0,(a1)  ;a1=interruptserverdata=enableflag
   move.b   TF_STATUS,d0   ;clears drive interrupt line
   and.b    #BSY,d0
   beq      olipsdjia
   moveq    #0,d0
   rts      ;Zero-lippu asettunut , seuraavat serverit jatkaa
olipsdjia   ;annetaan signaali
   move.l   the_task,a1 ;signalloitava taski
   move.l   signalmask,d0
   move.l   4,a6
   jsr      _LVOSignal(a6)
   moveq    #0,d0
;   moveq    #1,d0 ;Zero-lippu nollaksi, muut serverit ei jatka
   rts

doblocks ;d7=sectors>0
domore
   move.l   d7,d5
   move.l   d7,d4
   and.l    #$ff,d5
   bne      olivalilla1viiva255
   move.l   #$100,d5 ;256 sektoria
olivalilla1viiva255
   move.l   d5,d4 ;d4 antoparametri ;d5 sektoreiden lkm tällä kierroksella
   cmp.w    #CMD_READ,IO_COMMAND(a2)
   beq      wasread
   bsr      writesectors
   cmp.l    #0,d0       ;format or write
   beq      sectoracok
   rts
wasread
   bsr      readsectors
   cmp.l    #0,d0
   beq      sectoracok
   rts
sectoracok
   add.l    d5,d6 ;next block number
   sub.l    d5,d7
   bne      domore
   move.l   #0,d0
   rts

readsectors
   move.l   d6,d0
   bsr      issueread
   cmp.l    #0,d0
   bne      rsfl
readnextblk
   bsr      waitinterrupt
   bsr      waitDRQ  
   cmp.l    #0,d0
   bne      rsfl
   bsr      readdata
   cmp.l    #0,d0
   bne      rsfl
   bsr      waitready
   cmp.l    #0,d0
   bne      rsfl
   sub.l    #1,d4
   bne      readnextblk
   move.l   #0,d0
   rts
rsfl
   rts

writesectors
   move.l   d6,d0
   ;d4==sektoreita 1-256, arvo long alin 8bit. miiningful issuewritelle
   ;max d4=$100=256, min d4=1;
   bsr      issuewrite
   cmp.l    #0,d0
   bne      wekfha
writenextoneblockki
   bsr      waitDRQ  ;nopeahko
   cmp.l    #0,d0
   bne      wekfha
   bsr      writedata
   cmp.l    #0,d0
   bne      wekfha
   bsr      waitinterrupt
   bsr      waitready
   cmp.l    #0,d0
   bne      wekfha
   sub.l    #1,d4
   bne      writenextoneblockki
   rts      ;d0==0   ok
wekfha rts

DLY macro
;   bsr   registeraccessdelay
   endm

registeraccessdelay
   move.l   d0,-(sp)
   move.l   #9,d0
dileiluup
   sub.l    #1,d0
   bne      dileiluup
   move.l   (sp)+,d0
   rts

DLY400NS macro ;wait 400 nanoseconds
   move.l   d0,-(sp)
   move.l   #2,d0
atst\@
   sub.l    #1,d0
   bne      atst\@
   move.l   (sp)+,d0
  endm

waitDRQ
wdlp
   DLY400NS
   move.b   TF_STATUS,d0
   and.b    #BSY+DRDY+SKC+DRQ+DWF+ERR,d0
   cmp.b    #DRDY+SKC+DRQ,d0
   bne      ntyt
   move.l   #0,d0
   rts
ntyt
   and.b    #DWF+ERR,d0
   beq      wdlp  ;no errs
   move.l   #-123,d0
   rts

waitinterrupt
   DLY400NS ;wait for BSY go high (400 ns)
   move.w   #1,enableflag
      ; tell interruptserver to signal if drive not BSY
;;;   move.b   #8,TF_DEVICE_CONTROL;  drive interrupts on
   move.l   signalmask,d0
   move.l   4,a6
; 
;;;   jsr      _LVOWait(a6) ;does not work 
;
   ; clear signal
   ;enableflag cleared by the server
   move.b   #8+nIEN,TF_DEVICE_CONTROL;  drive interrupts off
   rts

waitready
voost
   DLY400NS
   move.b   TF_STATUS,d0
   and.b    #BSY+DRDY+SKC+DWF+ERR,d0
   cmp.b    #DRDY+SKC,d0
   bne      nyras
   move.l   #0,d0
   rts
nyras
   and.b    #DWF+ERR,d0
   beq      voost
   move.l   -234,d0
   rts


readdata
   move.l   #64-1,d0
   move.l   #TF_DATA,a0
riidluup
   DLY
   move.w   (a0),(a5)+
   move.w   (a0),(a5)+
   move.w   (a0),(a5)+ 
   move.w   (a0),(a5)+  
   dbra     d0,riidluup
   DLY
   move.b   TF_STATUS,d0
   and.l    #ERR,d0
   rts

issueread
   cmp.l #LBASELECTED,LBAorCHS
   beq issueLBAread
   bsr getCHS
issueCHSread
   DLY
   move.b   d2,TF_DRIVE_HEAD
   DLY
   move.b   d4,TF_SECTOR_COUNT
   DLY
   move.b   d0,TF_CYLINDER_LOW
   DLY
   move.b   d1,TF_CYLINDER_HIGH
   DLY
   move.b   d3,TF_SECTOR_NUMBER
   DLY
   move.b   #ATA_READ_SECTORS,TF_COMMAND
   DLY
   DLY400NS
   move.b   TF_STATUS,d0
   and.l    #DWF+ERR,d0
   rts

issueLBAread
   DLY
   move.b   #DRV0+L+0,TF_DRIVE_HEAD ; L=lba  lba bits 24..27
   DLY
   move.b   d4,TF_SECTOR_COUNT
   DLY
   move.b   d0,TF_SECTOR_NUMBER ;lba bits 0..7
   DLY
   lsr.l    #8,d0
   move.b   d0,TF_CYLINDER_LOW   ;lba bits 8..15
   DLY
   lsr.l    #8,d0
   move.b   d0,TF_CYLINDER_HIGH ;lba bits 16..23
   DLY
   move.b   #ATA_READ_SECTORS,TF_COMMAND
   DLY
   DLY400NS
   move.b   TF_STATUS,d0
   and.l    #DWF+ERR,d0
   rts


writedata
   move.l   #TF_DATA,a0
   move.l   #64-1,d0
wrdslmu
   DLY
   move.w   (a5)+,(a0)
   move.w   (a5)+,(a0)
   move.w   (a5)+,(a0)  
   move.w   (a5)+,(a0)  
   dbra     d0,wrdslmu
   DLY
   move.b   TF_STATUS,d0
   and.l    #ERR+DWF,d0
   rts

issuewrite
   cmp.l    #LBASELECTED,LBAorCHS
   beq      issueLBAwrite
   bsr      getCHS
issueCHSwrite
   DLY
   move.b   d2,TF_DRIVE_HEAD
   DLY
   move.b   d4,TF_SECTOR_COUNT
   DLY
   move.b   d0,TF_CYLINDER_LOW
   DLY
   move.b   d1,TF_CYLINDER_HIGH
   DLY
   move.b   d3,TF_SECTOR_NUMBER
   DLY
   move.b   #ATA_WRITE_SECTORS,TF_COMMAND
   DLY
   DLY400NS
   move.b   TF_STATUS,d0
   and.l    #DWF+ERR,d0
   rts

issueLBAwrite
   DLY
   move.b   #DRV0+L+0,TF_DRIVE_HEAD  ;L=lba; lba bits 24..27
   DLY
   move.b   d4,TF_SECTOR_COUNT
   DLY
   move.b   d0,TF_SECTOR_NUMBER  ;LBA  bits  0..7
   DLY
   lsr.l    #8,d0
   move.b   d0,TF_CYLINDER_LOW   ;LBA  bits  8..15
   DLY
   lsr.l    #8,d0
   move.b   d0,TF_CYLINDER_HIGH  ;LBA  bits  16..23
   DLY
   move.b   #ATA_WRITE_SECTORS,TF_COMMAND
   DLY
   DLY400NS
   move.b   TF_STATUS,d0
   and.l    #DWF+ERR,d0
   rts

getCHS
   move.l   d0,d3
   divu     #SECTORS_PER_TRACK,d3
   swap.l   d3
   add.w    #1,d3
   and.l    #$ff,d3 ;sector number
   move.l   d0,d2
   divu     #SECTORS_PER_TRACK,d2
   and.l    #$ffff,d2
   divu     #HEADS,d2
   move.l   d2,d0 ;cyl
   swap.l   d2 ;jakojäännös
   and.l    #$ff,d2;head
   move.l   d0,d1
   and.l    #$ff,d0; cylinder low
   lsr.l    #8,d1
   and.l    #$ff,d1; cylinder high
   rts

   END
