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
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 while device is busy
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
323 ld a,0E0h ; assume unit 0, lba mode
325 ld a,1 ; Enable 8-bit data transfer.
328 out (IdeCmd),a ; command: read sector data
330 in a,(IdeCmd) ; check final drive status
331 and 10001001b ; Busy, DRQ, or Error?
332 ret z ; no: everything is ok
333 ld a,1 ; return with A=1 on error
356 ; Remove leading and trailing spaces
359 push hl ; Save string address
362 dec hl ; Point to last char.
364 prn_el: ; Reduce string len by number of trailing spaces
367 jr nz,prn_el1 ; No more spaces
368 jp po,prn_el2 ; No more characters
377 pop hl ; Restore beginning of string
379 or a ; Test number of remaining chars
380 ret z ; Done, if string was spaces only
382 ld b,1 ; Flag, skip spaces
384 inc hl ;Text is low byte high byte format
399 ; Print divice information
404 ld hl,tmpsecbuf + 27*2 ; Model number
405 ld c,20*2 ; max character count
409 ld hl,tmpsecbuf + 10*2 ; Serial number
414 ld hl,tmpsecbuf + 23*2 ; Firmware revision
420 ld hl,(tmpsecbuf+60*2) ;Total Sectors Addressable in LBA Mode
421 ld de,(tmpsecbuf+61*2) ;
440 ; Print partition table info
461 db ': CP/M partition at: ',0
462 ld l,(ix+PTAB_START+0)
463 ld h,(ix+PTAB_START+1)
464 ld e,(ix+PTAB_START+2)
465 ld d,(ix+PTAB_START+3)
470 ld l,(ix+PTAB_SIZE+0)
471 ld h,(ix+PTAB_SIZE+1)
472 ld e,(ix+PTAB_SIZE+2)
473 ld d,(ix+PTAB_SIZE+3)
488 ;-------------------------------------------------------------------------------
490 ; This entry is called when a logical drive is about to
491 ; be logged into for the purpose of density determination.
492 ; It may adjust the parameters contained in the disk
493 ; parameter header pointed at by <DE>
495 ; absolute drive number in @adrv (8 bits) +0
496 ; relative drive number in @rdrv (8 bits) +1
500 ld (residual),a ; just in case
515 ; disk READ and WRITE entry points.
516 ; these entries are called with the following arguments:
518 ; absolute drive number in @adrv (8 bits) +0
519 ; relative drive number in @rdrv (8 bits) +1
520 ; disk track address in @trk (16 bits) +2
521 ; disk sector address in @sect(16 bits) +4
522 ; multi sector count in @cnt (8 bits) +6
523 ; disk transfer address in @dma (16 bits) +7
524 ; disk transfer bank in @dbnk (8 bits) +9
525 ; pointer to XDPH in <DE>
527 ; they transfer the appropriate data, perform retries
528 ; if necessary, then return an error code in <A>
531 ld de,read$msg ; point at " Read "
532 ld bc,M_DIM1*256 + CmdRd ; Transfermode: i/o to memory++
535 ld de,write$msg ; point at " Write "
536 ld bc,0*256 + CmdWr ; Transfermode: memory++ to i/o
540 ld hl,residual ; remainng sectors from last multi io?
551 ld (operation$name),de ; save message for errors
553 and a,~(M_DMS1+M_DIM1+M_DIM0)
557 ld b,1 ; assume 1 sector to transfer
563 ld b,a ; number of sectors to transfer
564 dec a ; save remaining
566 xor a ; reset multi sector count
580 out (IdeSCnt),a ; set sector count
582 ; compute logical block number (lba) --> cf-controller
584 ; TODO: sectors per track from dpb
585 ; lba = track * 8 + sector
599 push hl ; check, if block# fits in partition
600 ld e,(iy+PTAB_SIZE+0)
601 ld d,(iy+PTAB_SIZE+1)
604 sbc a,(iy+PTAB_SIZE+2)
608 ld a,1 ; block# >= partition size, return error
613 ld e,a ; add partition start
614 ld a,(iy+PTAB_START+0)
617 ld a,(iy+PTAB_START+1)
620 ld a,(iy+PTAB_START+2)
623 ld a,(iy+PTAB_START+3)
632 ; compute pysical transfer address --> DMA
634 call bnk2phy ; phys. linear address
659 in a,(IdeCmd) ; check final drive status
666 and 10001001b ; Busy, DRQ, or Error?
667 ret z ; Return to BDOS if no error
669 ; suppress error message if BDOS is returning errors to application...
675 ; Had permanent error, print message like:
676 ; BIOS Err on d: T-nn, S-mm, <operation> <type>, Retry ?
678 call ?pderr ; print message header
680 ld hl,(operation$name)
681 call ?pmsg ; last function (read or write)
691 ld hl,error$table ; point at table of message addresses
696 inc hl ; get next message address
698 push af ; shift left and push residual bits with status
701 ex de,hl ; print message, saving table pointer
703 jr nz,errm1 ; if any more bits left, continue
707 db ' Retry (Y/N) ? ',0
709 call u$conin$echo ; get operator response
711 jp z,retry ; Yes, then retry
718 ld a,1 ; return hard error to BDOS
721 cancel: ; here to abort job
722 jp ?wboot ; leap directly to warmstart vector
725 ; get console input, echo it, and shift to upper case
732 jr z,u$c1 ; see if any char already struck
734 jr u$c0 ; yes, eat it and try again
745 sub 'a'-'A' ; make upper case
748 ; error message components
768 b7$msg: db ' Bad Block detected,',0
769 b6$msg: db ' Uncorrectable Data Error,',0
770 b5$msg: db ' Media Changed,',0
771 b4$msg: db ' Sector ID Not Found,',0
772 b3$msg: db ' Media Change Requst,',0
773 b2$msg: db ' Aborted Command,',0
774 b1$msg: db ' Track 0 Not Found,',0
775 b0$msg: db ' AM Not Found (or general error),',0
782 ds PARTENTRY_SIZE*MAXDISKS
784 tmpsecbuf: ;temporary sector buffer