[9] | 1 | /*
|
---|
| 2 | * Io to an xdf disk
|
---|
| 3 | *
|
---|
| 4 | * written by:
|
---|
| 5 | *
|
---|
| 6 | * Alain L. Knaff
|
---|
| 7 | * alain@linux.lu
|
---|
| 8 | *
|
---|
| 9 | */
|
---|
| 10 |
|
---|
| 11 |
|
---|
| 12 | #include "sysincludes.h"
|
---|
| 13 | #ifdef OS_linux
|
---|
| 14 | #include "msdos.h"
|
---|
| 15 | #include "mtools.h"
|
---|
| 16 | #include "devices.h"
|
---|
| 17 | #include "xdf_io.h"
|
---|
| 18 |
|
---|
| 19 | extern int errno;
|
---|
| 20 |
|
---|
| 21 | /* Algorithms can't be patented */
|
---|
| 22 |
|
---|
| 23 | typedef struct sector_map {
|
---|
| 24 | unsigned int head:1;
|
---|
| 25 | unsigned int size:7;
|
---|
| 26 | } sector_map_t;
|
---|
| 27 |
|
---|
| 28 |
|
---|
| 29 | struct {
|
---|
| 30 | unsigned char track_size;
|
---|
| 31 | unsigned int track0_size:7;
|
---|
| 32 | unsigned int rootskip:1;
|
---|
| 33 | unsigned char rate;
|
---|
| 34 | sector_map_t map[9];
|
---|
| 35 | } xdf_table[]= {
|
---|
| 36 | {
|
---|
| 37 | 19, 16, 0, 0,
|
---|
| 38 | { {0,3}, {0,6}, {1,2}, {0,2}, {1,6}, {1,3}, {0,0} }
|
---|
| 39 | },
|
---|
| 40 | {
|
---|
| 41 | 23, 19, 0, 0,
|
---|
| 42 | { {0,3}, {0,4}, {1,6}, {0,2}, {1,2}, {0,6}, {1,4}, {1,3}, {0,0} }
|
---|
| 43 | },
|
---|
| 44 | {
|
---|
| 45 | 46, 37, 0x43, 1,
|
---|
| 46 | { {0,3}, {0,4}, {0,5}, {0,7}, {1,3}, {1,4}, {1,5}, {1,7}, {0,0} }
|
---|
| 47 | },
|
---|
| 48 | {
|
---|
| 49 | 24, 20, 0, 1,
|
---|
| 50 | { {0,5}, {1,6}, {0,6}, {1, 5} }
|
---|
| 51 | },
|
---|
| 52 | {
|
---|
| 53 | 48, 41, 0, 1,
|
---|
| 54 | { {0,6}, {1,7}, {0,7}, {1, 6} }
|
---|
| 55 | }
|
---|
| 56 | };
|
---|
| 57 |
|
---|
| 58 | #define NUMBER(x) (sizeof(x)/sizeof(x[0]))
|
---|
| 59 |
|
---|
| 60 | typedef struct {
|
---|
| 61 | unsigned char begin; /* where it begins */
|
---|
| 62 | unsigned char end;
|
---|
| 63 | unsigned char sector;
|
---|
| 64 | unsigned char sizecode;
|
---|
| 65 |
|
---|
| 66 | unsigned int dirty:1;
|
---|
| 67 | unsigned int phantom:2;
|
---|
| 68 | unsigned int valid:1;
|
---|
| 69 | unsigned int head:1;
|
---|
| 70 | } TrackMap_t;
|
---|
| 71 |
|
---|
| 72 |
|
---|
| 73 |
|
---|
| 74 | typedef struct Xdf_t {
|
---|
| 75 | Class_t *Class;
|
---|
| 76 | int refs;
|
---|
| 77 | Stream_t *Next;
|
---|
| 78 | Stream_t *Buffer;
|
---|
| 79 |
|
---|
| 80 | int fd;
|
---|
| 81 | char *buffer;
|
---|
| 82 |
|
---|
| 83 | int current_track;
|
---|
| 84 |
|
---|
| 85 | sector_map_t *map;
|
---|
| 86 |
|
---|
| 87 | int track_size;
|
---|
| 88 | int track0_size;
|
---|
| 89 | int sector_size;
|
---|
| 90 | int FatSize;
|
---|
| 91 | int RootDirSize;
|
---|
| 92 | TrackMap_t *track_map;
|
---|
| 93 |
|
---|
| 94 | unsigned char last_sector;
|
---|
| 95 | unsigned char rate;
|
---|
| 96 |
|
---|
| 97 | unsigned int stretch:1;
|
---|
| 98 | unsigned int rootskip:1;
|
---|
| 99 | signed int drive:4;
|
---|
| 100 | } Xdf_t;
|
---|
| 101 |
|
---|
| 102 | typedef struct {
|
---|
| 103 | unsigned char head;
|
---|
| 104 | unsigned char sector;
|
---|
| 105 | unsigned char ptr;
|
---|
| 106 | } Compactify_t;
|
---|
| 107 |
|
---|
| 108 |
|
---|
| 109 | static int analyze_reply(RawRequest_t *raw_cmd, int do_print)
|
---|
| 110 | {
|
---|
| 111 | int ret, bytes, newbytes;
|
---|
| 112 |
|
---|
| 113 | bytes = 0;
|
---|
| 114 | while(1) {
|
---|
| 115 | ret = analyze_one_reply(raw_cmd, &newbytes, do_print);
|
---|
| 116 | bytes += newbytes;
|
---|
| 117 | switch(ret) {
|
---|
| 118 | case 0:
|
---|
| 119 | return bytes;
|
---|
| 120 | case 1:
|
---|
| 121 | raw_cmd++;
|
---|
| 122 | break;
|
---|
| 123 | case -1:
|
---|
| 124 | if(bytes)
|
---|
| 125 | return bytes;
|
---|
| 126 | else
|
---|
| 127 | return 0;
|
---|
| 128 | }
|
---|
| 129 | }
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 |
|
---|
| 133 |
|
---|
| 134 | static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr,
|
---|
| 135 | const char *message, int retries)
|
---|
| 136 | {
|
---|
| 137 | int j;
|
---|
| 138 | int ret=-1;
|
---|
| 139 |
|
---|
| 140 | if(!nr)
|
---|
| 141 | return 0;
|
---|
| 142 | for (j=0; j< retries; j++){
|
---|
| 143 | switch(send_one_cmd(fd, raw_cmd, message)) {
|
---|
| 144 | case -1:
|
---|
| 145 | return -1;
|
---|
| 146 | case 1:
|
---|
| 147 | j++;
|
---|
| 148 | continue;
|
---|
| 149 | case 0:
|
---|
| 150 | break;
|
---|
| 151 | }
|
---|
| 152 | if((ret=analyze_reply(raw_cmd, j)) > 0)
|
---|
| 153 | return ret; /* ok */
|
---|
| 154 | }
|
---|
| 155 | if(j > 1 && j == retries) {
|
---|
| 156 | fprintf(stderr,"Too many errors, giving up\n");
|
---|
| 157 | return 0;
|
---|
| 158 | }
|
---|
| 159 | return -1;
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 |
|
---|
| 163 |
|
---|
| 164 | #define REC (This->track_map[ptr])
|
---|
| 165 | #define END(x) (This->track_map[(x)].end)
|
---|
| 166 | #define BEGIN(x) (This->track_map[(x)].begin)
|
---|
| 167 |
|
---|
| 168 | static int add_to_request(Xdf_t *This, int ptr,
|
---|
| 169 | RawRequest_t *request, int *nr,
|
---|
| 170 | int direction, Compactify_t *compactify)
|
---|
| 171 | {
|
---|
| 172 | #if 0
|
---|
| 173 | if(direction == MT_WRITE) {
|
---|
| 174 | printf("writing %d: %d %d %d %d [%02x]\n",
|
---|
| 175 | ptr, This->current_track,
|
---|
| 176 | REC.head, REC.sector, REC.sizecode,
|
---|
| 177 | *(This->buffer + ptr * This->sector_size));
|
---|
| 178 | } else
|
---|
| 179 | printf(" load %d.%d\n", This->current_track, ptr);
|
---|
| 180 | #endif
|
---|
| 181 | if(REC.phantom) {
|
---|
| 182 | if(direction== MT_READ)
|
---|
| 183 | memset(This->buffer + ptr * This->sector_size, 0,
|
---|
| 184 | 128 << REC.sizecode);
|
---|
| 185 | return 0;
|
---|
| 186 | }
|
---|
| 187 |
|
---|
| 188 | if(*nr &&
|
---|
| 189 | RR_SIZECODE(request+(*nr)-1) == REC.sizecode &&
|
---|
| 190 | compactify->head == REC.head &&
|
---|
| 191 | compactify->ptr + 1 == ptr &&
|
---|
| 192 | compactify->sector +1 == REC.sector) {
|
---|
| 193 | RR_SETSIZECODE(request+(*nr)-1, REC.sizecode);
|
---|
| 194 | } else {
|
---|
| 195 | if(*nr)
|
---|
| 196 | RR_SETCONT(request+(*nr)-1);
|
---|
| 197 | RR_INIT(request+(*nr));
|
---|
| 198 | RR_SETDRIVE(request+(*nr), This->drive);
|
---|
| 199 | RR_SETRATE(request+(*nr), This->rate);
|
---|
| 200 | RR_SETTRACK(request+(*nr), This->current_track);
|
---|
| 201 | RR_SETPTRACK(request+(*nr),
|
---|
| 202 | This->current_track << This->stretch);
|
---|
| 203 | RR_SETHEAD(request+(*nr), REC.head);
|
---|
| 204 | RR_SETSECTOR(request+(*nr), REC.sector);
|
---|
| 205 | RR_SETSIZECODE(request+(*nr), REC.sizecode);
|
---|
| 206 | RR_SETDIRECTION(request+(*nr), direction);
|
---|
| 207 | RR_SETDATA(request+(*nr),
|
---|
| 208 | (caddr_t) This->buffer + ptr * This->sector_size);
|
---|
| 209 | (*nr)++;
|
---|
| 210 | }
|
---|
| 211 | compactify->ptr = ptr;
|
---|
| 212 | compactify->head = REC.head;
|
---|
| 213 | compactify->sector = REC.sector;
|
---|
| 214 | return 0;
|
---|
| 215 | }
|
---|
| 216 |
|
---|
| 217 |
|
---|
| 218 | static void add_to_request_if_invalid(Xdf_t *This, int ptr,
|
---|
| 219 | RawRequest_t *request, int *nr,
|
---|
| 220 | Compactify_t *compactify)
|
---|
| 221 | {
|
---|
| 222 | if(!REC.valid)
|
---|
| 223 | add_to_request(This, ptr, request, nr, MT_READ, compactify);
|
---|
| 224 |
|
---|
| 225 | }
|
---|
| 226 |
|
---|
| 227 |
|
---|
| 228 | static void adjust_bounds(Xdf_t *This, off_t *begin, off_t *end)
|
---|
| 229 | {
|
---|
| 230 | /* translates begin and end from byte to sectors */
|
---|
| 231 | *begin = *begin / This->sector_size;
|
---|
| 232 | *end = (*end + This->sector_size - 1) / This->sector_size;
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 |
|
---|
| 236 | static inline int try_flush_dirty(Xdf_t *This)
|
---|
| 237 | {
|
---|
| 238 | int ptr, nr, bytes;
|
---|
| 239 | RawRequest_t requests[100];
|
---|
| 240 | Compactify_t compactify;
|
---|
| 241 |
|
---|
| 242 | if(This->current_track < 0)
|
---|
| 243 | return 0;
|
---|
| 244 |
|
---|
| 245 | nr = 0;
|
---|
| 246 | for(ptr=0; ptr < This->last_sector; ptr=REC.end)
|
---|
| 247 | if(REC.dirty)
|
---|
| 248 | add_to_request(This, ptr,
|
---|
| 249 | requests, &nr,
|
---|
| 250 | MT_WRITE, &compactify);
|
---|
| 251 | #if 1
|
---|
| 252 | bytes = send_cmd(This->fd,requests, nr, "writing", 4);
|
---|
| 253 | if(bytes < 0)
|
---|
| 254 | return bytes;
|
---|
| 255 | #else
|
---|
| 256 | bytes = 0xffffff;
|
---|
| 257 | #endif
|
---|
| 258 | for(ptr=0; ptr < This->last_sector; ptr=REC.end)
|
---|
| 259 | if(REC.dirty) {
|
---|
| 260 | if(bytes >= REC.end - REC.begin) {
|
---|
| 261 | bytes -= REC.end - REC.begin;
|
---|
| 262 | REC.dirty = 0;
|
---|
| 263 | } else
|
---|
| 264 | return 1;
|
---|
| 265 | }
|
---|
| 266 | return 0;
|
---|
| 267 | }
|
---|
| 268 |
|
---|
| 269 |
|
---|
| 270 |
|
---|
| 271 | static int flush_dirty(Xdf_t *This)
|
---|
| 272 | {
|
---|
| 273 | int ret;
|
---|
| 274 |
|
---|
| 275 | while((ret = try_flush_dirty(This))) {
|
---|
| 276 | if(ret < 0)
|
---|
| 277 | return ret;
|
---|
| 278 | }
|
---|
| 279 | return 0;
|
---|
| 280 | }
|
---|
| 281 |
|
---|
| 282 |
|
---|
| 283 | static int load_data(Xdf_t *This, off_t begin, off_t end, int retries)
|
---|
| 284 | {
|
---|
| 285 | int ptr, nr, bytes;
|
---|
| 286 | RawRequest_t requests[100];
|
---|
| 287 | Compactify_t compactify;
|
---|
| 288 |
|
---|
| 289 | adjust_bounds(This, &begin, &end);
|
---|
| 290 |
|
---|
| 291 | ptr = begin;
|
---|
| 292 | nr = 0;
|
---|
| 293 | for(ptr=REC.begin; ptr < end ; ptr = REC.end)
|
---|
| 294 | add_to_request_if_invalid(This, ptr, requests, &nr,
|
---|
| 295 | &compactify);
|
---|
| 296 | bytes = send_cmd(This->fd,requests, nr, "reading", retries);
|
---|
| 297 | if(bytes < 0)
|
---|
| 298 | return bytes;
|
---|
| 299 | ptr = begin;
|
---|
| 300 | for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
|
---|
| 301 | if(!REC.valid) {
|
---|
| 302 | if(bytes >= REC.end - REC.begin) {
|
---|
| 303 | bytes -= REC.end - REC.begin;
|
---|
| 304 | REC.valid = 1;
|
---|
| 305 | } else if(ptr > begin)
|
---|
| 306 | return ptr * This->sector_size;
|
---|
| 307 | else
|
---|
| 308 | return -1;
|
---|
| 309 | }
|
---|
| 310 | }
|
---|
| 311 | return end * This->sector_size;
|
---|
| 312 | }
|
---|
| 313 |
|
---|
| 314 | static void mark_dirty(Xdf_t *This, off_t begin, off_t end)
|
---|
| 315 | {
|
---|
| 316 | int ptr;
|
---|
| 317 |
|
---|
| 318 | adjust_bounds(This, &begin, &end);
|
---|
| 319 |
|
---|
| 320 | ptr = begin;
|
---|
| 321 | for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
|
---|
| 322 | REC.valid = 1;
|
---|
| 323 | if(!REC.phantom)
|
---|
| 324 | REC.dirty = 1;
|
---|
| 325 | }
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 |
|
---|
| 329 | static int load_bounds(Xdf_t *This, off_t begin, off_t end)
|
---|
| 330 | {
|
---|
| 331 | off_t lbegin, lend;
|
---|
| 332 | int endp1, endp2;
|
---|
| 333 |
|
---|
| 334 | lbegin = begin;
|
---|
| 335 | lend = end;
|
---|
| 336 |
|
---|
| 337 | adjust_bounds(This, &lbegin, &lend);
|
---|
| 338 |
|
---|
| 339 | if(begin != BEGIN(lbegin) * This->sector_size &&
|
---|
| 340 | end != BEGIN(lend) * This->sector_size &&
|
---|
| 341 | lend < END(END(lbegin)))
|
---|
| 342 | /* contiguous end & begin, load them in one go */
|
---|
| 343 | return load_data(This, begin, end, 4);
|
---|
| 344 |
|
---|
| 345 | if(begin != BEGIN(lbegin) * This->sector_size) {
|
---|
| 346 | endp1 = load_data(This, begin, begin, 4);
|
---|
| 347 | if(endp1 < 0)
|
---|
| 348 | return endp1;
|
---|
| 349 | }
|
---|
| 350 |
|
---|
| 351 | if(end != BEGIN(lend) * This->sector_size) {
|
---|
| 352 | endp2 = load_data(This, end, end, 4);
|
---|
| 353 | if(endp2 < 0)
|
---|
| 354 | return BEGIN(lend) * This->sector_size;
|
---|
| 355 | }
|
---|
| 356 | return lend * This->sector_size;
|
---|
| 357 | }
|
---|
| 358 |
|
---|
| 359 |
|
---|
| 360 | static int fill_t0(Xdf_t *This, int ptr, int size, int *sector, int *head)
|
---|
| 361 | {
|
---|
| 362 | int n;
|
---|
| 363 |
|
---|
| 364 | for(n = 0; n < size; ptr++,n++) {
|
---|
| 365 | REC.head = *head;
|
---|
| 366 | REC.sector = *sector + 129;
|
---|
| 367 | REC.phantom = 0;
|
---|
| 368 | (*sector)++;
|
---|
| 369 | if(!*head && *sector >= This->track0_size - 8) {
|
---|
| 370 | *sector = 0;
|
---|
| 371 | *head = 1;
|
---|
| 372 | }
|
---|
| 373 | }
|
---|
| 374 | return ptr;
|
---|
| 375 | }
|
---|
| 376 |
|
---|
| 377 |
|
---|
| 378 | static int fill_phantoms(Xdf_t *This, int ptr, int size)
|
---|
| 379 | {
|
---|
| 380 | int n;
|
---|
| 381 |
|
---|
| 382 | for(n = 0; n < size; ptr++,n++)
|
---|
| 383 | REC.phantom = 1;
|
---|
| 384 | return ptr;
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 | static void decompose(Xdf_t *This, int where, int len, off_t *begin,
|
---|
| 388 | off_t *end, int boot)
|
---|
| 389 | {
|
---|
| 390 | int ptr, track;
|
---|
| 391 | sector_map_t *map;
|
---|
| 392 | int lbegin, lend;
|
---|
| 393 |
|
---|
| 394 | track = where / This->track_size / 1024;
|
---|
| 395 |
|
---|
| 396 | *begin = where - track * This->track_size * 1024;
|
---|
| 397 | *end = where + len - track * This->track_size * 1024;
|
---|
| 398 | maximize(*end, This->track_size * 1024);
|
---|
| 399 |
|
---|
| 400 | if(This->current_track == track && !boot)
|
---|
| 401 | /* already OK, return immediately */
|
---|
| 402 | return;
|
---|
| 403 | if(!boot)
|
---|
| 404 | flush_dirty(This);
|
---|
| 405 | This->current_track = track;
|
---|
| 406 |
|
---|
| 407 | if(track) {
|
---|
| 408 | for(ptr=0, map=This->map; map->size; map++) {
|
---|
| 409 | /* iterate through all sectors */
|
---|
| 410 | lbegin = ptr;
|
---|
| 411 | lend = ptr + (128 << map->size) / This->sector_size;
|
---|
| 412 | for( ; ptr < lend ; ptr++) {
|
---|
| 413 | REC.begin = lbegin;
|
---|
| 414 | REC.end = lend;
|
---|
| 415 |
|
---|
| 416 | REC.head = map->head;
|
---|
| 417 | REC.sector = map->size + 128;
|
---|
| 418 | REC.sizecode = map->size;
|
---|
| 419 |
|
---|
| 420 | REC.valid = 0;
|
---|
| 421 | REC.dirty = 0;
|
---|
| 422 | REC.phantom = 0;
|
---|
| 423 | }
|
---|
| 424 | }
|
---|
| 425 | REC.begin = REC.end = ptr;
|
---|
| 426 | } else {
|
---|
| 427 | int sector, head;
|
---|
| 428 |
|
---|
| 429 | head = 0;
|
---|
| 430 | sector = 0;
|
---|
| 431 |
|
---|
| 432 | for(ptr=boot; ptr < 2 * This->track_size; ptr++) {
|
---|
| 433 | REC.begin = ptr;
|
---|
| 434 | REC.end = ptr+1;
|
---|
| 435 |
|
---|
| 436 | REC.sizecode = 2;
|
---|
| 437 |
|
---|
| 438 | REC.valid = 0;
|
---|
| 439 | REC.dirty = 0;
|
---|
| 440 | }
|
---|
| 441 |
|
---|
| 442 | /* boot & 1st fat */
|
---|
| 443 | ptr=fill_t0(This, 0, 1 + This->FatSize, §or, &head);
|
---|
| 444 |
|
---|
| 445 | /* second fat */
|
---|
| 446 | ptr=fill_phantoms(This, ptr, This->FatSize);
|
---|
| 447 |
|
---|
| 448 | /* root dir */
|
---|
| 449 | ptr=fill_t0(This, ptr, This->RootDirSize, §or, &head);
|
---|
| 450 |
|
---|
| 451 | /* "bad sectors" at the beginning of the fs */
|
---|
| 452 | ptr=fill_phantoms(This, ptr, 5);
|
---|
| 453 |
|
---|
| 454 | if(This->rootskip)
|
---|
| 455 | sector++;
|
---|
| 456 |
|
---|
| 457 | /* beginning of the file system */
|
---|
| 458 | ptr = fill_t0(This, ptr,
|
---|
| 459 | (This->track_size - This->FatSize) * 2 -
|
---|
| 460 | This->RootDirSize - 6,
|
---|
| 461 | §or, &head);
|
---|
| 462 | }
|
---|
| 463 | This->last_sector = ptr;
|
---|
| 464 | }
|
---|
| 465 |
|
---|
| 466 |
|
---|
| 467 | static int xdf_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
|
---|
| 468 | {
|
---|
| 469 | off_t begin, end;
|
---|
| 470 | size_t len2;
|
---|
| 471 | DeclareThis(Xdf_t);
|
---|
| 472 |
|
---|
| 473 | decompose(This, truncBytes32(where), len, &begin, &end, 0);
|
---|
| 474 | len2 = load_data(This, begin, end, 4);
|
---|
| 475 | if(len2 < 0)
|
---|
| 476 | return len2;
|
---|
| 477 | len2 -= begin;
|
---|
| 478 | maximize(len, len2);
|
---|
| 479 | memcpy(buf, This->buffer + begin, len);
|
---|
| 480 | return end - begin;
|
---|
| 481 | }
|
---|
| 482 |
|
---|
| 483 | static int xdf_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
|
---|
| 484 | {
|
---|
| 485 | off_t begin, end;
|
---|
| 486 | size_t len2;
|
---|
| 487 | DeclareThis(Xdf_t);
|
---|
| 488 |
|
---|
| 489 | decompose(This, truncBytes32(where), len, &begin, &end, 0);
|
---|
| 490 | len2 = load_bounds(This, begin, end);
|
---|
| 491 | if(len2 < 0)
|
---|
| 492 | return len2;
|
---|
| 493 | maximize(end, len2);
|
---|
| 494 | len2 -= begin;
|
---|
| 495 | maximize(len, len2);
|
---|
| 496 | memcpy(This->buffer + begin, buf, len);
|
---|
| 497 | mark_dirty(This, begin, end);
|
---|
| 498 | return end - begin;
|
---|
| 499 | }
|
---|
| 500 |
|
---|
| 501 | static int xdf_flush(Stream_t *Stream)
|
---|
| 502 | {
|
---|
| 503 | DeclareThis(Xdf_t);
|
---|
| 504 |
|
---|
| 505 | return flush_dirty(This);
|
---|
| 506 | }
|
---|
| 507 |
|
---|
| 508 | static int xdf_free(Stream_t *Stream)
|
---|
| 509 | {
|
---|
| 510 | DeclareThis(Xdf_t);
|
---|
| 511 | Free(This->track_map);
|
---|
| 512 | Free(This->buffer);
|
---|
| 513 | return close(This->fd);
|
---|
| 514 | }
|
---|
| 515 |
|
---|
| 516 |
|
---|
| 517 | static int check_geom(struct device *dev, int media, struct bootsector *boot)
|
---|
| 518 | {
|
---|
| 519 | int sect;
|
---|
| 520 |
|
---|
| 521 | if(media >= 0xfc && media <= 0xff)
|
---|
| 522 | return 1; /* old DOS */
|
---|
| 523 |
|
---|
| 524 | if (!IS_MFORMAT_ONLY(dev)) {
|
---|
| 525 | if(compare(dev->sectors, 19) &&
|
---|
| 526 | compare(dev->sectors, 23) &&
|
---|
| 527 | compare(dev->sectors, 24) &&
|
---|
| 528 | compare(dev->sectors, 46) &&
|
---|
| 529 | compare(dev->sectors, 48))
|
---|
| 530 | return 1;
|
---|
| 531 |
|
---|
| 532 | /* check against contradictory info from configuration file */
|
---|
| 533 | if(compare(dev->heads, 2))
|
---|
| 534 | return 1;
|
---|
| 535 | }
|
---|
| 536 |
|
---|
| 537 | /* check against info from boot */
|
---|
| 538 | if(boot) {
|
---|
| 539 | sect = WORD(nsect);
|
---|
| 540 | if((sect != 19 && sect != 23 && sect != 24 &&
|
---|
| 541 | sect != 46 && sect != 48) ||
|
---|
| 542 | (!IS_MFORMAT_ONLY(dev) && compare(dev->sectors, sect)) ||
|
---|
| 543 | WORD(nheads) !=2)
|
---|
| 544 | return 1;
|
---|
| 545 | }
|
---|
| 546 | return 0;
|
---|
| 547 | }
|
---|
| 548 |
|
---|
| 549 | static void set_geom(struct bootsector *boot, struct device *dev)
|
---|
| 550 | {
|
---|
| 551 | /* fill in config info to be returned to user */
|
---|
| 552 | dev->heads = 2;
|
---|
| 553 | dev->use_2m = 0xff;
|
---|
| 554 | if(boot) {
|
---|
| 555 | dev->sectors = WORD(nsect);
|
---|
| 556 | if(WORD(psect))
|
---|
| 557 | dev->tracks = WORD(psect) / dev->sectors / 2;
|
---|
| 558 | }
|
---|
| 559 | }
|
---|
| 560 |
|
---|
| 561 | static int config_geom(Stream_t *Stream, struct device *dev,
|
---|
| 562 | struct device *orig_dev, int media,
|
---|
| 563 | struct bootsector *boot)
|
---|
| 564 | {
|
---|
| 565 | if(check_geom(dev, media, boot))
|
---|
| 566 | return 1;
|
---|
| 567 | set_geom(boot,dev);
|
---|
| 568 | return 0;
|
---|
| 569 | }
|
---|
| 570 |
|
---|
| 571 | static Class_t XdfClass = {
|
---|
| 572 | xdf_read,
|
---|
| 573 | xdf_write,
|
---|
| 574 | xdf_flush,
|
---|
| 575 | xdf_free,
|
---|
| 576 | config_geom,
|
---|
| 577 | 0, /* get_data */
|
---|
| 578 | 0 /* pre-allocate */
|
---|
| 579 | };
|
---|
| 580 |
|
---|
| 581 | Stream_t *XdfOpen(struct device *dev, char *name,
|
---|
| 582 | int mode, char *errmsg, struct xdf_info *info)
|
---|
| 583 | {
|
---|
| 584 | Xdf_t *This;
|
---|
| 585 | off_t begin, end;
|
---|
| 586 | struct bootsector *boot;
|
---|
| 587 | int type;
|
---|
| 588 |
|
---|
| 589 | if(dev && (!SHOULD_USE_XDF(dev) || check_geom(dev, 0, 0)))
|
---|
| 590 | return NULL;
|
---|
| 591 |
|
---|
| 592 | This = New(Xdf_t);
|
---|
| 593 | if (!This)
|
---|
| 594 | return NULL;
|
---|
| 595 |
|
---|
| 596 | This->Class = &XdfClass;
|
---|
| 597 | This->sector_size = 512;
|
---|
| 598 | This->stretch = 0;
|
---|
| 599 |
|
---|
| 600 | precmd(dev);
|
---|
| 601 | This->fd = open(name, mode | dev->mode | O_EXCL | O_NDELAY);
|
---|
| 602 | if(This->fd < 0) {
|
---|
| 603 | #ifdef HAVE_SNPRINTF
|
---|
| 604 | snprintf(errmsg,199,"xdf floppy: open: \"%s\"", strerror(errno));
|
---|
| 605 | #else
|
---|
| 606 | sprintf(errmsg,"xdf floppy: open: \"%s\"", strerror(errno));
|
---|
| 607 | #endif
|
---|
| 608 | goto exit_0;
|
---|
| 609 | }
|
---|
| 610 | closeExec(This->fd);
|
---|
| 611 |
|
---|
| 612 | This->drive = GET_DRIVE(This->fd);
|
---|
| 613 | if(This->drive < 0)
|
---|
| 614 | goto exit_1;
|
---|
| 615 |
|
---|
| 616 | /* allocate buffer */
|
---|
| 617 | This->buffer = (char *) malloc(96 * 512);
|
---|
| 618 | if (!This->buffer)
|
---|
| 619 | goto exit_1;
|
---|
| 620 |
|
---|
| 621 | This->current_track = -1;
|
---|
| 622 | This->track_map = (TrackMap_t *)
|
---|
| 623 | calloc(96, sizeof(TrackMap_t));
|
---|
| 624 | if(!This->track_map)
|
---|
| 625 | goto exit_2;
|
---|
| 626 |
|
---|
| 627 | /* lock the device on writes */
|
---|
| 628 | if (lock_dev(This->fd, mode == O_RDWR, dev)) {
|
---|
| 629 | #ifdef HAVE_SNPRINTF
|
---|
| 630 | snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:",
|
---|
| 631 | dev->name);
|
---|
| 632 | #else
|
---|
| 633 | sprintf(errmsg,"xdf floppy: device \"%s\" busy:",
|
---|
| 634 | dev->name);
|
---|
| 635 | #endif
|
---|
| 636 | goto exit_3;
|
---|
| 637 | }
|
---|
| 638 |
|
---|
| 639 | /* Before reading the boot sector, assume dummy values suitable
|
---|
| 640 | * for reading at least the boot sector */
|
---|
| 641 | This->track_size = 11;
|
---|
| 642 | This->track0_size = 6;
|
---|
| 643 | This->rate = 0;
|
---|
| 644 | This->FatSize = 9;
|
---|
| 645 | This->RootDirSize = 1;
|
---|
| 646 | decompose(This, 0, 512, &begin, &end, 0);
|
---|
| 647 | if (load_data(This, 0, 1, 1) < 0 ) {
|
---|
| 648 | This->rate = 0x43;
|
---|
| 649 | if(load_data(This, 0, 1, 1) < 0)
|
---|
| 650 | goto exit_3;
|
---|
| 651 | }
|
---|
| 652 |
|
---|
| 653 | boot = (struct bootsector *) This->buffer;
|
---|
| 654 | This->FatSize = WORD(fatlen);
|
---|
| 655 | This->RootDirSize = WORD(dirents)/16;
|
---|
| 656 | This->track_size = WORD(nsect);
|
---|
| 657 | for(type=0; type < NUMBER(xdf_table); type++) {
|
---|
| 658 | if(xdf_table[type].track_size == This->track_size) {
|
---|
| 659 | This->map = xdf_table[type].map;
|
---|
| 660 | This->track0_size = xdf_table[type].track0_size;
|
---|
| 661 | This->rootskip = xdf_table[type].rootskip;
|
---|
| 662 | break;
|
---|
| 663 | }
|
---|
| 664 | }
|
---|
| 665 | if(type == NUMBER(xdf_table))
|
---|
| 666 | goto exit_3;
|
---|
| 667 |
|
---|
| 668 | if(info) {
|
---|
| 669 | info->RootDirSize = This->RootDirSize;
|
---|
| 670 | info->FatSize = This->FatSize;
|
---|
| 671 | info->BadSectors = 5;
|
---|
| 672 | }
|
---|
| 673 | decompose(This, 0, 512, &begin, &end, 1);
|
---|
| 674 |
|
---|
| 675 | This->refs = 1;
|
---|
| 676 | This->Next = 0;
|
---|
| 677 | This->Buffer = 0;
|
---|
| 678 | if(dev)
|
---|
| 679 | set_geom(boot, dev);
|
---|
| 680 | return (Stream_t *) This;
|
---|
| 681 |
|
---|
| 682 | exit_3:
|
---|
| 683 | Free(This->track_map);
|
---|
| 684 | exit_2:
|
---|
| 685 | Free(This->buffer);
|
---|
| 686 | exit_1:
|
---|
| 687 | close(This->fd);
|
---|
| 688 | exit_0:
|
---|
| 689 | Free(This);
|
---|
| 690 | return NULL;
|
---|
| 691 | }
|
---|
| 692 |
|
---|
| 693 | #endif
|
---|
| 694 |
|
---|
| 695 | /* Algorithms can't be patented */
|
---|
| 696 |
|
---|