]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blob - cbios/cfio.180
include --> maclib
[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 maclib z180reg.inc
37 maclib config.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 maclib 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 in0 a,(dcntl)
653 and a,~(M_DMS1+M_DIM1+M_DIM0)
654 or b
655 out0 (dcntl),a
656
657 ld b,1 ; assume 1 sector to transfer
658 if MULTIIO
659 ld a,(@cnt)
660 or a
661 jr z,rwc_doit
662
663 ld b,a ; number of sectors to transfer
664 dec a ; save remaining
665 ld (hl),a
666 xor a ; reset multi sector count
667 ld (@cnt),a
668 rwc_doit:
669 endif
670
671 ld iy,parttbl
672 ld a,(@rdrv)
673 ld e,a
674 ld d,PARTENTRY_SIZE
675 mlt de
676 add iy,de
677
678 retry:
679 ld a,b
680 out (IdeSCnt),a ; set sector count
681
682 ; compute logical block number (lba) --> cf-controller
683
684 ; TODO: sectors per track from dpb
685 ; lba = track * 8 + sector
686
687 xor a
688 ld hl,(@trk)
689 add hl,hl
690 adc a,a ; *2
691 add hl,hl
692 adc a,a ; *4
693 add hl,hl
694 adc a,a ; *8
695 ld de,(@sect)
696 add hl,de
697 adc a,0
698
699 push hl ; check, if block# fits in partition
700 ld e,(iy+PTAB_SIZE+0)
701 ld d,(iy+PTAB_SIZE+1)
702 sbc hl,de
703 ld e,a
704 sbc a,(iy+PTAB_SIZE+2)
705 pop hl
706 jr c,lba_ok
707 ld a,1 ; block# >= partition size, return error
708 ret
709
710 lba_ok:
711 WAITREADY
712 ld a,(iy+PTAB_START+0) ; add partition start
713 add a,l
714 out (IdeSNum),a
715 ld a,(iy+PTAB_START+1)
716 adc a,h
717 out (IdeCLo),a
718 ld a,(iy+PTAB_START+2)
719 adc a,e
720 out (IdeCHi),a
721 ld a,(iy+PTAB_START+3)
722 adc a,0
723 and 00FH
724 or 0E0H
725 out (IdeSDH),a
726
727 ld hl,(@dma)
728 ld a,(@dbnk)
729
730 ; compute pysical transfer address --> DMA
731
732 call bnk2phy ; phys. linear address
733 out0 mar1l,l
734 out0 mar1h,h
735 out0 mar1b,a
736 ld a,IdeDat
737 out0 iar1l,a
738 xor a
739 out0 iar1h,a
740 out0 iar1b,a
741 out0 bcr1l,a
742 ld a,c
743 out (IDECmd),a
744 push bc
745 nxt_sec:
746 ld a,2
747 out0 bcr1h,a
748 WAITDRQ
749 ld a,M_DE1+M_NDWE0
750 out0 (dstat),a
751 wait_dma:
752 in0 a,(dstat)
753 bit DE1,A
754 jr nz,wait_dma
755
756 WAITNOTBUSY
757 in a,(IdeCmd) ; check final drive status
758 bit 0,a ; any error?
759 jr nz,err_out
760 djnz nxt_sec
761 err_out:
762 pop bc
763 ld e,a
764 and 10001001b ; Busy, DRQ, or Error?
765 ret z ; Return to BDOS if no error
766
767 ld hl,print_details
768 call pr.errors
769 jp z,retry ; Yes, then retry once more
770 ; otherwise,
771 xor a
772 ld (residual),a
773
774 ld a,1 ; return hard error to BDOS
775 ret
776
777 ;-------------------------------------------------------------------------------
778
779 print_details:
780 ld hl,msg$drq
781 bit 3,e
782 call nz,?pmsg
783
784 bit 0,e
785 ret z
786
787 in a,(IDEErr)
788 ld e,8
789 errm1:
790 ld hl,b0$msg ; point at message[0]
791 dec e ; index of next message
792 add a,a ; shift left and push residual bits with status
793 push af
794 ld a,e
795 call c,pr.idx ; print it, if bit is set.
796 pop af
797 jr nz,errm1 ; if any more bits left, continue
798 ret
799
800 ;-------------------------------------------------------------------------------
801 ; error message components
802
803 msg$drq:
804 db 'DRQ, ',0
805
806 b7$msg: db ' Bad Block detected,',0
807 b6$msg: db ' Uncorrectable Data Error,',0
808 b5$msg: db ' Media Changed,',0
809 b4$msg: db ' Sector ID Not Found,',0
810 b3$msg: db ' Media Change Requst,',0
811 b2$msg: db ' Aborted Command,',0
812 b1$msg: db ' Track 0 Not Found,',0
813 b0$msg: db ' AM Not Found (or general error),',0
814 db 0
815
816 ;-------------------------------------------------------------------------------
817
818 residual:
819 db 0
820
821 parttbl:
822 ds PARTENTRY_SIZE*MAXDISKS
823
824 tmpsecbuf: ;temporary sector buffer
825 ds 512
826
827 end