blob: d84fd5316da78fbbd1e80813ee50f3c1373c00c1 [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* Copyright 1994,1996-2003,2005,2007,2009 Alain Knaff.
2 * This file is part of mtools.
3 *
4 * Mtools 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 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Mtools 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.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Io to an xdf disk
18 *
19 * written by:
20 *
21 * Alain L. Knaff
22 * alain@knaff.lu
23 *
24 */
25
26
27#include "sysincludes.h"
28#ifdef OS_linux
29#include "msdos.h"
30#include "mtools.h"
31#include "devices.h"
32#include "xdf_io.h"
33
34/* Algorithms can't be patented */
35
36typedef struct sector_map {
37 unsigned int head:1;
38 unsigned int size:7;
39} sector_map_t;
40
41
42static struct {
43 unsigned char track_size;
44 unsigned int track0_size:7;
45 unsigned int rootskip:1;
46 unsigned char rate;
47 sector_map_t map[9];
48} xdf_table[]= {
49 {
50 19, 16, 0, 0,
51 { {0,3}, {0,6}, {1,2}, {0,2}, {1,6}, {1,3}, {0,0} }
52 },
53 {
54 23, 19, 0, 0,
55 { {0,3}, {0,4}, {1,6}, {0,2}, {1,2}, {0,6}, {1,4}, {1,3}, {0,0} }
56 },
57 {
58 46, 37, 1, 0x43,
59 { {0,3}, {0,4}, {0,5}, {0,7}, {1,3}, {1,4}, {1,5}, {1,7}, {0,0} }
60 },
61 {
62 24, 20, 1, 0,
63 { {0,5}, {1,6}, {0,6}, {1, 5} }
64 },
65 {
66 48, 41, 1, 0,
67 { {0,6}, {1,7}, {0,7}, {1, 6} }
68 }
69};
70
71#define NUMBER(x) (sizeof(x)/sizeof(x[0]))
72
73typedef struct {
74 unsigned char begin; /* where it begins */
Yi Kong39bbd962022-01-09 19:41:38 +080075 unsigned char end;
Alistair Delvabeaee832021-02-24 11:27:23 -080076 unsigned char sector;
77 unsigned char sizecode;
78
79 unsigned int dirty:1;
80 unsigned int phantom:2;
81 unsigned int valid:1;
82 unsigned int head:1;
83} TrackMap_t;
84
85
86
87typedef struct Xdf_t {
Yi Kong39bbd962022-01-09 19:41:38 +080088 struct Stream_t head;
Alistair Delvabeaee832021-02-24 11:27:23 -080089
90 int fd;
91 char *buffer;
Yi Kong39bbd962022-01-09 19:41:38 +080092
93 bool track_valid;
94 uint8_t current_track;
95
Alistair Delvabeaee832021-02-24 11:27:23 -080096 sector_map_t *map;
97
Yi Kong39bbd962022-01-09 19:41:38 +080098 uint32_t track_size;
Alistair Delvabeaee832021-02-24 11:27:23 -080099 int track0_size;
Yi Kong39bbd962022-01-09 19:41:38 +0800100 uint16_t sector_size;
101 uint8_t FatSize;
102 uint16_t RootDirSize;
Alistair Delvabeaee832021-02-24 11:27:23 -0800103 TrackMap_t *track_map;
104
105 unsigned char last_sector;
106 unsigned char rate;
107
108 unsigned int stretch:1;
109 unsigned int rootskip:1;
110 signed int drive:4;
111} Xdf_t;
112
113typedef struct {
114 unsigned char head;
115 unsigned char sector;
116 unsigned char ptr;
117} Compactify_t;
118
119
120static int analyze_reply(RawRequest_t *raw_cmd, int do_print)
121{
122 int ret, bytes, newbytes;
123
124 bytes = 0;
125 while(1) {
126 ret = analyze_one_reply(raw_cmd, &newbytes, do_print);
127 bytes += newbytes;
128 switch(ret) {
129 case 0:
130 return bytes;
131 case 1:
132 raw_cmd++;
133 break;
134 case -1:
135 if(bytes)
136 return bytes;
137 else
138 return 0;
139 }
140 }
141}
Yi Kong39bbd962022-01-09 19:41:38 +0800142
Alistair Delvabeaee832021-02-24 11:27:23 -0800143
144
145static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr,
146 const char *message, int retries)
147{
148 int j;
149 int ret=-1;
Yi Kong39bbd962022-01-09 19:41:38 +0800150
Alistair Delvabeaee832021-02-24 11:27:23 -0800151 if(!nr)
152 return 0;
153 for (j=0; j< retries; j++){
154 switch(send_one_cmd(fd, raw_cmd, message)) {
155 case -1:
156 return -1;
157 case 1:
158 j++;
159 continue;
160 case 0:
161 break;
162 }
163 if((ret=analyze_reply(raw_cmd, j)) > 0)
164 return ret; /* ok */
165 }
166 if(j > 1 && j == retries) {
167 fprintf(stderr,"Too many errors, giving up\n");
168 return 0;
169 }
170 return -1;
171}
172
173
174
175#define REC (This->track_map[ptr])
176#define END(x) (This->track_map[(x)].end)
177#define BEGIN(x) (This->track_map[(x)].begin)
178
Yi Kong39bbd962022-01-09 19:41:38 +0800179static int add_to_request(Xdf_t *This, unsigned char ptr,
Alistair Delvabeaee832021-02-24 11:27:23 -0800180 RawRequest_t *request, int *nr,
181 int direction, Compactify_t *compactify)
182{
183#if 0
184 if(direction == MT_WRITE) {
Yi Kong39bbd962022-01-09 19:41:38 +0800185 printf("writing %d: %u %d %d %d [%02x]\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800186 ptr, This->current_track,
187 REC.head, REC.sector, REC.sizecode,
188 *(This->buffer + ptr * This->sector_size));
189 } else
Yi Kong39bbd962022-01-09 19:41:38 +0800190 printf(" load %d.%u\n", This->current_track, ptr);
Alistair Delvabeaee832021-02-24 11:27:23 -0800191#endif
192 if(REC.phantom) {
Yi Kong39bbd962022-01-09 19:41:38 +0800193 if(direction== MT_READ)
Alistair Delvabeaee832021-02-24 11:27:23 -0800194 memset(This->buffer + ptr * This->sector_size, 0,
Yi Kong39bbd962022-01-09 19:41:38 +0800195 128u << REC.sizecode);
Alistair Delvabeaee832021-02-24 11:27:23 -0800196 return 0;
197 }
Yi Kong39bbd962022-01-09 19:41:38 +0800198
Alistair Delvabeaee832021-02-24 11:27:23 -0800199 if(*nr &&
Yi Kong39bbd962022-01-09 19:41:38 +0800200 RR_SIZECODE(request+(*nr)-1) == REC.sizecode &&
Alistair Delvabeaee832021-02-24 11:27:23 -0800201 compactify->head == REC.head &&
202 compactify->ptr + 1 == ptr &&
203 compactify->sector +1 == REC.sector) {
204 RR_SETSIZECODE(request+(*nr)-1, REC.sizecode);
205 } else {
206 if(*nr)
207 RR_SETCONT(request+(*nr)-1);
208 RR_INIT(request+(*nr));
209 RR_SETDRIVE(request+(*nr), This->drive);
210 RR_SETRATE(request+(*nr), This->rate);
211 RR_SETTRACK(request+(*nr), This->current_track);
Yi Kong39bbd962022-01-09 19:41:38 +0800212 RR_SETPTRACK(request+(*nr),
Alistair Delvabeaee832021-02-24 11:27:23 -0800213 This->current_track << This->stretch);
214 RR_SETHEAD(request+(*nr), REC.head);
215 RR_SETSECTOR(request+(*nr), REC.sector);
216 RR_SETSIZECODE(request+(*nr), REC.sizecode);
217 RR_SETDIRECTION(request+(*nr), direction);
218 RR_SETDATA(request+(*nr),
219 (caddr_t) This->buffer + ptr * This->sector_size);
220 (*nr)++;
221 }
222 compactify->ptr = ptr;
223 compactify->head = REC.head;
224 compactify->sector = REC.sector;
225 return 0;
226}
227
228
Yi Kong39bbd962022-01-09 19:41:38 +0800229static void add_to_request_if_invalid(Xdf_t *This, unsigned char ptr,
Alistair Delvabeaee832021-02-24 11:27:23 -0800230 RawRequest_t *request, int *nr,
231 Compactify_t *compactify)
232{
233 if(!REC.valid)
234 add_to_request(This, ptr, request, nr, MT_READ, compactify);
235
236}
237
238
Yi Kong39bbd962022-01-09 19:41:38 +0800239static void adjust_bounds(Xdf_t *This, uint32_t ibegin, uint32_t iend,
240 uint8_t *begin, uint8_t *end)
Alistair Delvabeaee832021-02-24 11:27:23 -0800241{
242 /* translates begin and end from byte to sectors */
Yi Kong39bbd962022-01-09 19:41:38 +0800243 *begin = (uint8_t) (ibegin / This->sector_size);
244 *end = (uint8_t) ((iend + This->sector_size - 1) / This->sector_size);
Alistair Delvabeaee832021-02-24 11:27:23 -0800245}
246
247
248static __inline__ int try_flush_dirty(Xdf_t *This)
249{
Yi Kong39bbd962022-01-09 19:41:38 +0800250 unsigned char ptr;
251 int nr, bytes;
Alistair Delvabeaee832021-02-24 11:27:23 -0800252 RawRequest_t requests[100];
253 Compactify_t compactify;
254
Yi Kong39bbd962022-01-09 19:41:38 +0800255 if(!This->track_valid)
Alistair Delvabeaee832021-02-24 11:27:23 -0800256 return 0;
Yi Kong39bbd962022-01-09 19:41:38 +0800257
Alistair Delvabeaee832021-02-24 11:27:23 -0800258 nr = 0;
259 for(ptr=0; ptr < This->last_sector; ptr=REC.end)
260 if(REC.dirty)
261 add_to_request(This, ptr,
262 requests, &nr,
263 MT_WRITE, &compactify);
264#if 1
265 bytes = send_cmd(This->fd,requests, nr, "writing", 4);
266 if(bytes < 0)
267 return bytes;
268#else
269 bytes = 0xffffff;
270#endif
271 for(ptr=0; ptr < This->last_sector; ptr=REC.end)
272 if(REC.dirty) {
273 if(bytes >= REC.end - REC.begin) {
274 bytes -= REC.end - REC.begin;
275 REC.dirty = 0;
276 } else
277 return 1;
278 }
279 return 0;
280}
281
282
283
284static int flush_dirty(Xdf_t *This)
Yi Kong39bbd962022-01-09 19:41:38 +0800285{
Alistair Delvabeaee832021-02-24 11:27:23 -0800286 int ret;
287
288 while((ret = try_flush_dirty(This))) {
Yi Kong39bbd962022-01-09 19:41:38 +0800289 if(ret < 0)
Alistair Delvabeaee832021-02-24 11:27:23 -0800290 return ret;
291 }
292 return 0;
293}
294
295
Yi Kong39bbd962022-01-09 19:41:38 +0800296static ssize_t load_data(Xdf_t *This, uint32_t ibegin, uint32_t iend,
297 int retries)
Alistair Delvabeaee832021-02-24 11:27:23 -0800298{
Yi Kong39bbd962022-01-09 19:41:38 +0800299 unsigned char ptr;
300 int nr, bytes;
Alistair Delvabeaee832021-02-24 11:27:23 -0800301 RawRequest_t requests[100];
302 Compactify_t compactify;
Yi Kong39bbd962022-01-09 19:41:38 +0800303 unsigned char begin, end;
304 adjust_bounds(This, ibegin, iend, &begin, &end);
Alistair Delvabeaee832021-02-24 11:27:23 -0800305
Alistair Delvabeaee832021-02-24 11:27:23 -0800306 ptr = begin;
307 nr = 0;
308 for(ptr=REC.begin; ptr < end ; ptr = REC.end)
309 add_to_request_if_invalid(This, ptr, requests, &nr,
310 &compactify);
311 bytes = send_cmd(This->fd,requests, nr, "reading", retries);
312 if(bytes < 0)
313 return bytes;
314 ptr = begin;
315 for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
316 if(!REC.valid) {
317 if(bytes >= REC.end - REC.begin) {
318 bytes -= REC.end - REC.begin;
319 REC.valid = 1;
320 } else if(ptr > begin)
321 return ptr * This->sector_size;
322 else
323 return -1;
324 }
325 }
326 return end * This->sector_size;
327}
328
Yi Kong39bbd962022-01-09 19:41:38 +0800329static void mark_dirty(Xdf_t *This, uint32_t ibegin, uint32_t iend)
Alistair Delvabeaee832021-02-24 11:27:23 -0800330{
331 int ptr;
Yi Kong39bbd962022-01-09 19:41:38 +0800332 unsigned char begin, end;
Alistair Delvabeaee832021-02-24 11:27:23 -0800333
Yi Kong39bbd962022-01-09 19:41:38 +0800334 adjust_bounds(This, ibegin, iend, &begin, &end);
335
Alistair Delvabeaee832021-02-24 11:27:23 -0800336 ptr = begin;
337 for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
338 REC.valid = 1;
339 if(!REC.phantom)
340 REC.dirty = 1;
341 }
342}
343
344
Yi Kong39bbd962022-01-09 19:41:38 +0800345static ssize_t load_bounds(Xdf_t *This, uint32_t begin, uint32_t end)
Alistair Delvabeaee832021-02-24 11:27:23 -0800346{
Yi Kong39bbd962022-01-09 19:41:38 +0800347 unsigned char lbegin, lend;
Alistair Delvabeaee832021-02-24 11:27:23 -0800348
Yi Kong39bbd962022-01-09 19:41:38 +0800349 adjust_bounds(This, begin, end, &lbegin, &lend);
Alistair Delvabeaee832021-02-24 11:27:23 -0800350
351 if(begin != BEGIN(lbegin) * This->sector_size &&
352 end != BEGIN(lend) * This->sector_size &&
353 lend < END(END(lbegin)))
354 /* contiguous end & begin, load them in one go */
355 return load_data(This, begin, end, 4);
356
357 if(begin != BEGIN(lbegin) * This->sector_size) {
Yi Kong39bbd962022-01-09 19:41:38 +0800358 ssize_t ret = load_data(This, begin, begin, 4);
359 if(ret < 0)
360 return ret;
Alistair Delvabeaee832021-02-24 11:27:23 -0800361 }
362
363 if(end != BEGIN(lend) * This->sector_size) {
Yi Kong39bbd962022-01-09 19:41:38 +0800364 ssize_t ret = load_data(This, end, end, 4);
365 if(ret < 0)
Alistair Delvabeaee832021-02-24 11:27:23 -0800366 return BEGIN(lend) * This->sector_size;
367 }
368 return lend * This->sector_size;
369}
370
Yi Kong39bbd962022-01-09 19:41:38 +0800371/* Fill out a map that is just sufficient to read boot sector */
372static void fill_boot(Xdf_t *This)
Alistair Delvabeaee832021-02-24 11:27:23 -0800373{
Yi Kong39bbd962022-01-09 19:41:38 +0800374 uint8_t ptr=0;
375
376 REC.head = 0;
377 REC.sector = 129;
378 REC.phantom = 0;
379
380 REC.begin = ptr;
381 REC.end = ptr+1;
382
383 REC.sizecode = 2;
384
385 REC.valid = 0;
386 REC.dirty = 0;
387 This->last_sector=1;
388 This->current_track=0;
389}
390
391
392static uint8_t fill_t0(Xdf_t *This, uint8_t ptr, unsigned int size,
393 uint8_t *sector, uint8_t *head)
394{
395 unsigned int n;
Alistair Delvabeaee832021-02-24 11:27:23 -0800396
397 for(n = 0; n < size; ptr++,n++) {
398 REC.head = *head;
399 REC.sector = *sector + 129;
400 REC.phantom = 0;
401 (*sector)++;
402 if(!*head && *sector >= This->track0_size - 8) {
403 *sector = 0;
404 *head = 1;
405 }
406 }
407 return ptr;
408}
409
410
Yi Kong39bbd962022-01-09 19:41:38 +0800411static uint8_t fill_phantoms(Xdf_t *This, uint8_t ptr, uint8_t size)
Alistair Delvabeaee832021-02-24 11:27:23 -0800412{
Yi Kong39bbd962022-01-09 19:41:38 +0800413 unsigned int n;
Alistair Delvabeaee832021-02-24 11:27:23 -0800414
415 for(n = 0; n < size; ptr++,n++)
416 REC.phantom = 1;
417 return ptr;
418}
419
Yi Kong39bbd962022-01-09 19:41:38 +0800420static int decompose(Xdf_t *This, mt_off_t iwhere, size_t len,
421 uint32_t *begin, uint32_t *end, uint8_t boot)
Alistair Delvabeaee832021-02-24 11:27:23 -0800422{
Yi Kong39bbd962022-01-09 19:41:38 +0800423 uint8_t ptr;
Alistair Delvabeaee832021-02-24 11:27:23 -0800424 sector_map_t *map;
Yi Kong39bbd962022-01-09 19:41:38 +0800425 uint8_t lbegin, lend;
426 uint32_t track_size = This->track_size * 1024;
427
428 smt_off_t track = (smt_off_t) iwhere / track_size;
429 uint32_t where = (smt_off_t) iwhere % track_size;
430
431 *begin = where;
432 if(where + len > track_size)
433 *end = track_size;
434 else
435 *end = (uint32_t) (where + len);
Alistair Delvabeaee832021-02-24 11:27:23 -0800436
437 if(This->current_track == track && !boot)
438 /* already OK, return immediately */
Yi Kong39bbd962022-01-09 19:41:38 +0800439 return 0;
Alistair Delvabeaee832021-02-24 11:27:23 -0800440 if(!boot)
441 flush_dirty(This);
Yi Kong39bbd962022-01-09 19:41:38 +0800442 if(track >= 80)
443 return -1;
444 This->current_track = (uint8_t) track;
445 This->track_valid = true;
Alistair Delvabeaee832021-02-24 11:27:23 -0800446
447 if(track) {
448 for(ptr=0, map=This->map; map->size; map++) {
449 /* iterate through all sectors */
450 lbegin = ptr;
Yi Kong39bbd962022-01-09 19:41:38 +0800451 lend = ptr +
452 (uint8_t) ((128u<<map->size)/This->sector_size);
Alistair Delvabeaee832021-02-24 11:27:23 -0800453 for( ; ptr < lend ; ptr++) {
454 REC.begin = lbegin;
455 REC.end = lend;
Yi Kong39bbd962022-01-09 19:41:38 +0800456
Alistair Delvabeaee832021-02-24 11:27:23 -0800457 REC.head = map->head;
458 REC.sector = map->size + 128;
459 REC.sizecode = map->size;
Yi Kong39bbd962022-01-09 19:41:38 +0800460
Alistair Delvabeaee832021-02-24 11:27:23 -0800461 REC.valid = 0;
462 REC.dirty = 0;
463 REC.phantom = 0;
464 }
465 }
466 REC.begin = REC.end = ptr;
467 } else {
Yi Kong39bbd962022-01-09 19:41:38 +0800468 uint8_t sector, head;
Alistair Delvabeaee832021-02-24 11:27:23 -0800469
470 head = 0;
471 sector = 0;
472
473 for(ptr=boot; ptr < 2 * This->track_size; ptr++) {
474 REC.begin = ptr;
475 REC.end = ptr+1;
Yi Kong39bbd962022-01-09 19:41:38 +0800476
Alistair Delvabeaee832021-02-24 11:27:23 -0800477 REC.sizecode = 2;
Yi Kong39bbd962022-01-09 19:41:38 +0800478
Alistair Delvabeaee832021-02-24 11:27:23 -0800479 REC.valid = 0;
480 REC.dirty = 0;
481 }
482
483 /* boot & 1st fat */
484 ptr=fill_t0(This, 0, 1 + This->FatSize, &sector, &head);
485
486 /* second fat */
487 ptr=fill_phantoms(This, ptr, This->FatSize);
488
489 /* root dir */
490 ptr=fill_t0(This, ptr, This->RootDirSize, &sector, &head);
Yi Kong39bbd962022-01-09 19:41:38 +0800491
Alistair Delvabeaee832021-02-24 11:27:23 -0800492 /* "bad sectors" at the beginning of the fs */
493 ptr=fill_phantoms(This, ptr, 5);
494
495 if(This->rootskip)
496 sector++;
497
498 /* beginning of the file system */
499 ptr = fill_t0(This, ptr,
500 (This->track_size - This->FatSize) * 2 -
501 This->RootDirSize - 6,
502 &sector, &head);
503 }
504 This->last_sector = ptr;
Yi Kong39bbd962022-01-09 19:41:38 +0800505 return 0;
Alistair Delvabeaee832021-02-24 11:27:23 -0800506}
507
508
Yi Kong39bbd962022-01-09 19:41:38 +0800509static ssize_t xdf_pread(Stream_t *Stream, char *buf,
510 mt_off_t where, size_t len)
511{
512 uint32_t begin, end;
513 ssize_t ret;
Alistair Delvabeaee832021-02-24 11:27:23 -0800514 DeclareThis(Xdf_t);
515
Yi Kong39bbd962022-01-09 19:41:38 +0800516 if(decompose(This, truncBytes32(where), len, &begin, &end, 0) < 0)
517 /* Read beyond end of device */
518 return 0;
519 ret = load_data(This, begin, end, 4);
520 if(ret < 0 || (size_t) ret < begin)
521 return -1;
522 maximize(len, (size_t) ret - begin);
Alistair Delvabeaee832021-02-24 11:27:23 -0800523 memcpy(buf, This->buffer + begin, len);
Yi Kong39bbd962022-01-09 19:41:38 +0800524 return (ssize_t) (end - begin);
Alistair Delvabeaee832021-02-24 11:27:23 -0800525}
526
Yi Kong39bbd962022-01-09 19:41:38 +0800527static ssize_t xdf_pwrite(Stream_t *Stream, char *buf,
528 mt_off_t where, size_t len)
529{
530 uint32_t begin, end;
531 ssize_t len2;
Alistair Delvabeaee832021-02-24 11:27:23 -0800532 DeclareThis(Xdf_t);
533
Yi Kong39bbd962022-01-09 19:41:38 +0800534 if(decompose(This, truncBytes32(where), len, &begin, &end, 0) < 0) {
535 /* Write beyond end of device */
536 errno = EFBIG;
537 return -1;
538 }
539
Alistair Delvabeaee832021-02-24 11:27:23 -0800540 len2 = load_bounds(This, begin, end);
Yi Kong39bbd962022-01-09 19:41:38 +0800541 if(len2 < 0)
542 return -1;
543 maximize(end, (uint32_t)len2);
Alistair Delvabeaee832021-02-24 11:27:23 -0800544 len2 -= begin;
Yi Kong39bbd962022-01-09 19:41:38 +0800545 maximize(len, (size_t) len2);
Alistair Delvabeaee832021-02-24 11:27:23 -0800546 memcpy(This->buffer + begin, buf, len);
547 mark_dirty(This, begin, end);
Yi Kong39bbd962022-01-09 19:41:38 +0800548 return (ssize_t) (end - begin);
Alistair Delvabeaee832021-02-24 11:27:23 -0800549}
550
551static int xdf_flush(Stream_t *Stream)
552{
553 DeclareThis(Xdf_t);
554
Yi Kong39bbd962022-01-09 19:41:38 +0800555 return flush_dirty(This);
Alistair Delvabeaee832021-02-24 11:27:23 -0800556}
557
558static int xdf_free(Stream_t *Stream)
559{
560 DeclareThis(Xdf_t);
561 Free(This->track_map);
562 Free(This->buffer);
563 return close(This->fd);
564}
565
566
Yi Kong39bbd962022-01-09 19:41:38 +0800567static int check_geom(Xdf_t *This, struct device *dev)
Alistair Delvabeaee832021-02-24 11:27:23 -0800568{
Yi Kong39bbd962022-01-09 19:41:38 +0800569 unsigned int sect;
Alistair Delvabeaee832021-02-24 11:27:23 -0800570
571 if (!IS_MFORMAT_ONLY(dev)) {
572 if(compare(dev->sectors, 19) &&
573 compare(dev->sectors, 23) &&
574 compare(dev->sectors, 24) &&
575 compare(dev->sectors, 46) &&
576 compare(dev->sectors, 48))
577 return 1;
Yi Kong39bbd962022-01-09 19:41:38 +0800578
Alistair Delvabeaee832021-02-24 11:27:23 -0800579 /* check against contradictory info from configuration file */
580 if(compare(dev->heads, 2))
581 return 1;
582 }
583
584 /* check against info from boot */
Yi Kong39bbd962022-01-09 19:41:38 +0800585 if(This) {
586 sect = This->track_size;
Alistair Delvabeaee832021-02-24 11:27:23 -0800587 if((sect != 19 && sect != 23 && sect != 24 &&
588 sect != 46 && sect != 48) ||
Yi Kong39bbd962022-01-09 19:41:38 +0800589 (!IS_MFORMAT_ONLY(dev) && compare(dev->sectors, sect)))
590 return 1;
Alistair Delvabeaee832021-02-24 11:27:23 -0800591 }
592 return 0;
593}
594
Yi Kong39bbd962022-01-09 19:41:38 +0800595static void set_geom(Xdf_t *This, struct device *dev)
Alistair Delvabeaee832021-02-24 11:27:23 -0800596{
597 /* fill in config info to be returned to user */
598 dev->heads = 2;
599 dev->use_2m = 0xff;
Yi Kong39bbd962022-01-09 19:41:38 +0800600 dev->sectors = (uint16_t) This->track_size;
601 dev->tracks = 80;
Alistair Delvabeaee832021-02-24 11:27:23 -0800602}
603
Yi Kong39bbd962022-01-09 19:41:38 +0800604static int config_geom(Stream_t *Stream UNUSEDP, struct device *dev,
605 struct device *orig_dev UNUSEDP)
Alistair Delvabeaee832021-02-24 11:27:23 -0800606{
Yi Kong39bbd962022-01-09 19:41:38 +0800607 DeclareThis(Xdf_t);
608 if(check_geom(This, dev))
Alistair Delvabeaee832021-02-24 11:27:23 -0800609 return 1;
Yi Kong39bbd962022-01-09 19:41:38 +0800610 set_geom(This, dev);
Alistair Delvabeaee832021-02-24 11:27:23 -0800611 return 0;
612}
613
614static Class_t XdfClass = {
Yi Kong39bbd962022-01-09 19:41:38 +0800615 0,
616 0,
617 xdf_pread,
618 xdf_pwrite,
619 xdf_flush,
620 xdf_free,
621 config_geom,
Alistair Delvabeaee832021-02-24 11:27:23 -0800622 0, /* get_data */
623 0, /* pre-allocate */
624 0, /* get_dosConvert */
625 0 /* discard */
626};
627
Yi Kong39bbd962022-01-09 19:41:38 +0800628Stream_t *XdfOpen(struct device *dev, const char *name,
Alistair Delvabeaee832021-02-24 11:27:23 -0800629 int mode, char *errmsg, struct xdf_info *info)
630{
631 Xdf_t *This;
Yi Kong39bbd962022-01-09 19:41:38 +0800632 uint32_t begin, end;
Alistair Delvabeaee832021-02-24 11:27:23 -0800633 union bootsector *boot;
634 unsigned int type;
Yi Kong39bbd962022-01-09 19:41:38 +0800635 uint16_t fatSize;
Alistair Delvabeaee832021-02-24 11:27:23 -0800636
Yi Kong39bbd962022-01-09 19:41:38 +0800637 if(dev && ((!SHOULD_USE_XDF(dev) && !getenv("MTOOLS_USE_XDF")) ||
638 check_geom(NULL, dev)))
Alistair Delvabeaee832021-02-24 11:27:23 -0800639 return NULL;
640
641 This = New(Xdf_t);
642 if (!This)
643 return NULL;
Yi Kong39bbd962022-01-09 19:41:38 +0800644 init_head(&This->head, &XdfClass, NULL);
Alistair Delvabeaee832021-02-24 11:27:23 -0800645
Alistair Delvabeaee832021-02-24 11:27:23 -0800646 This->sector_size = 512;
647 This->stretch = 0;
648
649 precmd(dev);
Yi Kong39bbd962022-01-09 19:41:38 +0800650 This->fd = open(name,
651 ((mode | dev->mode) & ~O_ACCMODE) |
652 O_EXCL | O_NDELAY | O_RDWR);
Alistair Delvabeaee832021-02-24 11:27:23 -0800653 if(This->fd < 0) {
654#ifdef HAVE_SNPRINTF
655 snprintf(errmsg,199,"xdf floppy: open: \"%s\"", strerror(errno));
656#else
657 sprintf(errmsg,"xdf floppy: open: \"%s\"", strerror(errno));
658#endif
659 goto exit_0;
660 }
661 closeExec(This->fd);
662
663 This->drive = GET_DRIVE(This->fd);
664 if(This->drive < 0)
665 goto exit_1;
666
667 /* allocate buffer */
668 This->buffer = (char *) malloc(96 * 512);
669 if (!This->buffer)
670 goto exit_1;
671
Yi Kong39bbd962022-01-09 19:41:38 +0800672 This->track_valid = false;
Alistair Delvabeaee832021-02-24 11:27:23 -0800673 This->track_map = (TrackMap_t *)
674 calloc(96, sizeof(TrackMap_t));
675 if(!This->track_map)
676 goto exit_2;
677
678 /* lock the device on writes */
679 if (lock_dev(This->fd, mode == O_RDWR, dev)) {
680#ifdef HAVE_SNPRINTF
Yi Kong39bbd962022-01-09 19:41:38 +0800681 snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:",
Alistair Delvabeaee832021-02-24 11:27:23 -0800682 dev->name);
683#else
Yi Kong39bbd962022-01-09 19:41:38 +0800684 sprintf(errmsg,"xdf floppy: device \"%s\" busy:",
Alistair Delvabeaee832021-02-24 11:27:23 -0800685 dev->name);
686#endif
687 goto exit_3;
688 }
689
690 /* Before reading the boot sector, assume dummy values suitable
Yi Kong39bbd962022-01-09 19:41:38 +0800691 * for reading just the boot sector */
692 fill_boot(This);
Alistair Delvabeaee832021-02-24 11:27:23 -0800693 This->rate = 0;
Yi Kong39bbd962022-01-09 19:41:38 +0800694 if (load_data(This, 0, 1, 4) < 0 ) {
Alistair Delvabeaee832021-02-24 11:27:23 -0800695 This->rate = 0x43;
Yi Kong39bbd962022-01-09 19:41:38 +0800696 if(load_data(This, 0, 1, 4) < 0)
Alistair Delvabeaee832021-02-24 11:27:23 -0800697 goto exit_3;
698 }
699
700 boot = (union bootsector *) This->buffer;
Yi Kong39bbd962022-01-09 19:41:38 +0800701
702 fatSize = WORD(fatlen);
703 if(fatSize > UINT8_MAX) {
704 fprintf(stderr, "Fat size %d too large\n", fatSize);
705 exit(1);
706 }
707 This->FatSize = (uint8_t) fatSize;
Alistair Delvabeaee832021-02-24 11:27:23 -0800708 This->RootDirSize = WORD(dirents)/16;
709 This->track_size = WORD(nsect);
710 for(type=0; type < NUMBER(xdf_table); type++) {
711 if(xdf_table[type].track_size == This->track_size) {
712 This->map = xdf_table[type].map;
713 This->track0_size = xdf_table[type].track0_size;
714 This->rootskip = xdf_table[type].rootskip;
715 This->rate = xdf_table[type].rate;
716 break;
717 }
718 }
719 if(type == NUMBER(xdf_table))
720 goto exit_3;
721
722 if(info) {
723 info->RootDirSize = This->RootDirSize;
724 info->FatSize = This->FatSize;
725 info->BadSectors = 5;
726 }
727 decompose(This, 0, 512, &begin, &end, 1);
728
Alistair Delvabeaee832021-02-24 11:27:23 -0800729 if(dev)
Yi Kong39bbd962022-01-09 19:41:38 +0800730 set_geom(This, dev);
731 return &This->head;
Alistair Delvabeaee832021-02-24 11:27:23 -0800732
733exit_3:
734 Free(This->track_map);
735exit_2:
736 Free(This->buffer);
737exit_1:
738 close(This->fd);
739exit_0:
740 Free(This);
741 return NULL;
742}
743
744#endif
745
746/* Algorithms can't be patented */