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