]> cloudbase.mooo.com Git - z180-stamp-cpm3.git/blob - cbios/cfio.180
a76c9bdbf2c51520e408d185b25cbbe6d046b8a5
[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
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 while device is busy
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 WAITREADY
323 ld a,0E0h ; assume unit 0, lba mode
324 out (IdeSDH),a ;
325 ld a,1 ; Enable 8-bit data transfer.
326 out (IDEFeat),a
327 ld a,CmdSF
328 out (IdeCmd),a ; command: read sector data
329 WAITNOTBUSY
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
334 ret
335
336
337 pr_char_nlbl:
338 bit 0,b
339 jr z,pr_char
340 cp ' '
341 ret z
342 res 0,b
343 ; fall thru
344 pr_char:
345 push hl
346 push de
347 push bc
348 ld c,a
349 call ?cono
350 pop bc
351 pop de
352 pop hl
353 ret
354
355 ; Print an id string
356 ; Remove leading and trailing spaces
357
358 pr_id:
359 push hl ; Save string address
360 ld b,0
361 add hl,bc
362 dec hl ; Point to last char.
363 ld a,' '
364 prn_el: ; Reduce string len by number of trailing spaces
365 dec hl
366 cpi
367 jr nz,prn_el1 ; No more spaces
368 jp po,prn_el2 ; No more characters
369 cpd
370 dec hl
371 jr nz,prn_el1
372 jp po,prn_el2
373 jr prn_el
374 prn_el1:
375 inc c
376 prn_el2:
377 pop hl ; Restore beginning of string
378 ld a,c
379 or a ; Test number of remaining chars
380 ret z ; Done, if string was spaces only
381
382 ld b,1 ; Flag, skip spaces
383 prn_lp:
384 inc hl ;Text is low byte high byte format
385 ld a,(hl)
386 call pr_char_nlbl
387 dec c
388 ret z
389 dec hl
390 prn_lp1:
391 ld a,(hl)
392 call pr_char_nlbl
393 dec c
394 ret z
395 inc hl
396 inc hl
397 jr prn_lp
398
399 ; Print divice information
400
401 prnt_info:
402 call pr.inln
403 db ' Model: ',0
404 ld hl,tmpsecbuf + 27*2 ; Model number
405 ld c,20*2 ; max character count
406 call pr_id ;
407 call pr.inln
408 db ', S/N: ',0
409 ld hl,tmpsecbuf + 10*2 ; Serial number
410 ld c, 10*2
411 call pr_id
412 call pr.inln
413 db ', Rev: ',0
414 ld hl,tmpsecbuf + 23*2 ; Firmware revision
415 ld c, 4*2
416 call pr_id
417
418 call pr.inln
419 db cr,lf,' Size: ',0
420 ld hl,(tmpsecbuf+60*2) ;Total Sectors Addressable in LBA Mode
421 ld de,(tmpsecbuf+61*2) ;
422 push hl
423 push de
424 ld bc,1
425 call pr.decl
426 call pr.inln
427 db ' Sectors (',0
428 pop de
429 pop hl
430 srl d
431 rr e
432 rr h
433 rr l
434 ld bc,1
435 call pr.decl
436 call pr.inln
437 db ' KiB)',cr,lf,0
438 ret
439
440 ; Print partition table info
441
442 prnt_ptab:
443 ld ix,parttbl
444 ld c,0
445 prp_lp:
446 ld a,c
447 cp 4
448 ret z
449 ld a,(ix+PTAB_TYPE)
450 or a
451 ret z
452
453 push bc
454 call pr.inln
455 db ' ',0
456 ld a,(@adrv)
457 add a,c
458 add a,'A'
459 call pr_char
460 call pr.inln
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)
466 ld bc,1
467 call pr.decl
468 call pr.inln
469 db ', size: ',0
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)
474 srl d
475 rr e
476 rr h
477 rr l
478 ld bc,1
479 call pr.decl
480 call pr.inln
481 db 'KiB',cr,lf,0
482 ld bc,PARTENTRY_SIZE
483 add ix,bc
484 pop bc
485 inc c
486 jr prp_lp
487
488 ;-------------------------------------------------------------------------------
489
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>
494 ;
495 ; absolute drive number in @adrv (8 bits) +0
496 ; relative drive number in @rdrv (8 bits) +1
497
498 cf$login:
499 xor a
500 ld (residual),a ; just in case
501
502 ld hl,parttbl
503 ld a,(@rdrv)
504 ld e,a
505 ld d,PARTENTRY_SIZE
506 mlt de
507 add hl,de
508 ld a,(hl)
509 or a
510 ret nz
511 ld hl,0
512 ld (@xdph),hl
513 ret ;
514
515 ; disk READ and WRITE entry points.
516 ; these entries are called with the following arguments:
517 ;
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>
526 ;
527 ; they transfer the appropriate data, perform retries
528 ; if necessary, then return an error code in <A>
529
530 cf$read:
531 ld de,read$msg ; point at " Read "
532 ld bc,M_DIM1*256 + CmdRd ; Transfermode: i/o to memory++
533 jr rw$common
534 cf$write:
535 ld de,write$msg ; point at " Write "
536 ld bc,0*256 + CmdWr ; Transfermode: memory++ to i/o
537 rw$common:
538
539 if MULTIIO
540 ld hl,residual ; remainng sectors from last multi io?
541 ld a,(hl)
542 sub a,1
543 jr c,rwc_new_sectors
544
545 ld (hl),a
546 xor a
547 ret
548 endif
549
550 rwc_new_sectors:
551 ld (operation$name),de ; save message for errors
552 in0 a,(dcntl)
553 and a,~(M_DMS1+M_DIM1+M_DIM0)
554 or b
555 out0 (dcntl),a
556
557 ld b,1 ; assume 1 sector to transfer
558 if MULTIIO
559 ld a,(@cnt)
560 or a
561 jr z,rwc_doit
562
563 ld b,a ; number of sectors to transfer
564 dec a ; save remaining
565 ld (hl),a
566 xor a ; reset multi sector count
567 ld (@cnt),a
568 rwc_doit:
569 endif
570
571 ld iy,parttbl
572 ld a,(@rdrv)
573 ld e,a
574 ld d,PARTENTRY_SIZE
575 mlt de
576 add iy,de
577
578 retry:
579 ld a,b
580 out (IdeSCnt),a ; set sector count
581
582 ; compute logical block number (lba) --> cf-controller
583
584 ; TODO: sectors per track from dpb
585 ; lba = track * 8 + sector
586
587 xor a
588 ld hl,(@trk)
589 add hl,hl
590 adc a,a ; *2
591 add hl,hl
592 adc a,a ; *4
593 add hl,hl
594 adc a,a ; *8
595 ld de,(@sect)
596 add hl,de
597 adc a,0
598
599 push hl ; check, if block# fits in partition
600 ld e,(iy+PTAB_SIZE+0)
601 ld d,(iy+PTAB_SIZE+1)
602 sbc hl,de
603 ld l,a
604 sbc a,(iy+PTAB_SIZE+2)
605 ld a,l
606 pop hl
607 jr c,lba_ok
608 ld a,1 ; block# >= partition size, return error
609 ret
610
611 lba_ok:
612 WAITREADY
613 ld e,a ; add partition start
614 ld a,(iy+PTAB_START+0)
615 add a,l
616 out (IdeSNum),a
617 ld a,(iy+PTAB_START+1)
618 adc a,h
619 out (IdeCLo),a
620 ld a,(iy+PTAB_START+2)
621 adc a,e
622 out (IdeCHi),a
623 ld a,(iy+PTAB_START+3)
624 adc a,0
625 and 00FH
626 or 0E0H
627 out (IdeSDH),a
628
629 ld hl,(@dma)
630 ld a,(@dbnk)
631
632 ; compute pysical transfer address --> DMA
633
634 call bnk2phy ; phys. linear address
635 out0 mar1l,l
636 out0 mar1h,h
637 out0 mar1b,a
638 ld a,IdeDat
639 out0 iar1l,a
640 xor a
641 out0 iar1h,a
642 out0 iar1b,a
643 out0 bcr1l,a
644 ld a,c
645 out (IDECmd),a
646 push bc
647 nxt_sec:
648 ld a,2
649 out0 bcr1h,a
650 WAITDRQ
651 ld a,M_DE1+M_NDWE0
652 out0 (dstat),a
653 wait_dma:
654 in0 a,(dstat)
655 bit DE1,A
656 jr nz,wait_dma
657
658 WAITNOTBUSY
659 in a,(IdeCmd) ; check final drive status
660 bit 0,a ; any error?
661 jr nz,err_out
662 djnz nxt_sec
663 err_out:
664 pop bc
665 ld e,a
666 and 10001001b ; Busy, DRQ, or Error?
667 ret z ; Return to BDOS if no error
668
669 ; suppress error message if BDOS is returning errors to application...
670
671 ld a,(@ermde)
672 cp 0ffh
673 jr z,hard$error
674
675 ; Had permanent error, print message like:
676 ; BIOS Err on d: T-nn, S-mm, <operation> <type>, Retry ?
677
678 call ?pderr ; print message header
679
680 ld hl,(operation$name)
681 call ?pmsg ; last function (read or write)
682
683 ld hl,msg$drq
684 bit 3,e
685 call nz,?pmsg
686
687 bit 0,e
688 jr z,prompt
689
690 in a,(IDEErr)
691 ld hl,error$table ; point at table of message addresses
692 errm1:
693 ld e,(hl)
694 inc hl
695 ld d,(hl)
696 inc hl ; get next message address
697 add a,a
698 push af ; shift left and push residual bits with status
699 ex de,hl
700 call c,?pmsg
701 ex de,hl ; print message, saving table pointer
702 pop af
703 jr nz,errm1 ; if any more bits left, continue
704
705 prompt:
706 call pr.inln
707 db ' Retry (Y/N) ? ',0
708
709 call u$conin$echo ; get operator response
710 cp 'Y'
711 jp z,retry ; Yes, then retry
712
713 hard$error:
714 ; otherwise,
715 xor a
716 ld (residual),a
717
718 ld a,1 ; return hard error to BDOS
719 ret
720
721 cancel: ; here to abort job
722 jp ?wboot ; leap directly to warmstart vector
723
724
725 ; get console input, echo it, and shift to upper case
726
727 u$conin$echo:
728 push bc
729 u$c0:
730 call ?const
731 or a
732 jr z,u$c1 ; see if any char already struck
733 call ?conin
734 jr u$c0 ; yes, eat it and try again
735 u$c1:
736 call ?conin
737 push af
738 ld c,a
739 cp ' '-1
740 call nc,?cono
741 pop af
742 pop bc
743 cp 'a'
744 ret c
745 sub 'a'-'A' ; make upper case
746 ret
747
748 ; error message components
749
750 operation$name:
751 dw read$msg
752 read$msg:
753 db ', Read, ',0
754 write$msg:
755 db ', Write, ',0
756 msg$drq:
757 db 'DRQ, ',0
758 error$table:
759 dw b7$msg
760 dw b6$msg
761 dw b5$msg
762 dw b4$msg
763 dw b3$msg
764 dw b2$msg
765 dw b1$msg
766 dw b0$msg
767
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
776
777
778 residual:
779 db 0
780
781 parttbl:
782 ds PARTENTRY_SIZE*MAXDISKS
783
784 tmpsecbuf: ;temporary sector buffer
785 ds 512
786
787 end