1 /* disk.c: Routines for handling disk images
2 Copyright (c) 2007-2017 Gergely Szasz
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 Author contact information:
20 Philip: philip-fuse@shadowmagic.org.uk
24 //==========================================================================
28 //==========================================================================
29 static int open_fdi (buffer_t
*buffer
, disk_t
*d
, int preindex
) {
31 int bpt
, bpt_fm
, max_bpt
= 0, max_bpt_fm
= 0;
32 int data_offset
, track_offset
, head_offset
, sector_offset
;
35 d
->wrprot
= (buff
[0x03] == 1 ? 1 : 0);
36 d
->sides
= buff
[0x06]+256*buff
[0x07];
37 d
->cylinders
= buff
[0x04]+256*buff
[0x05];
39 data_offset
= buff
[0x0a]+256*buff
[0x0b];
40 h
= (0x0e)+buff
[0x0c]+256*buff
[0x0d]; /* save head start */
43 /* first determine the longest track */
45 for (i
= 0; i
< d
->cylinders
*d
->sides
; ++i
) {
47 buffer
->index
= head_offset
;
48 if (buffread(head
, 7, buffer
) != 1) return (d
->status
= DISK_OPEN
); /* 7 := track head */
49 bpt
= postindex_len(d
, GAP_MINIMAL_MFM
)+
50 (preindex
? preindex_len(d
, GAP_MINIMAL_MFM
) : 0)+6; /* +gap4 */
51 bpt_fm
= postindex_len(d
, GAP_MINIMAL_FM
)+
52 (preindex
? preindex_len(d
, GAP_MINIMAL_FM
) : 0)+3; /* +gap4 */
53 /* calculate track len */
54 for (j
= 0; j
< head
[0x06]; ++j
) {
56 /* 35-sector header */
57 if (buffread(head
+7, 245, buffer
) != 1) {
58 /* 7*35 := max 35 sector head */
59 return d
->status
= DISK_OPEN
;
62 if ((head
[0x0b+7*(j
%35)]&0x3f) != 0) {
63 bpt
+= calc_sectorlen(1, 0x80<<head
[0x0a+7*(j
%35)], GAP_MINIMAL_MFM
);
64 bpt_fm
+= calc_sectorlen(0, 0x80<<head
[0x0a+7*(j
%35)], GAP_MINIMAL_FM
);
67 if (bpt
> max_bpt
) max_bpt
= bpt
;
68 if (bpt_fm
> max_bpt_fm
) max_bpt_fm
= bpt_fm
;
69 head_offset
+= 7+7*head
[0x06];
72 if (max_bpt
== 0 || max_bpt_fm
== 0) return (d
->status
= DISK_GEOM
);
74 d
->density
= DISK_DENS_AUTO
; /* disk_alloc use d->bpt */
75 if (max_bpt_fm
< 3000) {
76 /* we choose an SD disk with FM */
81 gap
= GAP_MINIMAL_MFM
;
83 if (disk_alloc(d
) != DISK_OK
) return d
->status
;
85 /* start reading the tracks */
86 head_offset
= h
; /* restore head start */
87 for (i
= 0; i
< d
->cylinders
*d
->sides
; ++i
) {
89 buffer
->index
= head_offset
;
90 buffread(head
, 7, buffer
); /* 7 = track head */
91 track_offset
= head
[0x00]+256*head
[0x01]+65536*head
[0x02]+16777216*head
[0x03];
92 DISK_SET_TRACK_IDX(d
, i
);
95 if (preindex
) preindex_add(d
, gap
);
96 postindex_add(d
, gap
);
98 for (j
= 0; j
< head
[0x06]; ++j
) {
100 /* if we have more than 35 sector in a track,
101 we have to seek back to the next sector
102 headers and read it (max 35 sector header) */
103 buffer
->index
= head_offset
+7*(j
+1);
104 buffread(head
+7, 245, buffer
); /* 7*35 := max 35 sector head */
106 id_add(d
, head
[0x08+7*(j
%35)], head
[0x07+7*(j
%35)],
107 head
[0x09+7*(j
%35)], head
[0x0a+7*(j
%35)], gap
,
108 (head
[0x0b+7*(j
%35)]&0x3f ? CRC_OK
: CRC_ERROR
));
109 sector_offset
= head
[0x0c+7*(j
%35)]+256*head
[0x0d+7*(j
%35)];
110 buffer
->index
= data_offset
+track_offset
+sector_offset
;
111 data_add(d
, buffer
, NULL
,
112 ((head
[0x0b+7*(j
%35)]&0x3f) == 0 ? -1 : 0x80<<head
[0x0a+7*(j
%35)]),
113 (head
[0x0b+7*(j
%35)]&0x80 ? DDAM
: NO_DDAM
),
114 gap
, CRC_OK
, NO_AUTOFILL
, NULL
);
116 head_offset
+= 7+7*head
[0x06];
120 return (d
->status
= DISK_OK
);
124 //==========================================================================
128 //==========================================================================
129 static int write_fdi (FILE *file
, disk_t
*d
) {
130 int i
, j
, k
, sbase
, sectors
, seclen
, mfm
, del
;
136 memcpy(head
, "FDI", 3);
137 head
[0x03] = d
->wrprot
= 1;
138 head
[0x04] = d
->cylinders
&0xff;
139 head
[0x05] = d
->cylinders
>>8;
140 head
[0x06] = d
->sides
&0xff;
141 head
[0x07] = d
->sides
>>8;
144 for (j
= 0; j
< d
->cylinders
; ++j
) {
145 for (i
= 0; i
< d
->sides
; ++i
) {
146 guess_track_geom(d
, i
, j
, &sbase
, &s
, &seclen
, &mfm
);
150 h
= (sectors
+d
->cylinders
*d
->sides
)*7; /* track header len */
151 head
[0x08] = (h
+0x0e)&0xff; /* description offset */
152 head
[0x09] = (h
+0x0e)>>8; /* "http://fuse-emulator.sourceforge.net" */
153 head
[0x0a] = (h
+0x33)&0xff; /* data offset */
154 head
[0x0b] = (h
+0x33)>>8;
156 if (fwrite(head
, 14, 1, file
) != 1) return (d
->status
= DISK_WRPART
);
158 /* write track headers */
159 toff
= 0; /* offset of track data */
160 for (i
= 0; i
< d
->cylinders
; ++i
) {
161 for (j
= 0; j
< d
->sides
; ++j
) {
162 DISK_SET_TRACK(d
, j
, i
);
164 head
[0x00] = toff
&0xff;
165 head
[0x01] = (toff
>>8)&0xff; /* track offset */
166 head
[0x02] = (toff
>>16)&0xff;
167 head
[0x03] = (toff
>>24)&0xff;
170 guess_track_geom(d
, j
, i
, &sbase
, §ors
, &seclen
, &mfm
);
171 head
[0x06] = sectors
;
173 if (fwrite(head
, 7, 1, file
) != 1) return (d
->status
= DISK_WRPART
);
175 DISK_SET_TRACK(d
, j
, i
);
179 while (sectors
> 0) {
180 while (k
< 35 && id_read(d
, &h
, &t
, &s
, &b
)) {
185 head
[0x05+k
*7] = soff
&0xff;
186 head
[0x06+k
*7] = (soff
>>8)&0xff;
187 if (!datamark_read(d
, &del
)) {
188 head
[0x04+k
*7] = 0; /* corrupt sector data */
190 head
[0x04+k
*7] = 1<<b
|(del
? 0x80 : 0x00);
196 if (fwrite(head
, 7*k
, 1, file
) != 1) return (d
->status
= DISK_WRPART
);
204 if (fwrite("http://fuse-emulator.sourceforge.net", 37, 1, file
) != 1) {
205 return (d
->status
= DISK_WRPART
);
209 for (i
= 0; i
< d
->cylinders
; ++i
) {
210 for (j
= 0; j
< d
->sides
; ++j
) {
211 if (saverawtrack(d
, file
, j
, i
)) return (d
->status
= DISK_WRPART
);
215 return (d
->status
= DISK_OK
);