home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / CMDS / mtools_3.6.src.lzh / MTOOLS_3.6 / xdf_io.c < prev    next >
Text File  |  1997-11-12  |  14KB  |  686 lines

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