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