revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / plugins / fdi / fdi.c
blob0cf741191db5b90d15a05cdbcb40b541679b81b9
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #define USED_PLUGIN_API_VERSION 8
28 #include <devices/diskimage.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <string.h>
32 #include "endian.h"
33 #include "fdi2raw.h"
34 #include "device_locale.h"
35 #include <SDI_compiler.h>
36 #include "rev/diskimage.device_rev.h"
38 PLUGIN_VERSTAG("FDI")
40 extern struct DiskImagePlugin fdi_plugin;
42 PLUGIN_TABLE(&fdi_plugin)
44 BOOL FDI_Init (struct DiskImagePlugin *Self, const struct PluginData *data);
45 void FDI_Exit (struct DiskImagePlugin *Self);
46 BOOL FDI_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
47 const UBYTE *test, LONG testsize);
48 APTR FDI_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name);
49 void FDI_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr);
50 LONG FDI_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg);
51 LONG FDI_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io);
53 struct DiskImagePlugin fdi_plugin = {
54 PLUGIN_NODE(0, "FDI"),
55 PLUGIN_FLAG_M68K,
56 27,
57 ZERO,
58 NULL,
59 FDI_Init,
60 FDI_Exit,
61 FDI_CheckImage,
62 FDI_OpenImage,
63 FDI_CloseImage,
64 FDI_Geometry,
65 FDI_Read,
66 NULL,
67 NULL,
68 NULL,
69 NULL,
70 NULL
73 struct Library *SysBase;
74 struct Library *DOSBase;
75 struct DIPluginIFace *IPlugin;
76 #ifndef __AROS__
77 struct Library *MathIeeeDoubBasBase;
78 #endif
80 BOOL FDI_Init (struct DiskImagePlugin *Self, const struct PluginData *data) {
81 SysBase = data->SysBase;
82 DOSBase = data->DOSBase;
83 IPlugin = data->IPlugin;
84 return TRUE;
87 void FDI_Exit (struct DiskImagePlugin *Self) {
88 #ifndef __AROS__
89 if (MathIeeeDoubBasBase) CloseLibrary(MathIeeeDoubBasBase);
90 #endif
93 BOOL FDI_CheckImage (struct DiskImagePlugin *Self, BPTR file, CONST_STRPTR name, QUAD file_size,
94 const UBYTE *test, LONG testsize)
96 return testsize >= 27 && !memcmp(test, "Formatted Disk Image file\r\n", 27);
99 struct FDIImage {
100 BPTR file;
101 FDI *fdi;
102 ULONG tracks;
103 ULONG heads;
104 ULONG sectors;
105 UWORD *mfmbuf;
106 UWORD *tracktiming;
107 ULONG track_in_buf;
108 ULONG mfmbuf_size;
109 ULONG track_size;
110 ULONG tracklen;
113 APTR FDI_OpenImage (struct DiskImagePlugin *Self, APTR unit, BPTR file, CONST_STRPTR name) {
114 LONG done = FALSE;
115 LONG error = NO_ERROR;
116 LONG error_string = NO_ERROR_STRING;
117 IPTR error_args[4] = {0};
118 struct FDIImage *image = NULL;
120 #ifndef __AROS__
121 if (!MathIeeeDoubBasBase) {
122 MathIeeeDoubBasBase = OpenLibrary("mathieeedoubbas.library", 0);
123 if (!MathIeeeDoubBasBase) {
124 error = ERROR_OBJECT_NOT_FOUND;
125 error_string = MSG_REQ;
126 error_args[0] = (IPTR)"mathieeedoubbas.library";
127 goto error;
130 #endif
132 image = AllocVec(sizeof(*image), MEMF_CLEAR);
133 if (!image) {
134 error = ERROR_NO_FREE_STORE;
135 goto error;
137 image->file = file;
139 image->fdi = fdi2raw_header(image->file);
140 if (!image->fdi) {
141 error = IoErr();
142 goto error;
145 image->tracks = fdi2raw_get_last_track(image->fdi);
146 image->heads = fdi2raw_get_last_head(image->fdi)+1;
147 image->sectors = fdi2raw_get_num_sector(image->fdi);
148 image->track_size = image->sectors << 9;
150 image->mfmbuf_size = 0x8000;
151 if (image->sectors == 22) image->mfmbuf_size *= 2;
153 image->mfmbuf = AllocVec(image->mfmbuf_size, MEMF_ANY);
154 image->tracktiming = AllocVec(image->mfmbuf_size, MEMF_CLEAR);
155 if (!image->mfmbuf || !image->tracktiming) {
156 error = ERROR_NO_FREE_STORE;
157 goto error;
159 image->track_in_buf = ~0;
161 done = TRUE;
163 error:
164 if (!done) {
165 if (image) {
166 Plugin_CloseImage(Self, image);
167 image = NULL;
168 } else {
169 Close(file);
171 if (error == NO_ERROR) {
172 error = ERROR_OBJECT_WRONG_TYPE;
173 error_string = MSG_EOF;
175 IPlugin_SetDiskImageErrorA(unit, error, error_string, error_args);
177 return image;
180 void FDI_CloseImage (struct DiskImagePlugin *Self, APTR image_ptr) {
181 struct FDIImage *image = image_ptr;
182 if (image) {
183 if (image->fdi) fdi2raw_header_free(image->fdi);
184 FreeVec(image->mfmbuf);
185 FreeVec(image->tracktiming);
186 Close(image->file);
187 FreeVec(image);
191 LONG FDI_Geometry (struct DiskImagePlugin *Self, APTR image_ptr, struct DriveGeometry *dg) {
192 struct FDIImage *image = image_ptr;
193 dg->dg_SectorSize = 512;
194 dg->dg_Heads = image->heads;
195 dg->dg_Cylinders = image->tracks / image->heads;
196 dg->dg_TrackSectors = image->sectors;
197 dg->dg_CylSectors = image->sectors * image->heads;
198 dg->dg_TotalSectors = image->sectors * image->tracks;
199 return IOERR_SUCCESS;
202 static LONG read_sector (UBYTE *buf, int track, int sector, UWORD *data, LONG len);
203 static UWORD getmfmword (const UWORD *mbuf, ULONG shift);
204 static ULONG getmfmlong (const UWORD *mbuf, ULONG shift);
206 LONG FDI_Read (struct DiskImagePlugin *Self, APTR image_ptr, struct IOStdReq *io) {
207 struct FDIImage *image = image_ptr;
208 UBYTE *buffer;
209 ULONG offset, size;
210 LONG track, block, sectors;
211 unsigned int tracklen;
212 FDI *fdi = image->fdi;
213 UWORD *mfmbuf = image->mfmbuf;
214 LONG error;
216 buffer = io->io_Data;
217 offset = io->io_Offset;
218 size = io->io_Length;
219 io->io_Actual = 0;
221 if (offset & 511) return IOERR_BADADDRESS;
222 if (size & 511) return IOERR_BADLENGTH;
224 offset >>= 9;
225 size >>= 9;
227 sectors = image->sectors;
228 track = offset / sectors;
229 block = offset % sectors;
231 while (size) {
232 if (track != image->track_in_buf) {
234 if (track >= image->tracks) return TDERR_SeekError;
236 tracklen = 0;
237 if (!fdi2raw_loadtrack(fdi, mfmbuf, image->tracktiming,
238 track, &tracklen, NULL, NULL, 1) || !tracklen)
240 image->track_in_buf = ~0;
241 return TDERR_NotSpecified;
243 image->tracklen = tracklen >>= 3;
244 image->track_in_buf = track;
245 } else {
246 tracklen = image->tracklen;
249 for (; size && block < sectors; block++, size--) {
250 error = read_sector(buffer, track, block, mfmbuf, tracklen);
251 if (error) {
252 /*DebugPrintF("error: %ld, track: %ld, block: %ld, tracklen: %ld\n",
253 error, track, block, tracklen);*/
254 return error;
256 buffer += 512;
257 io->io_Actual += 512;
260 block = 0;
261 track++;
263 return IOERR_SUCCESS;
266 static LONG read_sector (UBYTE *buf, int track, int sector, UWORD *data, LONG len) {
267 ULONG shift = 0;
268 ULONG odd, even, chksum, id, dlong;
269 UWORD *end;
270 ULONG i;
272 end = data + ((len+1) >> 1);
273 end -= 540;
275 while (data <= end) {
276 while (getmfmword(data, shift) != 0x4489) {
277 if (data >= end) {
278 return TDERR_NoSecHdr;
280 shift++;
281 if (shift == 16) {
282 shift = 0;
283 data++;
286 while (getmfmword(data, shift) == 0x4489) {
287 if (data >= end) return TDERR_BadSecPreamble;
288 data++;
291 odd = getmfmlong(data, shift);
292 even = getmfmlong(data + 2, shift);
293 data += 4;
294 id = (odd << 1)|even;
295 chksum = odd ^ even;
296 for (i = 0; i < 4; i++) {
297 odd = getmfmlong(data, shift);
298 even = getmfmlong(data + 8, shift);
299 data += 2;
301 dlong = (odd << 1)|even;
302 chksum ^= odd ^ even;
304 data += 8;
305 odd = getmfmlong(data, shift);
306 even = getmfmlong(data + 2, shift);
307 data += 4;
308 if (((odd << 1)|even) != chksum ||
309 ((id & 0xff000000) >> 24) != 0xff ||
310 ((id & 0x00ff0000) >> 16) != track)
312 return TDERR_BadSecHdr;
315 odd = getmfmlong(data, shift);
316 even = getmfmlong(data + 2, shift);
317 data += 4;
318 chksum = (odd << 1)|even;
319 if (((id & 0x0000ff00) >> 8) == sector) {
320 for (i = 0; i < 128; i++) {
321 odd = getmfmlong(data, shift);
322 even = getmfmlong(data + 256, shift);
323 data += 2;
324 dlong = (odd << 1)|even;
325 wbe32(buf, dlong);
326 buf += 4;
327 chksum ^= odd ^ even;
329 if (chksum) {
330 return TDERR_BadSecSum;
332 return IOERR_SUCCESS;
334 data += 512;
337 return TDERR_NoSecHdr;
340 #define MFMMASK 0x55555555
342 static UWORD getmfmword (const UWORD *mbuf, ULONG shift) {
343 return (rbe16(&mbuf[0]) << shift) | (rbe16(&mbuf[1]) >> (16 - shift));
346 static ULONG getmfmlong (const UWORD *mbuf, ULONG shift) {
347 return ((getmfmword (mbuf, shift) << 16) | getmfmword (mbuf + 1, shift)) & MFMMASK;