00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "sysincludes.h"
00013 #ifdef OS_linux
00014 #include "msdos.h"
00015 #include "mtools.h"
00016 #include "devices.h"
00017 #include "xdf_io.h"
00018
00019 extern int errno;
00020
00021
00022
00023 typedef struct sector_map {
00024 unsigned int head:1;
00025 unsigned int size:7;
00026 } sector_map_t;
00027
00028
00029 struct {
00030 unsigned char track_size;
00031 unsigned int track0_size:7;
00032 unsigned int rootskip:1;
00033 unsigned char rate;
00034 sector_map_t map[9];
00035 } xdf_table[]= {
00036 {
00037 19, 16, 0, 0,
00038 { {0,3}, {0,6}, {1,2}, {0,2}, {1,6}, {1,3}, {0,0} }
00039 },
00040 {
00041 23, 19, 0, 0,
00042 { {0,3}, {0,4}, {1,6}, {0,2}, {1,2}, {0,6}, {1,4}, {1,3}, {0,0} }
00043 },
00044 {
00045 46, 37, 0x43, 1,
00046 { {0,3}, {0,4}, {0,5}, {0,7}, {1,3}, {1,4}, {1,5}, {1,7}, {0,0} }
00047 },
00048 {
00049 24, 20, 0, 1,
00050 { {0,5}, {1,6}, {0,6}, {1, 5} }
00051 },
00052 {
00053 48, 41, 0, 1,
00054 { {0,6}, {1,7}, {0,7}, {1, 6} }
00055 }
00056 };
00057
00058 #define NUMBER(x) (sizeof(x)/sizeof(x[0]))
00059
00060 typedef struct {
00061 unsigned char begin;
00062 unsigned char end;
00063 unsigned char sector;
00064 unsigned char sizecode;
00065
00066 unsigned int dirty:1;
00067 unsigned int phantom:2;
00068 unsigned int valid:1;
00069 unsigned int head:1;
00070 } TrackMap_t;
00071
00072
00073
00074 typedef struct Xdf_t {
00075 Class_t *Class;
00076 int refs;
00077 Stream_t *Next;
00078 Stream_t *Buffer;
00079
00080 int fd;
00081 char *buffer;
00082
00083 int current_track;
00084
00085 sector_map_t *map;
00086
00087 int track_size;
00088 int track0_size;
00089 int sector_size;
00090 int FatSize;
00091 int RootDirSize;
00092 TrackMap_t *track_map;
00093
00094 unsigned char last_sector;
00095 unsigned char rate;
00096
00097 unsigned int stretch:1;
00098 unsigned int rootskip:1;
00099 signed int drive:4;
00100 } Xdf_t;
00101
00102 typedef struct {
00103 unsigned char head;
00104 unsigned char sector;
00105 unsigned char ptr;
00106 } Compactify_t;
00107
00108
00109 static int analyze_reply(RawRequest_t *raw_cmd, int do_print)
00110 {
00111 int ret, bytes, newbytes;
00112
00113 bytes = 0;
00114 while(1) {
00115 ret = analyze_one_reply(raw_cmd, &newbytes, do_print);
00116 bytes += newbytes;
00117 switch(ret) {
00118 case 0:
00119 return bytes;
00120 case 1:
00121 raw_cmd++;
00122 break;
00123 case -1:
00124 if(bytes)
00125 return bytes;
00126 else
00127 return 0;
00128 }
00129 }
00130 }
00131
00132
00133
00134 static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr,
00135 const char *message, int retries)
00136 {
00137 int j;
00138 int ret=-1;
00139
00140 if(!nr)
00141 return 0;
00142 for (j=0; j< retries; j++){
00143 switch(send_one_cmd(fd, raw_cmd, message)) {
00144 case -1:
00145 return -1;
00146 case 1:
00147 j++;
00148 continue;
00149 case 0:
00150 break;
00151 }
00152 if((ret=analyze_reply(raw_cmd, j)) > 0)
00153 return ret;
00154 }
00155 if(j > 1 && j == retries) {
00156 fprintf(stderr,"Too many errors, giving up\n");
00157 return 0;
00158 }
00159 return -1;
00160 }
00161
00162
00163
00164 #define REC (This->track_map[ptr])
00165 #define END(x) (This->track_map[(x)].end)
00166 #define BEGIN(x) (This->track_map[(x)].begin)
00167
00168 static int add_to_request(Xdf_t *This, int ptr,
00169 RawRequest_t *request, int *nr,
00170 int direction, Compactify_t *compactify)
00171 {
00172 #if 0
00173 if(direction == MT_WRITE) {
00174 printf("writing %d: %d %d %d %d [%02x]\n",
00175 ptr, This->current_track,
00176 REC.head, REC.sector, REC.sizecode,
00177 *(This->buffer + ptr * This->sector_size));
00178 } else
00179 printf(" load %d.%d\n", This->current_track, ptr);
00180 #endif
00181 if(REC.phantom) {
00182 if(direction== MT_READ)
00183 memset(This->buffer + ptr * This->sector_size, 0,
00184 128 << REC.sizecode);
00185 return 0;
00186 }
00187
00188 if(*nr &&
00189 RR_SIZECODE(request+(*nr)-1) == REC.sizecode &&
00190 compactify->head == REC.head &&
00191 compactify->ptr + 1 == ptr &&
00192 compactify->sector +1 == REC.sector) {
00193 RR_SETSIZECODE(request+(*nr)-1, REC.sizecode);
00194 } else {
00195 if(*nr)
00196 RR_SETCONT(request+(*nr)-1);
00197 RR_INIT(request+(*nr));
00198 RR_SETDRIVE(request+(*nr), This->drive);
00199 RR_SETRATE(request+(*nr), This->rate);
00200 RR_SETTRACK(request+(*nr), This->current_track);
00201 RR_SETPTRACK(request+(*nr),
00202 This->current_track << This->stretch);
00203 RR_SETHEAD(request+(*nr), REC.head);
00204 RR_SETSECTOR(request+(*nr), REC.sector);
00205 RR_SETSIZECODE(request+(*nr), REC.sizecode);
00206 RR_SETDIRECTION(request+(*nr), direction);
00207 RR_SETDATA(request+(*nr),
00208 (caddr_t) This->buffer + ptr * This->sector_size);
00209 (*nr)++;
00210 }
00211 compactify->ptr = ptr;
00212 compactify->head = REC.head;
00213 compactify->sector = REC.sector;
00214 return 0;
00215 }
00216
00217
00218 static void add_to_request_if_invalid(Xdf_t *This, int ptr,
00219 RawRequest_t *request, int *nr,
00220 Compactify_t *compactify)
00221 {
00222 if(!REC.valid)
00223 add_to_request(This, ptr, request, nr, MT_READ, compactify);
00224
00225 }
00226
00227
00228 static void adjust_bounds(Xdf_t *This, off_t *begin, off_t *end)
00229 {
00230
00231 *begin = *begin / This->sector_size;
00232 *end = (*end + This->sector_size - 1) / This->sector_size;
00233 }
00234
00235
00236 static inline int try_flush_dirty(Xdf_t *This)
00237 {
00238 int ptr, nr, bytes;
00239 RawRequest_t requests[100];
00240 Compactify_t compactify;
00241
00242 if(This->current_track < 0)
00243 return 0;
00244
00245 nr = 0;
00246 for(ptr=0; ptr < This->last_sector; ptr=REC.end)
00247 if(REC.dirty)
00248 add_to_request(This, ptr,
00249 requests, &nr,
00250 MT_WRITE, &compactify);
00251 #if 1
00252 bytes = send_cmd(This->fd,requests, nr, "writing", 4);
00253 if(bytes < 0)
00254 return bytes;
00255 #else
00256 bytes = 0xffffff;
00257 #endif
00258 for(ptr=0; ptr < This->last_sector; ptr=REC.end)
00259 if(REC.dirty) {
00260 if(bytes >= REC.end - REC.begin) {
00261 bytes -= REC.end - REC.begin;
00262 REC.dirty = 0;
00263 } else
00264 return 1;
00265 }
00266 return 0;
00267 }
00268
00269
00270
00271 static int flush_dirty(Xdf_t *This)
00272 {
00273 int ret;
00274
00275 while((ret = try_flush_dirty(This))) {
00276 if(ret < 0)
00277 return ret;
00278 }
00279 return 0;
00280 }
00281
00282
00283 static int load_data(Xdf_t *This, off_t begin, off_t end, int retries)
00284 {
00285 int ptr, nr, bytes;
00286 RawRequest_t requests[100];
00287 Compactify_t compactify;
00288
00289 adjust_bounds(This, &begin, &end);
00290
00291 ptr = begin;
00292 nr = 0;
00293 for(ptr=REC.begin; ptr < end ; ptr = REC.end)
00294 add_to_request_if_invalid(This, ptr, requests, &nr,
00295 &compactify);
00296 bytes = send_cmd(This->fd,requests, nr, "reading", retries);
00297 if(bytes < 0)
00298 return bytes;
00299 ptr = begin;
00300 for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
00301 if(!REC.valid) {
00302 if(bytes >= REC.end - REC.begin) {
00303 bytes -= REC.end - REC.begin;
00304 REC.valid = 1;
00305 } else if(ptr > begin)
00306 return ptr * This->sector_size;
00307 else
00308 return -1;
00309 }
00310 }
00311 return end * This->sector_size;
00312 }
00313
00314 static void mark_dirty(Xdf_t *This, off_t begin, off_t end)
00315 {
00316 int ptr;
00317
00318 adjust_bounds(This, &begin, &end);
00319
00320 ptr = begin;
00321 for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
00322 REC.valid = 1;
00323 if(!REC.phantom)
00324 REC.dirty = 1;
00325 }
00326 }
00327
00328
00329 static int load_bounds(Xdf_t *This, off_t begin, off_t end)
00330 {
00331 off_t lbegin, lend;
00332 int endp1, endp2;
00333
00334 lbegin = begin;
00335 lend = end;
00336
00337 adjust_bounds(This, &lbegin, &lend);
00338
00339 if(begin != BEGIN(lbegin) * This->sector_size &&
00340 end != BEGIN(lend) * This->sector_size &&
00341 lend < END(END(lbegin)))
00342
00343 return load_data(This, begin, end, 4);
00344
00345 if(begin != BEGIN(lbegin) * This->sector_size) {
00346 endp1 = load_data(This, begin, begin, 4);
00347 if(endp1 < 0)
00348 return endp1;
00349 }
00350
00351 if(end != BEGIN(lend) * This->sector_size) {
00352 endp2 = load_data(This, end, end, 4);
00353 if(endp2 < 0)
00354 return BEGIN(lend) * This->sector_size;
00355 }
00356 return lend * This->sector_size;
00357 }
00358
00359
00360 static int fill_t0(Xdf_t *This, int ptr, int size, int *sector, int *head)
00361 {
00362 int n;
00363
00364 for(n = 0; n < size; ptr++,n++) {
00365 REC.head = *head;
00366 REC.sector = *sector + 129;
00367 REC.phantom = 0;
00368 (*sector)++;
00369 if(!*head && *sector >= This->track0_size - 8) {
00370 *sector = 0;
00371 *head = 1;
00372 }
00373 }
00374 return ptr;
00375 }
00376
00377
00378 static int fill_phantoms(Xdf_t *This, int ptr, int size)
00379 {
00380 int n;
00381
00382 for(n = 0; n < size; ptr++,n++)
00383 REC.phantom = 1;
00384 return ptr;
00385 }
00386
00387 static void decompose(Xdf_t *This, int where, int len, off_t *begin,
00388 off_t *end, int boot)
00389 {
00390 int ptr, track;
00391 sector_map_t *map;
00392 int lbegin, lend;
00393
00394 track = where / This->track_size / 1024;
00395
00396 *begin = where - track * This->track_size * 1024;
00397 *end = where + len - track * This->track_size * 1024;
00398 maximize(*end, This->track_size * 1024);
00399
00400 if(This->current_track == track && !boot)
00401
00402 return;
00403 if(!boot)
00404 flush_dirty(This);
00405 This->current_track = track;
00406
00407 if(track) {
00408 for(ptr=0, map=This->map; map->size; map++) {
00409
00410 lbegin = ptr;
00411 lend = ptr + (128 << map->size) / This->sector_size;
00412 for( ; ptr < lend ; ptr++) {
00413 REC.begin = lbegin;
00414 REC.end = lend;
00415
00416 REC.head = map->head;
00417 REC.sector = map->size + 128;
00418 REC.sizecode = map->size;
00419
00420 REC.valid = 0;
00421 REC.dirty = 0;
00422 REC.phantom = 0;
00423 }
00424 }
00425 REC.begin = REC.end = ptr;
00426 } else {
00427 int sector, head;
00428
00429 head = 0;
00430 sector = 0;
00431
00432 for(ptr=boot; ptr < 2 * This->track_size; ptr++) {
00433 REC.begin = ptr;
00434 REC.end = ptr+1;
00435
00436 REC.sizecode = 2;
00437
00438 REC.valid = 0;
00439 REC.dirty = 0;
00440 }
00441
00442
00443 ptr=fill_t0(This, 0, 1 + This->FatSize, §or, &head);
00444
00445
00446 ptr=fill_phantoms(This, ptr, This->FatSize);
00447
00448
00449 ptr=fill_t0(This, ptr, This->RootDirSize, §or, &head);
00450
00451
00452 ptr=fill_phantoms(This, ptr, 5);
00453
00454 if(This->rootskip)
00455 sector++;
00456
00457
00458 ptr = fill_t0(This, ptr,
00459 (This->track_size - This->FatSize) * 2 -
00460 This->RootDirSize - 6,
00461 §or, &head);
00462 }
00463 This->last_sector = ptr;
00464 }
00465
00466
00467 static int xdf_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
00468 {
00469 off_t begin, end;
00470 size_t len2;
00471 DeclareThis(Xdf_t);
00472
00473 decompose(This, truncBytes32(where), len, &begin, &end, 0);
00474 len2 = load_data(This, begin, end, 4);
00475 if(len2 < 0)
00476 return len2;
00477 len2 -= begin;
00478 maximize(len, len2);
00479 memcpy(buf, This->buffer + begin, len);
00480 return end - begin;
00481 }
00482
00483 static int xdf_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
00484 {
00485 off_t begin, end;
00486 size_t len2;
00487 DeclareThis(Xdf_t);
00488
00489 decompose(This, truncBytes32(where), len, &begin, &end, 0);
00490 len2 = load_bounds(This, begin, end);
00491 if(len2 < 0)
00492 return len2;
00493 maximize(end, len2);
00494 len2 -= begin;
00495 maximize(len, len2);
00496 memcpy(This->buffer + begin, buf, len);
00497 mark_dirty(This, begin, end);
00498 return end - begin;
00499 }
00500
00501 static int xdf_flush(Stream_t *Stream)
00502 {
00503 DeclareThis(Xdf_t);
00504
00505 return flush_dirty(This);
00506 }
00507
00508 static int xdf_free(Stream_t *Stream)
00509 {
00510 DeclareThis(Xdf_t);
00511 Free(This->track_map);
00512 Free(This->buffer);
00513 return close(This->fd);
00514 }
00515
00516
00517 static int check_geom(struct device *dev, int media, struct bootsector *boot)
00518 {
00519 int sect;
00520
00521 if(media >= 0xfc && media <= 0xff)
00522 return 1;
00523
00524 if (!IS_MFORMAT_ONLY(dev)) {
00525 if(compare(dev->sectors, 19) &&
00526 compare(dev->sectors, 23) &&
00527 compare(dev->sectors, 24) &&
00528 compare(dev->sectors, 46) &&
00529 compare(dev->sectors, 48))
00530 return 1;
00531
00532
00533 if(compare(dev->heads, 2))
00534 return 1;
00535 }
00536
00537
00538 if(boot) {
00539 sect = WORD(nsect);
00540 if((sect != 19 && sect != 23 && sect != 24 &&
00541 sect != 46 && sect != 48) ||
00542 (!IS_MFORMAT_ONLY(dev) && compare(dev->sectors, sect)) ||
00543 WORD(nheads) !=2)
00544 return 1;
00545 }
00546 return 0;
00547 }
00548
00549 static void set_geom(struct bootsector *boot, struct device *dev)
00550 {
00551
00552 dev->heads = 2;
00553 dev->use_2m = 0xff;
00554 if(boot) {
00555 dev->sectors = WORD(nsect);
00556 if(WORD(psect))
00557 dev->tracks = WORD(psect) / dev->sectors / 2;
00558 }
00559 }
00560
00561 static int config_geom(Stream_t *Stream, struct device *dev,
00562 struct device *orig_dev, int media,
00563 struct bootsector *boot)
00564 {
00565 if(check_geom(dev, media, boot))
00566 return 1;
00567 set_geom(boot,dev);
00568 return 0;
00569 }
00570
00571 static Class_t XdfClass = {
00572 xdf_read,
00573 xdf_write,
00574 xdf_flush,
00575 xdf_free,
00576 config_geom,
00577 0,
00578 0
00579 };
00580
00581 Stream_t *XdfOpen(struct device *dev, char *name,
00582 int mode, char *errmsg, struct xdf_info *info)
00583 {
00584 Xdf_t *This;
00585 off_t begin, end;
00586 struct bootsector *boot;
00587 int type;
00588
00589 if(dev && (!SHOULD_USE_XDF(dev) || check_geom(dev, 0, 0)))
00590 return NULL;
00591
00592 This = New(Xdf_t);
00593 if (!This)
00594 return NULL;
00595
00596 This->Class = &XdfClass;
00597 This->sector_size = 512;
00598 This->stretch = 0;
00599
00600 precmd(dev);
00601 This->fd = open(name, mode | dev->mode | O_EXCL | O_NDELAY);
00602 if(This->fd < 0) {
00603 #ifdef HAVE_SNPRINTF
00604 snprintf(errmsg,199,"xdf floppy: open: \"%s\"", strerror(errno));
00605 #else
00606 sprintf(errmsg,"xdf floppy: open: \"%s\"", strerror(errno));
00607 #endif
00608 goto exit_0;
00609 }
00610 closeExec(This->fd);
00611
00612 This->drive = GET_DRIVE(This->fd);
00613 if(This->drive < 0)
00614 goto exit_1;
00615
00616
00617 This->buffer = (char *) malloc(96 * 512);
00618 if (!This->buffer)
00619 goto exit_1;
00620
00621 This->current_track = -1;
00622 This->track_map = (TrackMap_t *)
00623 calloc(96, sizeof(TrackMap_t));
00624 if(!This->track_map)
00625 goto exit_2;
00626
00627
00628 if (lock_dev(This->fd, mode == O_RDWR, dev)) {
00629 #ifdef HAVE_SNPRINTF
00630 snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:",
00631 dev->name);
00632 #else
00633 sprintf(errmsg,"xdf floppy: device \"%s\" busy:",
00634 dev->name);
00635 #endif
00636 goto exit_3;
00637 }
00638
00639
00640
00641 This->track_size = 11;
00642 This->track0_size = 6;
00643 This->rate = 0;
00644 This->FatSize = 9;
00645 This->RootDirSize = 1;
00646 decompose(This, 0, 512, &begin, &end, 0);
00647 if (load_data(This, 0, 1, 1) < 0 ) {
00648 This->rate = 0x43;
00649 if(load_data(This, 0, 1, 1) < 0)
00650 goto exit_3;
00651 }
00652
00653 boot = (struct bootsector *) This->buffer;
00654 This->FatSize = WORD(fatlen);
00655 This->RootDirSize = WORD(dirents)/16;
00656 This->track_size = WORD(nsect);
00657 for(type=0; type < NUMBER(xdf_table); type++) {
00658 if(xdf_table[type].track_size == This->track_size) {
00659 This->map = xdf_table[type].map;
00660 This->track0_size = xdf_table[type].track0_size;
00661 This->rootskip = xdf_table[type].rootskip;
00662 break;
00663 }
00664 }
00665 if(type == NUMBER(xdf_table))
00666 goto exit_3;
00667
00668 if(info) {
00669 info->RootDirSize = This->RootDirSize;
00670 info->FatSize = This->FatSize;
00671 info->BadSectors = 5;
00672 }
00673 decompose(This, 0, 512, &begin, &end, 1);
00674
00675 This->refs = 1;
00676 This->Next = 0;
00677 This->Buffer = 0;
00678 if(dev)
00679 set_geom(boot, dev);
00680 return (Stream_t *) This;
00681
00682 exit_3:
00683 Free(This->track_map);
00684 exit_2:
00685 Free(This->buffer);
00686 exit_1:
00687 close(This->fd);
00688 exit_0:
00689 Free(This);
00690 return NULL;
00691 }
00692
00693 #endif
00694
00695
00696