]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/fdread/fdutil.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.sbin / fdread / fdutil.c
1 /*
2  * Copyright (c) 2001 Joerg Wunsch
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <dev/ic/nec765.h>
30
31 #include <sys/fdcio.h>
32
33 #include <err.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sysexits.h>
38
39 #include "fdutil.h"
40
41 /*
42  * Decode the FDC status pointed to by `fdcsp', and print a textual
43  * translation to stderr.  If `terse' is false, the numerical FDC
44  * register status is printed, too.
45  */
46 void
47 printstatus(struct fdc_status *fdcsp, int terse)
48 {
49         char msgbuf[100];
50
51         if (!terse)
52                 fprintf(stderr,
53                 "\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n",
54                         fdcsp->status[0] & 0xff,
55                         fdcsp->status[1] & 0xff,
56                         fdcsp->status[2] & 0xff,
57                         fdcsp->status[3] & 0xff,
58                         fdcsp->status[4] & 0xff,
59                         fdcsp->status[5] & 0xff,
60                         fdcsp->status[6] & 0xff);
61
62         if ((fdcsp->status[0] & NE7_ST0_IC_RC) == 0) {
63                 sprintf(msgbuf, "timeout");
64         } else if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) {
65                 sprintf(msgbuf, "unexcpted interrupt code %#x",
66                         fdcsp->status[0] & NE7_ST0_IC_RC);
67         } else {
68                 strcpy(msgbuf, "unexpected error code in ST1/ST2");
69
70                 if (fdcsp->status[1] & NE7_ST1_EN)
71                         strcpy(msgbuf, "end of cylinder (wrong format)");
72                 else if (fdcsp->status[1] & NE7_ST1_DE) {
73                         if (fdcsp->status[2] & NE7_ST2_DD)
74                                 strcpy(msgbuf, "CRC error in data field");
75                         else
76                                 strcpy(msgbuf, "CRC error in ID field");
77                 } else if (fdcsp->status[1] & NE7_ST1_MA) {
78                         if (fdcsp->status[2] & NE7_ST2_MD)
79                                 strcpy(msgbuf, "no address mark in data field");
80                         else
81                                 strcpy(msgbuf, "no address mark in ID field");
82                 } else if (fdcsp->status[2] & NE7_ST2_WC)
83                         strcpy(msgbuf, "wrong cylinder (format mismatch)");
84                 else if (fdcsp->status[1] & NE7_ST1_ND)
85                         strcpy(msgbuf, "no data (sector not found)");
86         }
87         fputs(msgbuf, stderr);
88 }
89
90 static struct fd_type fd_types_auto[1] =
91     { { 0,0,0,0,0,0,0,0,0,0,0,FL_AUTO } };
92
93
94 static struct fd_type fd_types_288m[] = {
95 #if 0
96         { FDF_3_2880 },
97 #endif
98         { FDF_3_1722 },
99         { FDF_3_1476 },
100         { FDF_3_1440 },
101         { FDF_3_1200 },
102         { FDF_3_820 },
103         { FDF_3_800 },
104         { FDF_3_720 },
105         { 0,0,0,0,0,0,0,0,0,0,0,0 }
106 };
107
108 static struct fd_type fd_types_144m[] = {
109 #ifdef PC98
110 #if 0
111         { FDF_3_1722 },
112         { FDF_3_1476 },
113 #endif
114         { FDF_3_1440 },
115         { FDF_3_1200 },
116 #if 0
117         { FDF_3_820 },
118         { FDF_3_800 },
119 #endif
120         { FDF_3_720 },
121         { FDF_3_360 },
122         { FDF_3_640 },
123         { FDF_3_1230 },
124 #if 0
125         { FDF_3_1280 },
126         { FDF_3_1480 },
127         { FDF_3_1640 },
128 #endif
129         { 0,0,0,0,0,0,0,0,0,0,0,0 }
130 #else
131         { FDF_3_1722 },
132         { FDF_3_1476 },
133         { FDF_3_1440 },
134         { FDF_3_1200 },
135         { FDF_3_820 },
136         { FDF_3_800 },
137         { FDF_3_720 },
138         { 0,0,0,0,0,0,0,0,0,0,0,0 }
139 #endif
140 };
141
142 static struct fd_type fd_types_12m[] = {
143 #ifdef PC98
144         { FDF_5_1200 },
145 #if 0
146         { FDF_5_820 },
147         { FDF_5_800 },
148 #endif
149         { FDF_5_720 },
150         { FDF_5_360 },
151         { FDF_5_640 },
152         { FDF_5_1230 },
153 #if 0
154         { FDF_5_1280 },
155 #endif
156         { 0,0,0,0,0,0,0,0,0,0,0,0 }
157 #else
158         { FDF_5_1200 },
159         { FDF_5_1230 },
160         { FDF_5_1480 },
161         { FDF_5_1440 },
162         { FDF_5_820 },
163         { FDF_5_800 },
164         { FDF_5_720 },
165         { FDF_5_360 | FL_2STEP },
166         { FDF_5_640 },
167         { 0,0,0,0,0,0,0,0,0,0,0,0 }
168 #endif
169 };
170
171 static struct fd_type fd_types_720k[] =
172 {
173         { FDF_3_720 },
174         { 0,0,0,0,0,0,0,0,0,0,0,0 }
175 };
176
177 static struct fd_type fd_types_360k[] =
178 {
179         { FDF_5_360 },
180         { 0,0,0,0,0,0,0,0,0,0,0,0 }
181 };
182
183
184 /*
185  * Parse a format string, and fill in the parameter pointed to by `out'.
186  *
187  * sectrac,secsize,datalen,gap,ncyls,speed,heads,f_gap,f_inter,offs2,flags[...]
188  *
189  * sectrac = sectors per track
190  * secsize = sector size in bytes
191  * datalen = length of sector if secsize == 128
192  * gap     = gap length when reading
193  * ncyls   = number of cylinders
194  * speed   = transfer speed 250/300/500/1000 KB/s
195  * heads   = number of heads
196  * f_gap   = gap length when formatting
197  * f_inter = sector interleave when formatting
198  * offs2   = offset of sectors on side 2
199  * flags   = +/-mfm | +/-2step | +/-perpend
200  *             mfm - use MFM recording
201  *             2step - use 2 steps between cylinders
202  *             perpend - user perpendicular (vertical) recording
203  *
204  * Any omitted value will be passed on from parameter `in'.
205  */
206 void
207 parse_fmt(const char *s, enum fd_drivetype type,
208           struct fd_type in, struct fd_type *out)
209 {
210         int i, j;
211         const char *cp;
212         char *s1;
213
214         *out = in;
215
216         for (i = 0;; i++) {
217                 if (s == 0)
218                         break;
219
220                 if ((cp = strchr(s, ',')) == 0) {
221                         s1 = strdup(s);
222                         if (s1 == NULL)
223                                 abort();
224                         s = 0;
225                 } else {
226                         s1 = malloc(cp - s + 1);
227                         if (s1 == NULL)
228                                 abort();
229                         memcpy(s1, s, cp - s);
230                         s1[cp - s] = 0;
231
232                         s = cp + 1;
233                 }
234                 if (strlen(s1) == 0) {
235                         free(s1);
236                         continue;
237                 }
238
239                 switch (i) {
240                 case 0:         /* sectrac */
241                         if (getnum(s1, &out->sectrac))
242                                 errx(EX_USAGE,
243                                      "bad numeric value for sectrac: %s", s1);
244                         break;
245
246                 case 1:         /* secsize */
247                         if (getnum(s1, &j))
248                                 errx(EX_USAGE,
249                                      "bad numeric value for secsize: %s", s1);
250                         if (j == 128) out->secsize = 0;
251                         else if (j == 256) out->secsize = 1;
252                         else if (j == 512) out->secsize = 2;
253                         else if (j == 1024) out->secsize = 3;
254                         else
255                                 errx(EX_USAGE, "bad sector size %d", j);
256                         break;
257
258                 case 2:         /* datalen */
259                         if (getnum(s1, &j))
260                                 errx(EX_USAGE,
261                                      "bad numeric value for datalen: %s", s1);
262                         if (j >= 256)
263                                 errx(EX_USAGE, "bad datalen %d", j);
264                         out->datalen = j;
265                         break;
266
267                 case 3:         /* gap */
268                         if (getnum(s1, &out->gap))
269                                 errx(EX_USAGE,
270                                      "bad numeric value for gap: %s", s1);
271                         break;
272
273                 case 4:         /* ncyls */
274                         if (getnum(s1, &j))
275                                 errx(EX_USAGE,
276                                      "bad numeric value for ncyls: %s", s1);
277                         if (j > 85)
278                                 errx(EX_USAGE, "bad # of cylinders %d", j);
279                         out->tracks = j;
280                         break;
281
282                 case 5:         /* speed */
283                         if (getnum(s1, &j))
284                                 errx(EX_USAGE,
285                                      "bad numeric value for speed: %s", s1);
286                         switch (type) {
287                         default:
288                                 abort(); /* paranoia */
289
290                         case FDT_360K:
291                         case FDT_720K:
292                                 if (j == 250)
293                                         out->trans = FDC_250KBPS;
294                                 else
295                                         errx(EX_USAGE, "bad speed %d", j);
296                                 break;
297
298                         case FDT_12M:
299                                 if (j == 300)
300                                         out->trans = FDC_300KBPS;
301                                 else if (j == 250)
302                                         out->trans = FDC_250KBPS;
303                                 else if (j == 500)
304                                         out->trans = FDC_500KBPS;
305                                 else
306                                         errx(EX_USAGE, "bad speed %d", j);
307                                 break;
308
309                         case FDT_288M:
310                                 if (j == 1000)
311                                         out->trans = FDC_1MBPS;
312                                 /* FALLTHROUGH */
313                         case FDT_144M:
314                                 if (j == 250)
315                                         out->trans = FDC_250KBPS;
316                                 else if (j == 500)
317                                         out->trans = FDC_500KBPS;
318                                 else
319                                         errx(EX_USAGE, "bad speed %d", j);
320                                 break;
321                         }
322                         break;
323
324                 case 6:         /* heads */
325                         if (getnum(s1, &j))
326                                 errx(EX_USAGE,
327                                      "bad numeric value for heads: %s", s1);
328                         if (j == 1 || j == 2)
329                                 out->heads = j;
330                         else
331                                 errx(EX_USAGE, "bad # of heads %d", j);
332                         break;
333
334                 case 7:         /* f_gap */
335                         if (getnum(s1, &out->f_gap))
336                                 errx(EX_USAGE,
337                                      "bad numeric value for f_gap: %s", s1);
338                         break;
339
340                 case 8:         /* f_inter */
341                         if (getnum(s1, &out->f_inter))
342                                 errx(EX_USAGE,
343                                      "bad numeric value for f_inter: %s", s1);
344                         break;
345
346                 case 9:         /* offs2 */
347                         if (getnum(s1, &out->offset_side2))
348                                 errx(EX_USAGE,
349                                      "bad numeric value for offs2: %s", s1);
350                         break;
351
352                 default:
353                         if (strcmp(s1, "+mfm") == 0)
354                                 out->flags |= FL_MFM;
355                         else if (strcmp(s1, "-mfm") == 0)
356                                 out->flags &= ~FL_MFM;
357                         else if (strcmp(s1, "+auto") == 0)
358                                 out->flags |= FL_AUTO;
359                         else if (strcmp(s1, "-auto") == 0)
360                                 out->flags &= ~FL_AUTO;
361                         else if (strcmp(s1, "+2step") == 0)
362                                 out->flags |= FL_2STEP;
363                         else if (strcmp(s1, "-2step") == 0)
364                                 out->flags &= ~FL_2STEP;
365                         else if (strcmp(s1, "+perpnd") == 0)
366                                 out->flags |= FL_PERPND;
367                         else if (strcmp(s1, "-perpnd") == 0)
368                                 out->flags &= ~FL_PERPND;
369                         else
370                                 errx(EX_USAGE, "bad flag: %s", s1);
371                         break;
372                 }
373                 free(s1);
374         }
375
376         out->size = out->tracks * out->heads * out->sectrac;
377 }
378
379 /*
380  * Print a textual translation of the drive (density) type described
381  * by `in' to stdout.  The string uses the same form that is parseable
382  * by parse_fmt().
383  */
384 void
385 print_fmt(struct fd_type in)
386 {
387         int secsize, speed;
388
389         secsize = 128 << in.secsize;
390         switch (in.trans) {
391         case FDC_250KBPS:       speed = 250; break;
392         case FDC_300KBPS:       speed = 300; break;
393         case FDC_500KBPS:       speed = 500; break;
394         case FDC_1MBPS:         speed = 1000; break;
395         default:                speed = 1; break;
396         }
397
398         printf("%d,%d,%#x,%#x,%d,%d,%d,%#x,%d,%d",
399                in.sectrac, secsize, in.datalen, in.gap, in.tracks,
400                speed, in.heads, in.f_gap, in.f_inter, in.offset_side2);
401         if (in.flags & FL_MFM)
402                 printf(",+mfm");
403         if (in.flags & FL_2STEP)
404                 printf(",+2step");
405         if (in.flags & FL_PERPND)
406                 printf(",+perpnd");
407         if (in.flags & FL_AUTO)
408                 printf(",+auto");
409         putc('\n', stdout);
410 }
411
412 /*
413  * Based on `size' (in kilobytes), walk through the table of known
414  * densities for drive type `type' and see if we can find one.  If
415  * found, return it (as a pointer to static storage), otherwise return
416  * NULL.
417  */
418 struct fd_type *
419 get_fmt(int size, enum fd_drivetype type)
420 {
421         int i, n;
422         struct fd_type *fdtp;
423
424         switch (type) {
425         default:
426                 return (0);
427
428         case FDT_360K:
429                 fdtp = fd_types_360k;
430                 n = sizeof fd_types_360k / sizeof(struct fd_type);
431                 break;
432
433         case FDT_720K:
434                 fdtp = fd_types_720k;
435                 n = sizeof fd_types_720k / sizeof(struct fd_type);
436                 break;
437
438         case FDT_12M:
439                 fdtp = fd_types_12m;
440                 n = sizeof fd_types_12m / sizeof(struct fd_type);
441                 break;
442
443         case FDT_144M:
444                 fdtp = fd_types_144m;
445                 n = sizeof fd_types_144m / sizeof(struct fd_type);
446                 break;
447
448         case FDT_288M:
449                 fdtp = fd_types_288m;
450                 n = sizeof fd_types_288m / sizeof(struct fd_type);
451                 break;
452         }
453
454         if (size == -1)
455                 return fd_types_auto;
456
457         for (i = 0; i < n; i++, fdtp++) {
458                 fdtp->size = fdtp->sectrac * fdtp->heads * fdtp->tracks;
459                 if (((128 << fdtp->secsize) * fdtp->size / 1024) == size)
460                         return (fdtp);
461         }
462         return (0);
463 }
464
465 /*
466  * Parse a number from `s'.  If the string cannot be converted into a
467  * number completely, return -1, otherwise 0.  The result is returned
468  * in `*res'.
469  */
470 int
471 getnum(const char *s, int *res)
472 {
473         unsigned long ul;
474         char *cp;
475
476         ul = strtoul(s, &cp, 0);
477         if (*cp != '\0')
478           return (-1);
479
480         *res = (int)ul;
481         return (0);
482 }
483
484 /*
485  * Return a short name and a verbose description for the drive
486  * described by `t'.
487  */
488 void
489 getname(enum fd_drivetype t, const char **name, const char **descr)
490 {
491
492         switch (t) {
493         default:
494                 *name = "unknown";
495                 *descr = "unknown drive type";
496                 break;
497
498         case FDT_360K:
499                 *name = "360K";
500                 *descr = "5.25\" double-density";
501                 break;
502
503         case FDT_12M:
504                 *name = "1.2M";
505                 *descr = "5.25\" high-density";
506                 break;
507
508         case FDT_720K:
509                 *name = "720K";
510                 *descr = "3.5\" double-density";
511                 break;
512
513         case FDT_144M:
514                 *name = "1.44M";
515                 *descr = "3.5\" high-density";
516                 break;
517
518         case FDT_288M:
519                 *name = "2.88M";
520                 *descr = "3.5\" extra-density";
521                 break;
522         }
523 }