]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blob - cbios/cfio.180
fc3bea1187504bc6a2051df6979fd2e9a6d32bb7
[z180-stamp-cpm3.git] / cbios / cfio.180
1 TITLE 'compactflash disk handler'
2
3 ; CP/M-80 Version 3 -- Modular BIOS
4
5
6 ; Disk drive dispatching tables for linked BIOS
7
8 public cf0,cf1,cf2,cf3
9
10 ; Variables containing parameters passed by BDOS
11
12 extrn @xdph
13 extrn @adrv,@rdrv
14 extrn @trk,@sect,@cnt
15 extrn @dma,@dbnk
16
17 ; System Control Block variables
18
19 extrn @ermde ; BDOS error mode
20
21 ; Utility routines
22
23 extrn ?wboot ; warm boot vector
24 extrn ?pmsg ; print message @<HL>
25 extrn pr.idx ; print indexed message
26 extrn pr.inln ; print inline message
27 extrn pr.decl ; print 32 bit decimal number
28 extrn pr.errors ; print BIOS disk error header
29 extrn ?cono ; console out
30 extrn bnk2phy ; translate banked to physical linear address
31 extrn add_hla ; add <A> to <HL>
32 extrn gstimer ; get timer short (16 bit)
33
34 ; Port Address Equates
35
36 include config.inc
37 include z180reg.inc
38
39 ; CP/M 3 Disk definition macros
40
41 maclib cpm3slr.lib
42
43 ; Z180 macro library instruction definitions (ignored by slr180)
44
45 include z180.lib
46
47 DEBUG equ false ; not used
48 MULTIIO equ true ; Multi I/O currently not fully implemented.
49
50 ; IDE Task File Register Definitions
51
52 ;IdeDOR equ IDEBASE+6 ; Digital Output Register
53 IDEDat equ IDEBASE+0 ; Data Register
54 IDEErr equ IDEBASE+1 ; Error Register
55 IDEFeat equ IDEBASE+1 ; Feature Register
56 IDESCnt equ IDEBASE+2 ; Sector Count
57 IDESNum equ IDEBASE+3 ; Sector Number
58 IDECLo equ IDEBASE+4 ; Cylinder Low
59 IDECHi equ IDEBASE+5 ; Cylinder High
60 IDESDH equ IDEBASE+6 ; Drive and Head
61 IDECmd equ IDEBASE+7 ; Command / Status
62
63 ; IDE Hard disk commands:
64
65 CmdHome equ 10h ; Recalibrate
66 CmdRd equ 20h ; Read Sector
67 CmdWr equ 30h ; Write Sector
68 CmdInit equ 91h ; Initialize Drive Params
69 CmdId equ 0ECh ; Read ID
70 CmdSF equ 0EFh ; Set Feature
71
72 ; Partition Table Structures
73
74 PART_TYPE equ 4
75 PART_START equ 8
76 PART_SIZE equ 12
77
78 ; Partition table id
79 ; (see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html)
80
81 PARTID1_FAT16 equ 00EH
82 PARTID2_FAT16 equ 006H
83 PARTID_CPM equ 052H
84
85 MAXDISKS equ 4
86
87 ; parttabl fields
88 PTAB_TYPE equ 0 ; 1 byte
89 PTAB_START equ 1 ; 4 byte (28 bit, max 128 GiB)
90 PTAB_SIZE equ 5 ; 4 byte (3 needed, 20 bit, max 512 MiB)
91 PTAB_SPT equ 9 ; 1 byte
92 PTAB_BSH equ 10 ; 1 byte
93
94 PARTENTRY_SIZE equ 11
95
96
97 ; common control characters
98
99 cr equ 13
100 lf equ 10
101 bell equ 7
102
103 ;-------------------------------------------------------------------------------
104
105 ; Macro: wait while device is busy
106
107 WAITNOTBUSY macro
108 local wait
109 wait: in a,(IdeCmd)
110 rla
111 jr c,wait
112 endm
113
114 ; Macro: wait until device is ready
115
116 WAITREADY macro
117 local wait
118 wait: in a,(IdeCmd)
119 xor 01000000b
120 and 11000000b
121 jr nz,wait
122 endm
123
124 ; Macro: wait for DRQ signal
125
126 WAITDRQ macro
127 local wait
128 wait: in a,(IdeCmd)
129 bit 3,a
130 jr z,wait
131 endm
132
133 ;-------------------------------------------------------------------------------
134
135 dseg
136
137 ; Extended Disk Parameter Headers (XPDHs)
138
139 ; dph translate$table, - disk parameter header
140 ; disk$parameter$block,
141 ; checksum$size, (optional)
142 ; alloc$size (optional)
143
144 dw cf$write
145 dw cf$read
146 dw cf$login
147 dw cf$init0
148 db 0,0 ; relative drive zero
149 cf0: dph 0,dpbsimhd512,0
150
151 dw cf$write
152 dw cf$read
153 dw cf$login
154 dw cf$init1
155 db 1,0 ; relative drive one
156 cf1: dph 0,dpbsimhd512,0
157
158 dw cf$write
159 dw cf$read
160 dw cf$login
161 dw cf$init2
162 db 2,0 ; relative drive zero
163 cf2: dph 0,dpbsimhd512,0
164
165 dw cf$write
166 dw cf$read
167 dw cf$login
168 dw cf$init3
169 db 3,0 ; relative drive one
170 cf3: dph 0,dpbsimhd512,0
171
172 cseg ; DPB must be resident
173
174 ; dpb physical$sector$size, - disk parameter block
175 ; physical$sectors$per$track,
176 ; number$tracks,
177 ; block$size,
178 ; number$dir$entries,
179 ; track$offset,
180 ; checksum$vec$size (optional)
181
182 dpbsimhd512:
183 dpb 512,8,2048,4096,1024,6,8000h
184
185 ;-------------------------------------------------------------------------------
186
187 dseg ; rest is banked
188
189 ; Disk I/O routines for standardized BIOS interface
190
191 ; Initialization entry point.
192 ; called for first time initialization.
193
194 cf$init0:
195 call pr.inln ;
196 db 'cfio: CompactFlash Memory Card driver',0
197
198 ld hl,parttbl ; Clear partition table
199 ld b,PARTENTRY_SIZE*MAXDISKS
200 ini_clrtbl:
201 ld (hl),0
202 inc hl
203 djnz ini_clrtbl
204
205 call cf_init ; init ide interface / cf card
206 jr nz,nocard
207 call ident_read ; identify drive
208 jr nz,nocard
209
210 call prnt_info ; print device information
211 call ptab_read ; read the partition table
212 jr nz,pend
213
214 ld c,0 ; number of found disks (paritions)
215 jr nz,pend
216
217 ld hl,tmpsecbuf+512-1 ; Point to first byte of partition table
218 ld a,(hl) ; Test, if it has a valid MBR
219 cp 0AAH ;
220 jr nz,pend ;
221 dec hl
222 ld a,(hl) ;
223 cp 055H ;
224 jr nz,pend ;
225
226 ; Search for valid Partitions
227
228 ld hl,tmpsecbuf+512-2-64+PART_TYPE ; Point to partition type of first first partition table entry
229 ld de,parttbl ;
230 ld b,4 ; Max # of partition table entries
231 ploop:
232 ld a,(hl) ; Get Partitiontype
233 cp PARTID_CPM ; Test for CP/M Partition
234 ld a,16 ; Offset to next entry
235 jr nz,nextp
236 push bc
237 ld a,(hl) ; (Re)get Partitiontype
238 ld (de),a ; Save paritition type
239 inc de
240 inc hl ; Point to partition start (lba)
241 inc hl
242 inc hl
243 inc hl
244 ld bc,8 ; Copy partition start and size
245 ldir
246 rept PARTENTRY_SIZE-8-1
247 inc de
248 endm
249 pop bc
250 inc c ; One more found
251 ld a,c
252 cp MAXDISKS
253 jr z,pend
254 ld a,4
255 nextp:
256 call add_hla
257 djnz ploop
258 pend:
259 ;TODO: variable disk format: sectors per track, ...
260
261 call prnt_ptab ; Print partition table info
262 ret
263
264 nocard:
265 call pr.inln
266 db ": No Card",cr,lf,0
267 ret
268
269
270 cf$init1:
271 cf$init2:
272 cf$init3:
273 ret ; all initialization done by drive 0
274
275 ; Read ID from Hard Disk
276
277 ident_read:
278 WAITREADY
279 ld a,0E0h ; assume unit 0,
280 out (IdeSDH),a ;
281 ld a,CmdId
282 out (IdeCmd),a ; command: read sector data
283 ld hl,tmpsecbuf
284 ld bc,IdeDat ; B = 0 (counter), C = I/O address
285 WAITDRQ ; wait for DRQ to become active
286 inir
287 inir ; read 512 data bytes (2 x 256)
288 WAITNOTBUSY
289 in a,(IdeCmd) ; check final drive status
290 and 10001001b ; Busy, DRQ, or Error?
291 ret z ; no: everything is ok
292 ld a,1 ; return with A=1 on error
293 ret
294
295
296 ; Read partition table
297
298 ptab_read:
299 WAITREADY
300 ld a,0E0h ; assume unit 0, lba mode
301 out (IdeSDH),a ;
302 xor a ; sector 0 (lba)
303 out (IdeSNum),a ;
304 out (IdeCLo),a
305 out (IdeCHi),a ;
306 inc a ; one sector to read
307 out (IdeSCnt),a ; set sector count
308
309 ld a,CmdRd
310 out (IdeCmd),a ; command: read sector data
311 ld hl,tmpsecbuf
312 ld bc,IdeDat ; B = 0 (counter), C = I/O address
313 WAITDRQ ; wait for DRQ to become active
314 inir
315 inir ; read 512 data bytes (2 x 256)
316 WAITNOTBUSY
317 in a,(IdeCmd) ; check final drive status
318 and 10001001b ; Busy, DRQ, or Error?
319 ret z ; no: everything is ok
320 ld a,1 ; return with A=1 on error
321 ret
322
323 cf_init:
324 ld hl,25600 ; 32000/1.25 ms
325 call wait_nbsy_to ; wait for BSY == 0
326 jr c,cfi_error ; return error on timeout
327
328 ld hl,25600 ; 32000/1.25 ms
329 call wait_rdy_to ; wait for RDY == 1
330 jr c,cfi_error ; return error on timeout
331
332 ld a,0E0h ; assume unit 0, lba mode
333 out (IdeSDH),a ;
334
335 xor a ; execute NOP command
336 out (IdeCmd),a ;
337 ld hl,100
338 call wait_rdy_to
339 jr c,cfi_error
340 and 11111001b ;
341 cp 01010001b ; should return error
342 jr nz,cfi_error ;
343 ld a,10h ; execute RECALIBRATE command
344 out (IdeCmd),a ;
345 ld hl,100
346 call wait_rdy_to
347 and 11111001b ;
348 cp 01010000b ; should return ok
349 jr nz,cfi_error ;
350
351 ld a,1 ; Enable 8-bit data transfer.
352 out (IDEFeat),a
353 ld a,CmdSF ; Set feature command
354 out (IdeCmd),a ;
355 WAITNOTBUSY
356 in a,(IdeCmd) ; check final drive status
357 and 10001001b ; Busy, DRQ, or Error?
358 ret z ; no: everything is ok
359 cfi_error:
360 ld a,1 ; return with A=1 on error
361 ret
362
363 ;-------------------------------------------------------------------------------
364 ; print char, skipping leading blanks
365
366 pr_char_nlbl:
367 bit 0,b
368 jr z,pr_char
369 cp ' '
370 ret z
371 res 0,b
372 ; fall thru
373
374 ; print character, saving hl, de, bc
375
376 pr_char:
377 push hl
378 push de
379 push bc
380 ld c,a
381 call ?cono
382 pop bc
383 pop de
384 pop hl
385 ret
386
387 ;-------------------------------------------------------------------------------
388
389 reftime:dw 2
390 to: dw 2
391
392 chk_to:
393 or a
394 jr z,chk_1
395 ld (to),hl
396 ld hl,0
397 call gstimer
398 ld (reftime),hl
399 ret
400 chk_1:
401 push hl
402 push de
403 ld hl,(reftime)
404 call gstimer
405 ex de,hl
406 ld hl,(to)
407 or a
408 sbc hl,de
409 pop de
410 pop hl
411 ret
412
413
414 ; Wait while device is busy with time out
415 ; hl: timer tics (1.25ms) to wait
416 ; return:
417 ; a: IDE status register
418 ; carry flag set, if time out
419
420 wait_nbsy_to:
421 ld a,1
422 call chk_to
423 wnb_l:
424 in a,(IdeCmd)
425 rla
426 jr nc,wnb_e
427 xor a
428 call chk_to
429 jr nc,wnb_l
430 wnb_e:
431 in a,(IdeCmd)
432 ret
433
434 ; Wait for ready signal with time out
435 ; hl: timer tics (1.25ms) to wait
436 ; return:
437 ; a: IDE status register
438 ; carry flag set, if time out
439
440 wait_rdy_to:
441 ld a,1
442 call chk_to
443 wrdy_l:
444 in a,(IdeCmd)
445 xor 01000000b
446 and 11000000b ; clears carry
447 jr z,wrdy_e
448 xor a
449 call chk_to
450 jr nc,wrdy_l
451 wrdy_e:
452 in a,(IdeCmd)
453 ret
454
455 ;-------------------------------------------------------------------------------
456
457 ; Print an id string
458 ; Remove leading and trailing spaces
459
460 pr_id:
461 push hl ; Save string address
462 ld b,0
463 add hl,bc
464 dec hl ; Point to last char.
465 ld a,' '
466 prn_el: ; Reduce string len by number of trailing spaces
467 dec hl
468 cpi
469 jr nz,prn_el1 ; No more spaces
470 jp po,prn_el2 ; No more characters
471 cpd
472 dec hl
473 jr nz,prn_el1
474 jp po,prn_el2
475 jr prn_el
476 prn_el1:
477 inc c
478 prn_el2:
479 pop hl ; Restore beginning of string
480 ld a,c
481 or a ; Test number of remaining chars
482 ret z ; Done, if string was spaces only
483
484 ld b,1 ; Flag, skip spaces
485 prn_lp:
486 inc hl ;Text is low byte high byte format
487 ld a,(hl)
488 call pr_char_nlbl
489 dec c
490 ret z
491 dec hl
492 prn_lp1:
493 ld a,(hl)
494 call pr_char_nlbl
495 dec c
496 ret z
497 inc hl
498 inc hl
499 jr prn_lp
500
501 ; Print divice information
502
503 prnt_info:
504 call pr.inln
505 db cr,lf,' Model: ',0
506 ld hl,tmpsecbuf + 27*2 ; Model number
507 ld c,20*2 ; max character count
508 call pr_id ;
509 call pr.inln
510 db ', S/N: ',0
511 ld hl,tmpsecbuf + 10*2 ; Serial number
512 ld c, 10*2
513 call pr_id
514 call pr.inln
515 db ', Rev: ',0
516 ld hl,tmpsecbuf + 23*2 ; Firmware revision
517 ld c, 4*2
518 call pr_id
519
520 call pr.inln
521 db cr,lf,' Size: ',0
522 ld hl,(tmpsecbuf+60*2) ;Total Sectors Addressable in LBA Mode
523 ld de,(tmpsecbuf+61*2) ;
524 push hl
525 push de
526 ld bc,1
527 call pr.decl
528 call pr.inln
529 db ' Sectors (',0
530 pop de
531 pop hl
532 srl d
533 rr e
534 rr h
535 rr l
536 ld bc,1
537 call pr.decl
538 call pr.inln
539 db ' KiB)',cr,lf,0
540 ret
541
542 ; Print partition table info
543
544 prnt_ptab:
545 ld ix,parttbl
546 ld c,0
547 prp_lp:
548 ld a,c
549 cp 4
550 ret z
551 ld a,(ix+PTAB_TYPE)
552 or a
553 ret z
554
555 push bc
556 call pr.inln
557 db ' ',0
558 ld a,(@adrv)
559 add a,c
560 add a,'A'
561 call pr_char
562 call pr.inln
563 db ': CP/M partition at: ',0
564 ld l,(ix+PTAB_START+0)
565 ld h,(ix+PTAB_START+1)
566 ld e,(ix+PTAB_START+2)
567 ld d,(ix+PTAB_START+3)
568 ld bc,1
569 call pr.decl
570 call pr.inln
571 db ', size: ',0
572 ld l,(ix+PTAB_SIZE+0)
573 ld h,(ix+PTAB_SIZE+1)
574 ld e,(ix+PTAB_SIZE+2)
575 ld d,(ix+PTAB_SIZE+3)
576 srl d
577 rr e
578 rr h
579 rr l
580 ld bc,1
581 call pr.decl
582 call pr.inln
583 db 'KiB',cr,lf,0
584 ld bc,PARTENTRY_SIZE
585 add ix,bc
586 pop bc
587 inc c
588 jr prp_lp
589
590 ;-------------------------------------------------------------------------------
591
592 ; This entry is called when a logical drive is about to
593 ; be logged into for the purpose of density determination.
594 ; It may adjust the parameters contained in the disk
595 ; parameter header pointed at by <DE>
596 ;
597 ; absolute drive number in @adrv (8 bits) +0
598 ; relative drive number in @rdrv (8 bits) +1
599
600 cf$login:
601 xor a
602 ld (residual),a ; just in case
603
604 ld hl,parttbl
605 ld a,(@rdrv)
606 ld e,a
607 ld d,PARTENTRY_SIZE
608 mlt de
609 add hl,de
610 ld a,(hl)
611 or a
612 ret nz
613 ld hl,0
614 ld (@xdph),hl
615 ret ;
616
617 ; disk READ and WRITE entry points.
618 ; these entries are called with the following arguments:
619 ;
620 ; operation type (r/w) in @op (8 bits) +0
621 ; absolute drive number in @adrv (8 bits) +1
622 ; relative drive number in @rdrv (8 bits) +2
623 ; disk track address in @trk (16 bits) +3
624 ; disk sector address in @sect(16 bits) +5
625 ; multi sector count in @cnt (8 bits) +7
626 ; disk transfer address in @dma (16 bits) +8
627 ; disk transfer bank in @dbnk (8 bits) +10
628 ; pointer to XDPH in <DE>
629 ;
630 ; they transfer the appropriate data, perform retries
631 ; if necessary, then return an error code in <A>
632
633 cf$read:
634 ld bc,M_DIM1*256 + CmdRd ; Transfermode: i/o to memory++
635 jr rw$common
636 cf$write:
637 ld bc,0*256 + CmdWr ; Transfermode: memory++ to i/o
638 rw$common:
639
640 if MULTIIO
641 ld hl,residual ; remainng sectors from last multi io?
642 ld a,(hl)
643 sub a,1
644 jr c,rwc_new_sectors
645
646 ld (hl),a
647 xor a
648 ret
649 endif
650
651 rwc_new_sectors:
652 ld (cfstack),sp
653 ld sp,cfstack
654
655 in0 a,(dcntl)
656 and a,~(M_DMS1+M_DIM1+M_DIM0)
657 or b
658 out0 (dcntl),a
659
660 ld b,1 ; assume 1 sector to transfer
661 if MULTIIO
662 ld a,(@cnt)
663 or a
664 jr z,rwc_doit
665
666 ld b,a ; number of sectors to transfer
667 dec a ; save remaining
668 ld (hl),a
669 xor a ; reset multi sector count
670 ld (@cnt),a
671 rwc_doit:
672 endif
673
674 ld iy,parttbl
675 ld a,(@rdrv)
676 ld e,a
677 ld d,PARTENTRY_SIZE
678 mlt de
679 add iy,de
680
681 retry:
682 ld a,b
683 out (IdeSCnt),a ; set sector count
684
685 ; compute logical block number (lba) --> cf-controller
686
687 ; TODO: sectors per track from dpb
688 ; lba = track * 8 + sector
689
690 xor a
691 ld hl,(@trk)
692 add hl,hl
693 adc a,a ; *2
694 add hl,hl
695 adc a,a ; *4
696 add hl,hl
697 adc a,a ; *8
698 ld de,(@sect)
699 add hl,de
700 adc a,0
701
702 push hl ; check, if block# fits in partition
703 ld e,(iy+PTAB_SIZE+0)
704 ld d,(iy+PTAB_SIZE+1)
705 sbc hl,de
706 ld e,a
707 sbc a,(iy+PTAB_SIZE+2)
708 pop hl
709 jr c,lba_ok
710 ld a,1 ; block# >= partition size, return error
711 jp exit
712 ; ret
713
714 lba_ok:
715 WAITREADY
716 ld a,(iy+PTAB_START+0) ; add partition start
717 add a,l
718 out (IdeSNum),a
719 ld a,(iy+PTAB_START+1)
720 adc a,h
721 out (IdeCLo),a
722 ld a,(iy+PTAB_START+2)
723 adc a,e
724 out (IdeCHi),a
725 ld a,(iy+PTAB_START+3)
726 adc a,0
727 and 00FH
728 or 0E0H
729 out (IdeSDH),a
730
731 ld hl,(@dma)
732 ld a,(@dbnk)
733
734 ; compute pysical transfer address --> DMA
735
736 call bnk2phy ; phys. linear address
737 out0 mar1l,l
738 out0 mar1h,h
739 out0 mar1b,a
740 ld a,IdeDat
741 out0 iar1l,a
742 xor a
743 out0 iar1h,a
744 out0 iar1b,a
745 out0 bcr1l,a
746 ld a,c
747 out (IDECmd),a
748 push bc
749 nxt_sec:
750 ld a,2
751 out0 bcr1h,a
752 WAITDRQ
753 ld a,M_DE1+M_NDWE0
754 out0 (dstat),a
755 wait_dma:
756 in0 a,(dstat)
757 bit DE1,A
758 jr nz,wait_dma
759
760 WAITNOTBUSY
761 in a,(IdeCmd) ; check final drive status
762 bit 0,a ; any error?
763 jr nz,err_out
764 djnz nxt_sec
765 err_out:
766 pop bc
767 ld e,a
768 and 10001001b ; Busy, DRQ, or Error?
769 jr z,exit
770 ; ret z ; Return to BDOS if no error
771
772 ld hl,print_details
773 call pr.errors
774 jp z,retry ; Yes, then retry once more
775 ; otherwise,
776 xor a
777 ld (residual),a
778
779 ld a,1 ; return hard error to BDOS
780 exit:
781 ld sp,(cfstack)
782 ret
783
784 ;-------------------------------------------------------------------------------
785
786 print_details:
787 ld hl,msg$drq
788 bit 3,e
789 call nz,?pmsg
790
791 bit 0,e
792 ret z
793
794 in a,(IDEErr)
795 ld e,8
796 errm1:
797 ld hl,b0$msg ; point at message[0]
798 dec e ; index of next message
799 add a,a ; shift left and push residual bits with status
800 push af
801 ld a,e
802 call c,pr.idx ; print it, if bit is set.
803 pop af
804 jr nz,errm1 ; if any more bits left, continue
805 ret
806
807 ;-------------------------------------------------------------------------------
808 ; error message components
809
810 msg$drq:
811 db 'DRQ, ',0
812
813 b7$msg: db ' Bad Block detected,',0
814 b6$msg: db ' Uncorrectable Data Error,',0
815 b5$msg: db ' Media Changed,',0
816 b4$msg: db ' Sector ID Not Found,',0
817 b3$msg: db ' Media Change Requst,',0
818 b2$msg: db ' Aborted Command,',0
819 b1$msg: db ' Track 0 Not Found,',0
820 b0$msg: db ' AM Not Found (or general error),',0
821 db 0
822
823 ;-------------------------------------------------------------------------------
824
825 residual:
826 db 0
827
828 parttbl:
829 ds PARTENTRY_SIZE*MAXDISKS
830
831 tmpsecbuf: ;temporary sector buffer
832 ds 512
833
834 rept 80
835 db 07CH
836 endm
837 cfstack::
838 dw 0
839
840 end