source: trunk/minix/commands/i386/mtools-3.9.7/xdf_io.c@ 20

Last change on this file since 20 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 13.9 KB
Line 
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
19extern int errno;
20
21/* Algorithms can't be patented */
22
23typedef struct sector_map {
24 unsigned int head:1;
25 unsigned int size:7;
26} sector_map_t;
27
28
29struct {
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
60typedef 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
74typedef 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
102typedef struct {
103 unsigned char head;
104 unsigned char sector;
105 unsigned char ptr;
106} Compactify_t;
107
108
109static 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
134static 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
168static 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
218static 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
228static 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
236static 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
271static 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
283static 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
314static 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
329static 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
360static 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
378static 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
387static 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, &sector, &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, &sector, &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 &sector, &head);
462 }
463 This->last_sector = ptr;
464}
465
466
467static 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
483static 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
501static int xdf_flush(Stream_t *Stream)
502{
503 DeclareThis(Xdf_t);
504
505 return flush_dirty(This);
506}
507
508static 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
517static 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
549static 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
561static 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
571static 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
581Stream_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
682exit_3:
683 Free(This->track_map);
684exit_2:
685 Free(This->buffer);
686exit_1:
687 close(This->fd);
688exit_0:
689 Free(This);
690 return NULL;
691}
692
693#endif
694
695/* Algorithms can't be patented */
696
Note: See TracBrowser for help on using the repository browser.