home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / disk-man / mtools-3.000 / mtools-3 / mtools-3.0 / xdf_io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-08  |  11.0 KB  |  572 lines

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