1 TITLE 'compactflash disk handler'
3 ; CP/M-80 Version 3 -- Modular BIOS
6 ; Disk drive dispatching tables for linked BIOS
10 ; Variables containing parameters passed by BDOS
15 extrn @dma,@dbnk,@cbnk
17 ; System Control Block variables
19 extrn @ermde ; BDOS error mode
21 ; Utility routines in standard BIOS
23 extrn ?wboot ; warm boot vector
24 extrn ?pmsg,pr.inln ; print message @<HL>, print inline message
25 extrn pr.crlf ; print <cr><lf>
28 extrn ?pderr ; print BIOS disk error header
29 extrn ?conin,?cono ; con in and out
30 extrn ?const ; get console status
35 extrn gstimer ; get timer short (16 bit)
37 ; Port Address Equates
42 ; CP/M 3 Disk definition macros
46 ; Z180 macro library instruction definitions (ignored by slr180)
50 DEBUG equ false ; not used
51 MULTIIO equ true ; Multi I/O currently not fully implemented.
53 ; IDE Task File Register Definitions
55 ;IdeDOR equ IDEBASE+6 ; Digital Output Register
56 IDEDat equ IDEBASE+0 ; Data Register
57 IDEErr equ IDEBASE+1 ; Error Register
58 IDEFeat equ IDEBASE+1 ; Feature Register
59 IDESCnt equ IDEBASE+2 ; Sector Count
60 IDESNum equ IDEBASE+3 ; Sector Number
61 IDECLo equ IDEBASE+4 ; Cylinder Low
62 IDECHi equ IDEBASE+5 ; Cylinder High
63 IDESDH equ IDEBASE+6 ; Drive and Head
64 IDECmd equ IDEBASE+7 ; Command / Status
66 ; IDE Hard disk commands:
68 CmdHome equ 10h ; Recalibrate
69 CmdRd equ 20h ; Read Sector
70 CmdWr equ 30h ; Write Sector
71 CmdInit equ 91h ; Initialize Drive Params
72 CmdId equ 0ECh ; Read ID
73 CmdSF equ 0EFh ; Set Feature
75 ; Partition Table Structures
82 ; (see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html)
84 PARTID1_FAT16 equ 00EH
85 PARTID2_FAT16 equ 006H
91 PTAB_TYPE equ 0 ; 1 byte
92 PTAB_START equ 1 ; 4 byte (28 bit, max 128 GiB)
93 PTAB_SIZE equ 5 ; 4 byte (3 needed, 20 bit, max 512 MiB)
94 PTAB_SPT equ 9 ; 1 byte
95 PTAB_BSH equ 10 ; 1 byte
100 ; common control characters
106 ;-------------------------------------------------------------------------------
108 ; Macro: wait while device is busy
117 ; Macro: wait until device is ready
127 ; Macro: wait for DRQ signal
136 ;-------------------------------------------------------------------------------
140 ; Extended Disk Parameter Headers (XPDHs)
142 ; dph translate$table, - disk parameter header
143 ; disk$parameter$block,
144 ; checksum$size, (optional)
145 ; alloc$size (optional)
151 db 0,0 ; relative drive zero
152 cf0: dph 0,dpbsimhd512,0
158 db 1,0 ; relative drive one
159 cf1: dph 0,dpbsimhd512,0
165 db 2,0 ; relative drive zero
166 cf2: dph 0,dpbsimhd512,0
172 db 3,0 ; relative drive one
173 cf3: dph 0,dpbsimhd512,0
175 cseg ; DPB must be resident
177 ; dpb physical$sector$size, - disk parameter block
178 ; physical$sectors$per$track,
181 ; number$dir$entries,
183 ; checksum$vec$size (optional)
186 dpb 512,8,2048,4096,1024,6,8000h
188 ;-------------------------------------------------------------------------------
190 dseg ; rest is banked
192 ; Disk I/O routines for standardized BIOS interface
194 ; Initialization entry point.
195 ; called for first time initialization.
199 db 'cfio: CompactFlash Memory Card driver'cr,lf,0
201 ld hl,parttbl ; Clear partition table
202 ld b,PARTENTRY_SIZE*MAXDISKS
208 call cf_init ; init ide interface / cf card
211 call ident_read ; identify drive
214 call prnt_info ; print device information
215 call ptab_read ; read the partition table
217 ld c,0 ; number of found disks (paritions)
220 ld hl,tmpsecbuf+512-1 ; Point to first byte of partition table
221 ld a,(hl) ; Test, if it has a valid MBR
229 ; Search for valid Partitions
231 ld hl,tmpsecbuf+512-2-64+PART_TYPE ; Point to partition type of first first partition table entry
233 ld b,4 ; Max # of partition table entries
235 ld a,(hl) ; Get Partitiontype
236 cp PARTID_CPM ; Test for CP/M Partition
237 ld a,16 ; Offset to next entry
240 ld a,(hl) ; (Re)get Partitiontype
241 ld (de),a ; Save paritition type
243 inc hl ; Point to partition start (lba)
247 ld bc,8 ; Copy partition start and size
249 rept PARTENTRY_SIZE-8-1
253 inc c ; One more found
262 ;TODO: variable disk format: sectors per track, ...
264 call prnt_ptab ; Print partition table info
271 ret ; all initialization done by drive 0
273 ; Read ID from Hard Disk
277 ld a,0E0h ; assume unit 0,
280 out (IdeCmd),a ; command: read sector data
282 ld bc,IdeDat ; B = 0 (counter), C = I/O address
283 WAITDRQ ; wait for DRQ to become active
285 inir ; read 512 data bytes (2 x 256)
287 in a,(IdeCmd) ; check final drive status
288 and 10001001b ; Busy, DRQ, or Error?
289 ret z ; no: everything is ok
290 ld a,1 ; return with A=1 on error
294 ; Read partition table
298 ld a,0E0h ; assume unit 0, lba mode
300 xor a ; sector 0 (lba)
304 inc a ; one sector to read
305 out (IdeSCnt),a ; set sector count
308 out (IdeCmd),a ; command: read sector data
310 ld bc,IdeDat ; B = 0 (counter), C = I/O address
311 WAITDRQ ; wait for DRQ to become active
313 inir ; read 512 data bytes (2 x 256)
315 in a,(IdeCmd) ; check final drive status
316 and 10001001b ; Busy, DRQ, or Error?
317 ret z ; no: everything is ok
318 ld a,1 ; return with A=1 on error
322 ld hl,25600 ;32000/1.25 ms
324 jr c,cfi_error ; return error on timeout
340 ld hl,25600 ;32000/1.25 ms
342 jr c,cfi_error ; return error on timeout
344 ld a,0E0h ; assume unit 0, lba mode
346 ld a,1 ; Enable 8-bit data transfer.
348 ld a,CmdSF ; Set feature command
351 in a,(IdeCmd) ; check final drive status
352 and 10001001b ; Busy, DRQ, or Error?
353 ret z ; no: everything is ok
355 ld a,1 ; return with A=1 on error
377 ;-------------------------------------------------------------------------------
404 ; Wait while device is busy with time out
405 ; hl: timer tics (1.25ms) to wait
406 ; return carry flag set, if time out
421 ; Wait for ready signal with time out
422 ; hl: timer tics (1.25ms) to wait
423 ; return carry flag set, if time out
431 and 11000000b ; clears carry
439 ;-------------------------------------------------------------------------------
442 ; Remove leading and trailing spaces
445 push hl ; Save string address
448 dec hl ; Point to last char.
450 prn_el: ; Reduce string len by number of trailing spaces
453 jr nz,prn_el1 ; No more spaces
454 jp po,prn_el2 ; No more characters
463 pop hl ; Restore beginning of string
465 or a ; Test number of remaining chars
466 ret z ; Done, if string was spaces only
468 ld b,1 ; Flag, skip spaces
470 inc hl ;Text is low byte high byte format
485 ; Print divice information
490 ld hl,tmpsecbuf + 27*2 ; Model number
491 ld c,20*2 ; max character count
495 ld hl,tmpsecbuf + 10*2 ; Serial number
500 ld hl,tmpsecbuf + 23*2 ; Firmware revision
506 ld hl,(tmpsecbuf+60*2) ;Total Sectors Addressable in LBA Mode
507 ld de,(tmpsecbuf+61*2) ;
526 ; Print partition table info
547 db ': CP/M partition at: ',0
548 ld l,(ix+PTAB_START+0)
549 ld h,(ix+PTAB_START+1)
550 ld e,(ix+PTAB_START+2)
551 ld d,(ix+PTAB_START+3)
556 ld l,(ix+PTAB_SIZE+0)
557 ld h,(ix+PTAB_SIZE+1)
558 ld e,(ix+PTAB_SIZE+2)
559 ld d,(ix+PTAB_SIZE+3)
574 ;-------------------------------------------------------------------------------
576 ; This entry is called when a logical drive is about to
577 ; be logged into for the purpose of density determination.
578 ; It may adjust the parameters contained in the disk
579 ; parameter header pointed at by <DE>
581 ; absolute drive number in @adrv (8 bits) +0
582 ; relative drive number in @rdrv (8 bits) +1
586 ld (residual),a ; just in case
601 ; disk READ and WRITE entry points.
602 ; these entries are called with the following arguments:
604 ; absolute drive number in @adrv (8 bits) +0
605 ; relative drive number in @rdrv (8 bits) +1
606 ; disk track address in @trk (16 bits) +2
607 ; disk sector address in @sect(16 bits) +4
608 ; multi sector count in @cnt (8 bits) +6
609 ; disk transfer address in @dma (16 bits) +7
610 ; disk transfer bank in @dbnk (8 bits) +9
611 ; pointer to XDPH in <DE>
613 ; they transfer the appropriate data, perform retries
614 ; if necessary, then return an error code in <A>
617 ld de,read$msg ; point at " Read "
618 ld bc,M_DIM1*256 + CmdRd ; Transfermode: i/o to memory++
621 ld de,write$msg ; point at " Write "
622 ld bc,0*256 + CmdWr ; Transfermode: memory++ to i/o
626 ld hl,residual ; remainng sectors from last multi io?
637 ld (operation$name),de ; save message for errors
639 and a,~(M_DMS1+M_DIM1+M_DIM0)
643 ld b,1 ; assume 1 sector to transfer
649 ld b,a ; number of sectors to transfer
650 dec a ; save remaining
652 xor a ; reset multi sector count
666 out (IdeSCnt),a ; set sector count
668 ; compute logical block number (lba) --> cf-controller
670 ; TODO: sectors per track from dpb
671 ; lba = track * 8 + sector
685 push hl ; check, if block# fits in partition
686 ld e,(iy+PTAB_SIZE+0)
687 ld d,(iy+PTAB_SIZE+1)
690 sbc a,(iy+PTAB_SIZE+2)
694 ld a,1 ; block# >= partition size, return error
699 ld e,a ; add partition start
700 ld a,(iy+PTAB_START+0)
703 ld a,(iy+PTAB_START+1)
706 ld a,(iy+PTAB_START+2)
709 ld a,(iy+PTAB_START+3)
718 ; compute pysical transfer address --> DMA
720 call bnk2phy ; phys. linear address
745 in a,(IdeCmd) ; check final drive status
752 and 10001001b ; Busy, DRQ, or Error?
753 ret z ; Return to BDOS if no error
755 ; suppress error message if BDOS is returning errors to application...
761 ; Had permanent error, print message like:
762 ; BIOS Err on d: T-nn, S-mm, <operation> <type>, Retry ?
764 call ?pderr ; print message header
766 ld hl,(operation$name)
767 call ?pmsg ; last function (read or write)
777 ld hl,error$table ; point at table of message addresses
782 inc hl ; get next message address
784 push af ; shift left and push residual bits with status
787 ex de,hl ; print message, saving table pointer
789 jr nz,errm1 ; if any more bits left, continue
793 db ' Retry (Y/N) ? ',0
795 call u$conin$echo ; get operator response
797 jp z,retry ; Yes, then retry
804 ld a,1 ; return hard error to BDOS
807 cancel: ; here to abort job
808 jp ?wboot ; leap directly to warmstart vector
811 ; get console input, echo it, and shift to upper case
818 jr z,u$c1 ; see if any char already struck
820 jr u$c0 ; yes, eat it and try again
831 sub 'a'-'A' ; make upper case
834 ; error message components
854 b7$msg: db ' Bad Block detected,',0
855 b6$msg: db ' Uncorrectable Data Error,',0
856 b5$msg: db ' Media Changed,',0
857 b4$msg: db ' Sector ID Not Found,',0
858 b3$msg: db ' Media Change Requst,',0
859 b2$msg: db ' Aborted Command,',0
860 b1$msg: db ' Track 0 Not Found,',0
861 b0$msg: db ' AM Not Found (or general error),',0
868 ds PARTENTRY_SIZE*MAXDISKS
870 tmpsecbuf: ;temporary sector buffer