xdf_io.c

Go to the documentation of this file.
00001 /*
00002  * Io to an xdf disk
00003  *
00004  * written by:
00005  *
00006  * Alain L. Knaff
00007  * alain@linux.lu
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 /* Algorithms can't be patented */
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; /* where it begins */
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; /* ok */
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         /* translates begin and end from byte to sectors */
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                 /* contiguous end & begin, load them in one go */
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                 /* already OK, return immediately */
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                         /* iterate through all sectors */
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                 /* boot & 1st fat */
00443                 ptr=fill_t0(This, 0, 1 + This->FatSize, &sector, &head);
00444 
00445                 /* second fat */
00446                 ptr=fill_phantoms(This, ptr, This->FatSize);
00447 
00448                 /* root dir */
00449                 ptr=fill_t0(This, ptr, This->RootDirSize, &sector, &head);
00450                 
00451                 /* "bad sectors" at the beginning of the fs */
00452                 ptr=fill_phantoms(This, ptr, 5);
00453 
00454                 if(This->rootskip)
00455                         sector++;
00456 
00457                 /* beginning of the file system */
00458                 ptr = fill_t0(This, ptr,
00459                               (This->track_size - This->FatSize) * 2 -
00460                               This->RootDirSize - 6,
00461                               &sector, &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; /* old DOS */
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             /* check against contradictory info from configuration file */
00533             if(compare(dev->heads, 2))
00534                 return 1;
00535         }
00536 
00537         /* check against info from boot */
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         /* fill in config info to be returned to user */
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, /* get_data */
00578         0 /* pre-allocate */
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         /* allocate buffer */
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         /* lock the device on writes */
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         /* Before reading the boot sector, assume dummy values suitable
00640          * for reading at least the boot sector */
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 /* Algorithms can't be patented */
00696 

Generated on Fri Apr 14 22:56:56 2006 for minix by  doxygen 1.4.6