2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
5 Desc: Amiga HW floppy stuff
9 #include <exec/types.h>
10 #include <devices/trackdisk.h>
11 #include <devices/timer.h>
12 #include <hardware/cia.h>
13 #include <hardware/custom.h>
14 #include <proto/cia.h>
15 #include <proto/disk.h>
16 #include <proto/exec.h>
18 #include <resources/disk.h>
20 #include "trackdisk_device.h"
21 #include "trackdisk_hw.h"
24 #include <aros/debug.h>
26 #define QUICKRETRYRCNT 8 // re-read retries before reseeking, must be power of 2
28 #define ioStd(x) ((struct IOStdReq *)x)
30 static void td_wait_start(struct TrackDiskBase
*tdb
, UWORD millis
)
32 // do not remove, AbortIO()+WaitIO() does not clear signal bit
33 // if AbortIO() finishes before WaitIO() waits.
34 SetSignal(0, 1L << tdb
->td_TimerMP2
->mp_SigBit
);
35 tdb
->td_TimerIO2
->tr_node
.io_Command
= TR_ADDREQUEST
;
36 tdb
->td_TimerIO2
->tr_time
.tv_secs
= millis
/ 1000;
37 tdb
->td_TimerIO2
->tr_time
.tv_micro
= (millis
% 1000) * 1000;
38 SendIO((struct IORequest
*)tdb
->td_TimerIO2
);
40 static void td_wait_end(struct TrackDiskBase
*tdb
)
42 WaitIO((struct IORequest
*)tdb
->td_TimerIO2
);
44 static void td_wait(struct TrackDiskBase
*tdb
, UWORD millis
)
46 td_wait_start(tdb
, millis
);
50 static UBYTE
const drvmask
[] = { ~0x08, ~0x10, ~0x20, ~0x40 };
51 void td_select(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
55 if (tdu
->tdu_selected
)
57 tdu
->tdu_selected
= TRUE
;
58 tmp
= tdb
->ciab
->ciaprb
;
59 tmp
|= 0x08 | 0x10 | 0x20 | 0x40;
60 tdb
->ciab
->ciaprb
= tmp
;
65 tdb
->ciab
->ciaprb
= tmp
;
66 tmp
&= drvmask
[tdu
->tdu_UnitNum
];
67 tdb
->ciab
->ciaprb
= tmp
;
70 void td_deselect(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
73 if (!tdu
->tdu_selected
)
75 tdu
->tdu_selected
= FALSE
;
76 tmp
= tdb
->ciab
->ciaprb
;
77 tmp
|= 0x08 | 0x10 | 0x20 | 0x40;
78 tdb
->ciab
->ciaprb
= tmp
;
80 tdb
->ciab
->ciaprb
= tmp
;
83 static void td_setside(UBYTE side
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
86 tdb
->ciab
->ciaprb
|= 0x4;
87 tdu
->pub
.tdu_CurrTrk
|= 1;
89 tdb
->ciab
->ciaprb
&= ~0x04;
90 tdu
->pub
.tdu_CurrTrk
&= ~1;
94 static void td_setdirection(UBYTE dir
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
97 tdb
->ciab
->ciaprb
|= 0x02;
99 tdb
->ciab
->ciaprb
&= ~0x02;
100 if (dir
!= tdb
->td_lastdir
) {
102 tdb
->td_lastdir
= dir
;
106 static void td_step(struct TDU
*tdu
, struct TrackDiskBase
*tdb
, UBYTE delay
)
108 tdb
->ciab
->ciaprb
&= ~0x01;
109 tdb
->ciab
->ciaprb
|= 0x01;
114 void td_motoron(struct TDU
*tdu
, struct TrackDiskBase
*tdb
, BOOL wait
)
116 if (tdu
->tdu_MotorOn
)
118 tdu
->tdu_MotorOn
= 1;
120 td_deselect(tdu
, tdb
);
127 void td_motoroff(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
129 if (!tdu
->tdu_MotorOn
)
131 tdu
->tdu_MotorOn
= 0;
133 td_deselect(tdu
, tdb
);
137 static BOOL
td_istrackzero(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
139 return (tdb
->ciaa
->ciapra
& 0x10) == 0;
142 UBYTE
td_getprotstatus(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
145 v
= (tdb
->ciaa
->ciapra
& 0x08) ? 0 : 1;
149 BOOL
td_recalibrate(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
151 BYTE steps
= 80 + 15;
153 td_setside(0, tdu
, tdb
);
154 td_wait(tdb
, tdu
->pub
.tdu_CalibrateDelay
);
155 if (td_istrackzero(tdu
, tdb
)) {
156 // step to cyl 1 if current cyl == 0
157 td_setdirection(0, tdu
, tdb
);
158 td_wait(tdb
, tdu
->pub
.tdu_SettleDelay
);
159 td_step(tdu
, tdb
, tdu
->pub
.tdu_CalibrateDelay
);
161 td_wait(tdb
, tdu
->pub
.tdu_SettleDelay
);
162 td_setdirection(1, tdu
, tdb
);
163 td_wait(tdb
, tdu
->pub
.tdu_SettleDelay
);
164 while (!td_istrackzero(tdu
, tdb
)) {
165 if (steps
< 0) // drive is broken?
167 td_step(tdu
, tdb
, tdu
->pub
.tdu_CalibrateDelay
);
170 td_wait(tdb
, tdu
->pub
.tdu_SettleDelay
);
171 tdu
->pub
.tdu_CurrTrk
= 0;
175 static UBYTE
td_seek2(struct TDU
*tdu
, UBYTE cyl
, UBYTE side
, struct TrackDiskBase
*tdb
, BOOL nowait
)
178 D(bug("seek=%d/%d\n", cyl
, side
));
179 td_setside(side
, tdu
, tdb
);
180 if (tdu
->pub
.tdu_CurrTrk
/ 2 == cyl
)
182 if (tdu
->pub
.tdu_CurrTrk
/ 2 > cyl
|| cyl
== 0xff)
186 td_setdirection(dir
, tdu
, tdb
);
187 while (cyl
!= tdu
->pub
.tdu_CurrTrk
/ 2) {
188 td_step(tdu
, tdb
, tdu
->pub
.tdu_StepDelay
);
189 if (tdu
->pub
.tdu_CurrTrk
/ 2 > cyl
&& tdu
->pub
.tdu_CurrTrk
>= 2)
190 tdu
->pub
.tdu_CurrTrk
-= 2;
191 else if (tdu
->pub
.tdu_CurrTrk
/ 2 < cyl
)
192 tdu
->pub
.tdu_CurrTrk
+= 2;
196 td_wait_start(tdb
, tdu
->pub
.tdu_SettleDelay
);
201 UBYTE
td_seek(struct TDU
*tdu
, int cyl
, int side
, struct TrackDiskBase
*tdb
)
203 return td_seek2(tdu
, cyl
, side
, tdb
, FALSE
);
205 UBYTE
td_seek_nowait(struct TDU
*tdu
, int cyl
, int side
, struct TrackDiskBase
*tdb
)
207 return td_seek2(tdu
, cyl
, side
, tdb
, TRUE
);
210 // 0 = no disk, 1 = disk inserted
211 UBYTE
td_getDiskChange(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
214 v
= (tdb
->ciaa
->ciapra
& 0x04) ? 1 : 0;
218 static BOOL
checkbuffer(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
220 // allocate HD sized buffer if HD disk inserted
221 if ((tdu
->tdu_hddisk
&& !tdb
->td_supportHD
) || !tdb
->td_DMABuffer
) {
222 FreeMem(tdb
->td_DMABuffer
, DISK_BUFFERSIZE
);
223 FreeMem(tdb
->td_DataBuffer
, 11 * 512);
224 tdb
->td_DMABuffer
= AllocMem(DISK_BUFFERSIZE
* 2, MEMF_CHIP
);
225 tdb
->td_DataBuffer
= AllocMem(22 * 512, MEMF_ANY
);
226 if (!tdb
->td_DMABuffer
|| !tdb
->td_DataBuffer
) {
227 FreeMem(tdb
->td_DMABuffer
, DISK_BUFFERSIZE
* 2);
228 FreeMem(tdb
->td_DataBuffer
, 22 * 512);
231 tdb
->td_supportHD
= TRUE
;
236 static UBYTE
td_readwritetrack(UBYTE track
, UBYTE write
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
240 UWORD dsklen
= 0x8000 | ((DISK_BUFFERSIZE
/ 2) * (tdu
->tdu_hddisk
? 2 : 1)) | (write
? 0x4000 : 0);
242 td_motoron(tdu
, tdb
, TRUE
);
244 SetSignal(0, 1L << tdb
->td_IntBit
);
246 tdb
->custom
->adkcon
= 0x0600;
247 tdb
->custom
->adkcon
= write
? 0x9100 : 0x9500;
248 tdb
->custom
->intreq
= 0x0002; // clear disk interrupt request
249 tdb
->custom
->intena
= 0x8002; // enable disk interrupt
250 tdb
->custom
->dmacon
= 0x8010; // enable DMA
252 tdb
->custom
->dskpt
= tdb
->td_DMABuffer
;
253 tdb
->custom
->dsklen
= dsklen
;
254 tdb
->custom
->dsklen
= dsklen
; // dma started
255 D(bug("td diskdma started, track=%d write=%d len=%d\n", track
, write
, dsklen
& 0x3fff));
257 td_wait_start(tdb
, (tdu
->tdu_hddisk
? 2 : 1) * 1000);
258 sigs
= Wait((1L << tdb
->td_TimerMP2
->mp_SigBit
) | (1L << tdb
->td_IntBit
));
260 tdb
->custom
->dsklen
= 0x4000;
261 tdb
->custom
->intena
= 0x0002;
263 err
= TDERR_BadSecPreamble
;
264 if (sigs
& (1L << tdb
->td_IntBit
)) {
267 AbortIO((struct IORequest
*)tdb
->td_TimerIO2
);
269 WaitIO((struct IORequest
*)tdb
->td_TimerIO2
);
270 D(bug("td diskdma finished, err=%d\n", err
));
272 if (td_getDiskChange(tdu
, tdb
) == 0)
273 err
= TDERR_DiskChanged
;
278 static void make_crc_table16(struct TrackDiskBase
*tdb
)
283 tdb
->crc_table16
= AllocMem(256 * sizeof(UWORD
), MEMF_ANY
);
284 if (!tdb
->crc_table16
)
286 for (n
= 0; n
< 256; n
++) {
288 for (k
= 0; k
< 8; k
++) {
289 w
= (w
<< 1) ^ ((w
& 0x8000) ? 0x1021 : 0);
291 tdb
->crc_table16
[n
] = w
;
295 static UWORD
get_crc16_next(struct TrackDiskBase
*tdb
, void *vbuf
, UWORD len
, UWORD crc
)
297 UBYTE
*buf
= (UBYTE
*)vbuf
;
299 crc
= (crc
<< 8) ^ tdb
->crc_table16
[((crc
>> 8) ^ (*buf
++)) & 0xff];
302 static UWORD
get_crc16(struct TrackDiskBase
*tdb
, void *vbuf
, UWORD len
)
304 if (!tdb
->crc_table16
) {
305 make_crc_table16(tdb
);
306 if (!tdb
->crc_table16
)
309 return get_crc16_next(tdb
, vbuf
, len
, 0xffff);
312 /* Following really needs optimization... */
313 static UBYTE
mfmdecode (UWORD
**mfmp
)
322 for (i
= 0; i
< 8; i
++) {
331 /* PC floppy format decoding is very expensive compared to ADOS... */
332 static UBYTE
td_decodebuffer_pcdos(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
337 UBYTE
*data
= tdb
->td_DataBuffer
;
341 UBYTE current_head
, current_cyl
;
343 tmp
[0] = tmp
[1] = tmp
[2] = 0xa1;
345 datacrc
= get_crc16(tdb
, tmp
, 4);
346 current_head
= tdb
->td_buffer_track
& 1;
347 current_cyl
= tdb
->td_buffer_track
/ 2;
350 raw
= tdb
->td_DMABuffer
;
351 rawend
= tdb
->td_DMABuffer
+ DISK_BUFFERSIZE
* (tdu
->tdu_hddisk
? 2 : 1);
353 while (tdb
->td_sectorbits
!= (1 << tdu
->tdu_sectors
) - 1) {
358 if (raw
!= tdb
->td_DMABuffer
) {
359 while (*raw
!= 0x4489) {
362 lasterr
= TDERR_TooFewSecs
;
368 while (*raw
== 0x4489 && raw
< rawend
)
370 if (raw
>= rawend
- 8) {
372 lasterr
= TDERR_TooFewSecs
;
375 mark
= mfmdecode(&raw
);
377 UBYTE cyl
, head
, size
;
379 cyl
= mfmdecode (&raw
);
380 head
= mfmdecode (&raw
);
381 sector
= mfmdecode (&raw
);
382 size
= mfmdecode (&raw
);
383 crc
= (mfmdecode (&raw
) << 8) | mfmdecode (&raw
);
385 tmp
[0] = 0xa1; tmp
[1] = 0xa1; tmp
[2] = 0xa1; tmp
[3] = mark
;
386 tmp
[4] = cyl
; tmp
[5] = head
; tmp
[6] = sector
; tmp
[7] = size
;
387 if (get_crc16(tdb
, tmp
, 8) != crc
|| cyl
!= current_cyl
|| head
!= current_head
|| size
!= 2 || sector
< 1 || sector
> tdu
->tdu_sectors
) {
388 D(bug("PCDOS: corrupted sector header. cyl=%d head=%d sector=%d size=%d crc=%04x\n",
389 cyl
, head
, sector
, size
, crc
));
397 D(bug("PCDOS: unknown address mark %02X\n", mark
));
402 if (raw
>= rawend
- 512) {
404 lasterr
= TDERR_TooFewSecs
;
407 secdata
= data
+ sector
* 512;
408 for (i
= 0; i
< 512; i
++)
409 secdata
[i
] = mfmdecode (&raw
);
410 crc
= (mfmdecode (&raw
) << 8) | mfmdecode (&raw
);
411 if (get_crc16_next(tdb
, secdata
, 512, datacrc
) != crc
) {
412 D(bug("PCDOS: sector %d data checksum error\n", sector
+ 1));
415 D(bug("PCDOS: read sector %d\n", sector
));
416 tdb
->td_sectorbits
|= 1 << sector
;
420 D(bug("PCDOS: err=%d secmask=%08x\n", lasterr
, tdb
->td_sectorbits
));
425 static ULONG
getmfmlong(UWORD
*mfmbuf
)
427 return ((ULONG
*)mfmbuf
)[0] & 0x55555555;
429 static ULONG
getdecodedlong(UWORD
*mfmbuf
, UWORD offset
)
431 ULONG odd
= getmfmlong(mfmbuf
);
432 ULONG even
= getmfmlong(mfmbuf
+ offset
);
433 return (odd
<< 1) | even
;
435 static ULONG
getdecodedlongchk(UWORD
*mfmbuf
, UWORD offset
, ULONG
*chksum
)
437 ULONG odd
= getmfmlong(mfmbuf
);
438 ULONG even
= getmfmlong(mfmbuf
+ offset
);
439 *chksum
^= odd
^ even
;
440 return (odd
<< 1) | even
;
443 static UBYTE
td_decodebuffer_ados(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
448 UBYTE
*data
= tdb
->td_DataBuffer
;
451 raw
= tdb
->td_DMABuffer
;
452 rawend
= tdb
->td_DMABuffer
+ DISK_BUFFERSIZE
* (tdu
->tdu_hddisk
? 2 : 1);
453 while (tdb
->td_sectorbits
!= (1 << tdu
->tdu_sectors
) - 1) {
454 UWORD
*rawnext
= raw
;
456 ULONG chksum
, id
, dlong
;
459 if (raw
!= tdb
->td_DMABuffer
) {
460 while (*raw
!= 0x4489) {
463 lasterr
= TDERR_TooFewSecs
;
469 while (*raw
== 0x4489 && raw
< rawend
)
471 if (raw
+ 544 >= rawend
) {
473 lasterr
= TDERR_TooFewSecs
;
477 rawnext
= raw
+ 544 - 3;
480 id
= getdecodedlongchk(raw
, 2, &chksum
);
483 trackoffs
= (id
& 0xff00) >> 8;
484 if (trackoffs
>= tdu
->tdu_sectors
|| (id
& 0xff000000) != 0xff000000) {
485 lasterr
= TDERR_BadSecHdr
;
486 D(bug("td_decodebuffer trackid=%08x\n", id
));
487 continue; // corrupt sector number
489 if (tdb
->td_sectorbits
& (1 << trackoffs
)) {
490 // skip sector if it has already been successfully decoded and copied
495 for (i
= 0; i
< 4; i
++) {
496 getdecodedlongchk(raw
, 8, &chksum
);
500 dlong
= getdecodedlong(raw
, 2);
502 // header checksum ok?
503 if (dlong
!= chksum
) {
504 lasterr
= TDERR_BadHdrSum
;
505 D(bug("td_decodebuffer sector %d header checksum error\n", trackoffs
));
509 if (((id
& 0x00ff0000) >> 16) != tdb
->td_buffer_track
) {
510 lasterr
= TDERR_BadSecHdr
;
511 D(bug("td_decodebuffer sector %d header track mismatch (%d<>%d)\n",
512 trackoffs
, (id
& 0x00ff0000) >> 16, tdb
->td_buffer_track
));
517 chksum
= getdecodedlong(raw
, 2);
519 secdata
= data
+ trackoffs
* 512;
520 for (i
= 0; i
< 128; i
++) {
521 dlong
= getdecodedlongchk(raw
, 256, &chksum
);
523 *secdata
++ = dlong
>> 24;
524 *secdata
++ = dlong
>> 16;
525 *secdata
++ = dlong
>> 8;
529 lasterr
= TDERR_BadSecSum
;
530 D(bug("td_decodebuffer sector %d data checksum error\n", trackoffs
));
531 continue; // data checksum error
533 tdb
->td_sectorbits
|= 1 << trackoffs
;
536 D(bug("td_decodebuffer err=%d secmask=%08x\n", lasterr
, tdb
->td_sectorbits
));
540 static UBYTE
td_decodebuffer(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
542 if (tdu
->tdu_disktype
== DT_ADOS
)
543 return td_decodebuffer_ados(tdu
, tdb
);
544 else if (tdu
->tdu_disktype
== DT_PCDOS
)
545 return td_decodebuffer_pcdos(tdu
, tdb
);
546 return TDERR_TooFewSecs
;
549 static void mfmcode (ULONG
*mfm
, UWORD longs
)
551 ULONG prev
= mfm
[-1];
553 ULONG v
= (*mfm
) & 0x55555555;
554 // if mask1 is not set (previous bit) and mask2 (current bit) is not set: set bit.
555 ULONG mask1
= (prev
<< 31) | (v
>> 1);
556 ULONG mask2
= v
<< 1;
557 // mfmbits bit set only if bits in both masks are zero.
558 ULONG mfmbits
= ((~mask1
) & (~mask2
)) & 0xaaaaaaaa;
565 static void td_encodebuffer_ados(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
569 UBYTE
*databuf
= tdb
->td_DataBuffer
;
570 ULONG
*mfmbuf
= (ULONG
*)tdb
->td_DMABuffer
;
571 UWORD bufsize
= DISK_BUFFERSIZE
* (tdu
->tdu_hddisk
? 2 : 1);
572 UWORD gapsize
= bufsize
- tdu
->tdu_sectors
* 2 * 544;
574 for (i
= 0; i
< gapsize
/ 4 - 1; i
++)
575 *mfmbuf
++ = 0xaaaaaaaa;
577 for (sec
= 0; sec
< tdu
->tdu_sectors
; sec
++) {
579 ULONG hck
= 0, dck
= 0;
581 // make sure we have valid MFM clock bit here!
583 mfmbuf
[0] = 0x2aaaaaaa;
585 mfmbuf
[0] = 0xaaaaaaaa;
586 mfmbuf
[1] = 0x44894489;
588 deven
= (0xff << 24) | (tdb
->td_buffer_track
<< 16) | (sec
<< 8) | ((tdu
->tdu_sectors
- sec
) << 0);
597 for (i
= 4; i
< 12; i
++)
600 for (i
= 0; i
< 128; i
++) {
601 deven
= ((ULONG
*)databuf
)[i
];
605 mfmbuf
[ 0 + 16 + i
] = dodd
;
606 mfmbuf
[128 + 16 + i
] = deven
;
621 mfmcode (mfmbuf
+ 2, 2 * 128 + 16 - 2);
624 mfmbuf
+= 2 * 128 + 16;
630 static void td_encodebuffer(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
632 if (tdu
->tdu_disktype
== DT_ADOS
)
633 td_encodebuffer_ados(tdu
, tdb
);
636 static UBYTE
td_readbuffer(UBYTE track
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
640 if (tdb
->td_buffer_unit
!= tdu
->tdu_UnitNum
|| tdb
->td_buffer_track
!= track
)
641 tdb
->td_sectorbits
= 0;
642 tdb
->td_buffer_unit
= tdu
->tdu_UnitNum
;
643 tdb
->td_buffer_track
= track
;
645 td_seek(tdu
, track
>> 1, track
& 1, tdb
);
646 ret
= td_readwritetrack(track
, 0, tdu
, tdb
);
648 D(bug("td_readbuffer TRK=%d td_readwritetrack ERR=%d\n", track
, ret
));
649 tdb
->td_sectorbits
= 0;
652 ret
= td_decodebuffer(tdu
, tdb
);
653 D(bug("td_readbuffer td_decodebuffer ERR=%d MASK=%08x\n", ret
, tdb
->td_sectorbits
));
657 static void maybe_detect(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
659 if (tdu
->tdu_disktype
== DT_UNDETECTED
)
660 td_detectformat(tdu
, tdb
);
663 static UBYTE
maybe_flush(struct TDU
*tdu
, struct TrackDiskBase
*tdb
, int track
)
665 if (tdb
->td_buffer_unit
!= tdu
->tdu_UnitNum
|| tdb
->td_buffer_track
!= track
) {
667 err
= td_flush(tdu
, tdb
);
674 UBYTE
td_read(struct IOExtTD
*iotd
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
682 if (tdu
->tdu_DiskIn
== TDU_NODISK
)
683 return TDERR_DiskChanged
;
684 if (checkbuffer(tdu
, tdb
))
686 maybe_detect(tdu
, tdb
);
688 iotd
->iotd_Req
.io_Actual
= 0;
689 offset
= iotd
->iotd_Req
.io_Offset
;
690 len
= iotd
->iotd_Req
.io_Length
;
691 data
= iotd
->iotd_Req
.io_Data
;
693 D(bug("td_read: DATA=%x OFFSET=%x (TRK=%d) LEN=%d\n", data
, offset
, offset
/ (512 * tdu
->tdu_sectors
), len
));
697 totalretries
= (tdu
->pub
.tdu_RetryCnt
+ 1) * QUICKRETRYRCNT
- 1;
699 while (len
> 0 && totalretries
>= 0) {
701 UBYTE largestsectorneeded
, smallestsectorneeded
, totalsectorsneeded
;
703 UBYTE sec
, sectorsdone
;
705 track
= offset
/ (512 * tdu
->tdu_sectors
);
710 if ((totalretries
% QUICKRETRYRCNT
) == 0) {
711 if (!td_recalibrate(tdu
, tdb
)) {
712 err
= TDERR_SeekError
;
717 err
= maybe_flush(tdu
, tdb
, track
);
720 if (tdb
->td_buffer_unit
!= tdu
->tdu_UnitNum
|| tdb
->td_buffer_track
!= track
)
721 err
= td_readbuffer(track
, tdu
, tdb
);
723 smallestsectorneeded
= (offset
/ 512) % tdu
->tdu_sectors
;
724 largestsectorneeded
= smallestsectorneeded
+ len
/ 512;
725 if (largestsectorneeded
> tdu
->tdu_sectors
|| len
/ 512 > tdu
->tdu_sectors
) {
726 UBYTE nexttrack
= track
+ 1;
727 if (nexttrack
< 160) {
728 // start stepping to next track in advance (pointless but..)
729 td_seek_nowait(tdu
, nexttrack
>> 1, nexttrack
& 1, tdb
);
732 largestsectorneeded
= tdu
->tdu_sectors
;
734 totalsectorsneeded
= largestsectorneeded
- smallestsectorneeded
;
737 for (sec
= smallestsectorneeded
; sec
< largestsectorneeded
; sec
++) {
738 if (tdb
->td_sectorbits
& (1 << sec
)) {
739 CopyMem(tdb
->td_DataBuffer
+ sec
* 512, data
+ (sec
- smallestsectorneeded
) * 512, 512);
744 D(bug("td_read2 TRK=%d MIN=%d MAX=%d DONE=%d\n", track
, smallestsectorneeded
, largestsectorneeded
, sectorsdone
));
746 if (sectorsdone
< totalsectorsneeded
) {
747 // errors, force re-read
748 tdb
->td_buffer_unit
= -1;
749 // couldn't decode any sectors = reseek immediately
750 if (tdb
->td_sectorbits
== 0)
751 totalretries
= (totalretries
- 1) & ~(QUICKRETRYRCNT
- 1);
757 data
+= sectorsdone
* 512;
758 offset
+= sectorsdone
* 512;
759 len
-= sectorsdone
* 512;
760 iotd
->iotd_Req
.io_Actual
+= sectorsdone
* 512;
767 D(bug("td_read2 ERR=%d io_Actual=%d\n", err
, iotd
->iotd_Req
.io_Actual
));
771 static UBYTE
td_write2(struct IOExtTD
*iotd
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
777 if (checkbuffer(tdu
, tdb
))
781 iotd
->iotd_Req
.io_Actual
= 0;
782 offset
= iotd
->iotd_Req
.io_Offset
;
783 len
= iotd
->iotd_Req
.io_Length
;
784 data
= iotd
->iotd_Req
.io_Data
;
786 D(bug("TD_WRITE: DATA=%x OFFSET=%x (TRK=%d) LEN=%d\n", data
, offset
, offset
/ (512 * tdu
->tdu_sectors
), len
));
789 UBYTE track
, sec
, totalsectorsneeded
;
790 UBYTE smallestsectorneeded
, largestsectorneeded
;
792 track
= offset
/ (512 * tdu
->tdu_sectors
);
793 err
= maybe_flush(tdu
, tdb
, track
);
796 tdb
->td_buffer_unit
= tdu
->tdu_UnitNum
;
797 tdb
->td_buffer_track
= track
;
799 smallestsectorneeded
= (offset
/ 512) % tdu
->tdu_sectors
;
800 largestsectorneeded
= smallestsectorneeded
+ len
/ 512;
801 if (largestsectorneeded
> tdu
->tdu_sectors
|| len
/ 512 > tdu
->tdu_sectors
)
802 largestsectorneeded
= tdu
->tdu_sectors
;
803 totalsectorsneeded
= largestsectorneeded
- smallestsectorneeded
;
805 D(bug("TD_WRITE: TRK=%d MIN=%d MAX=%d MASK=%08x\n",
806 track
, smallestsectorneeded
, largestsectorneeded
, tdb
->td_sectorbits
));
808 // fill buffer with new data
809 for (sec
= smallestsectorneeded
; sec
< largestsectorneeded
; sec
++) {
810 CopyMem(data
+ (sec
- smallestsectorneeded
) * 512, tdb
->td_DataBuffer
+ sec
* 512, 512);
811 tdb
->td_sectorbits
|= 1 << sec
;
812 tdb
->td_dirty
= TRUE
;
815 data
+= totalsectorsneeded
* 512;
816 offset
+= totalsectorsneeded
* 512;
817 len
-= totalsectorsneeded
* 512;
818 iotd
->iotd_Req
.io_Actual
+= totalsectorsneeded
* 512;
823 UBYTE
td_write(struct IOExtTD
*iotd
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
826 if (tdu
->tdu_DiskIn
== TDU_NODISK
)
827 return TDERR_DiskChanged
;
828 if (tdu
->tdu_disktype
!= DT_ADOS
)
829 return TDERR_WriteProt
;
830 if (!td_getprotstatus(tdu
, tdb
)) {
831 err
= td_write2(iotd
, tdu
, tdb
);
833 err
= TDERR_WriteProt
;
838 void td_clear(struct TrackDiskBase
*tdb
)
840 tdb
->td_buffer_unit
= -1;
841 tdb
->td_sectorbits
= 0;
845 UBYTE
td_flush(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
850 if (tdb
->td_buffer_unit
!= tdu
->tdu_UnitNum
)
857 td_seek(tdu
, tdb
->td_buffer_track
>> 1, tdb
->td_buffer_track
& 1, tdb
);
858 D(bug("td_flush, writing unit %d track %d wmask=%08x\n",
859 tdb
->td_buffer_unit
, tdb
->td_buffer_track
, tdb
->td_sectorbits
));
861 totalretries
= (tdu
->pub
.tdu_RetryCnt
+ 1) * QUICKRETRYRCNT
- 1;
862 // read all non-modified sectors from disk (if needed)
864 while (tdb
->td_sectorbits
!= (1 << tdu
->tdu_sectors
) - 1) {
865 if ((totalretries
% QUICKRETRYRCNT
) == 0) {
866 if (!td_recalibrate(tdu
, tdb
)) {
868 tdb
->td_buffer_unit
= -1;
869 return TDERR_SeekError
;
872 err
= td_readbuffer(tdb
->td_buffer_track
, tdu
, tdb
);
875 D(bug("TD_FLUSH READBUF ERR=%d MASK=%08x\n", err
, tdb
->td_sectorbits
));
876 if (totalretries
-- <= 0) {
877 bug("TD_FLUSH disk error track %d, written data was lost!\n", tdb
->td_buffer_track
);
879 tdb
->td_buffer_unit
= -1;
880 return lasterr
? lasterr
: TDERR_NotSpecified
;
884 td_encodebuffer(tdu
, tdb
);
886 err
= td_readwritetrack(tdb
->td_buffer_track
, 1, tdu
, tdb
);
892 static UBYTE
td_format2(struct IOExtTD
*iotd
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
898 if (checkbuffer(tdu
, tdb
))
900 if (tdu
->tdu_disktype
!= DT_ADOS
)
901 return TDERR_WriteProt
;
902 iotd
->iotd_Req
.io_Actual
= 0;
903 offset
= iotd
->iotd_Req
.io_Offset
;
904 len
= iotd
->iotd_Req
.io_Length
;
905 data
= iotd
->iotd_Req
.io_Data
;
906 D(bug("TD_FORMAT: DATA=%x OFFSET=%x (TRK=%d) LEN=%d\n", data
, offset
, offset
/ (512 * tdu
->tdu_sectors
), len
));
907 while (len
>= tdu
->tdu_sectors
* 512) {
908 int track
= offset
/ (512 * tdu
->tdu_sectors
);
911 td_seek(tdu
, track
>> 1, track
& 1, tdb
);
912 CopyMem(data
, tdb
->td_DataBuffer
, tdu
->tdu_sectors
* 512);
913 tdb
->td_sectorbits
= (1 << tdu
->tdu_sectors
) - 1;
914 tdb
->td_buffer_unit
= tdu
->tdu_UnitNum
;
915 tdb
->td_buffer_track
= track
;
916 td_encodebuffer(tdu
, tdb
);
917 err
= td_readwritetrack(tdb
->td_buffer_track
, 1, tdu
, tdb
);
921 data
+= tdu
->tdu_sectors
* 512;
922 offset
+= tdu
->tdu_sectors
* 512;
923 iotd
->iotd_Req
.io_Actual
+= tdu
->tdu_sectors
* 512;
924 len
-= tdu
->tdu_sectors
* 512;
930 UBYTE
td_format(struct IOExtTD
*iotd
, struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
933 if (tdu
->tdu_DiskIn
== TDU_NODISK
)
934 return TDERR_DiskChanged
;
935 if (!td_getprotstatus(tdu
, tdb
)) {
937 err
= td_format2(iotd
, tdu
, tdb
);
939 err
= TDERR_WriteProt
;
944 static UBYTE
countbits(ULONG mask
)
954 void td_detectformat(struct TDU
*tdu
, struct TrackDiskBase
*tdb
)
960 D(bug("detectformat HD=%d\n", tdu
->tdu_hddisk
? 1 : 0));
961 if (checkbuffer(tdu
, tdb
)) {
962 tdu
->tdu_disktype
= DT_ADOS
;
963 tdu
->tdu_sectors
= tdu
->tdu_hddisk
? 22 : 11;
966 tdu
->tdu_disktype
= DT_UNDETECTED
;
967 tdb
->td_sectorbits
= 0;
968 tdb
->td_buffer_unit
= tdu
->tdu_UnitNum
;
969 tdb
->td_buffer_track
= track
;
971 td_seek(tdu
, track
>> 1, track
& 1, tdb
);
972 tdu
->tdu_sectors
= tdu
->tdu_hddisk
? 22 : 11;
973 err
= td_readwritetrack(track
, 0, tdu
, tdb
);
975 err
= td_decodebuffer_ados(tdu
, tdb
);
976 /* Did all sectors fail to decode? It could be non-ADOS disk */
977 if (err
&& tdb
->td_sectorbits
== 0) {
978 tdu
->tdu_sectors
= tdu
->tdu_hddisk
? 18 : 9;
979 err
= td_decodebuffer_pcdos(tdu
, tdb
);
980 cnt
= countbits(tdb
->td_sectorbits
);
981 if (cnt
> tdu
->tdu_sectors
/ 2 + 1) {
982 /* enough sectors decoded fine, assume PCDOS */
983 tdu
->tdu_disktype
= DT_PCDOS
;
986 tdu
->tdu_disktype
= DT_ADOS
;
989 if (tdu
->tdu_disktype
== DT_UNDETECTED
) {
990 tdu
->tdu_disktype
= DT_ADOS
;
991 tdu
->tdu_sectors
= tdu
->tdu_hddisk
? 22 : 11;
992 tdb
->td_sectorbits
= 0;
994 D(bug("detectformat=%d sectors=%d sectormask=%08x\n", tdu
->tdu_disktype
, tdu
->tdu_sectors
, tdb
->td_sectorbits
));