]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/fdread/fdutil.c
MFV r315791: ntp 4.2.8p10.
[FreeBSD/FreeBSD.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         { FDF_3_1722 },
110         { FDF_3_1476 },
111         { FDF_3_1440 },
112         { FDF_3_1200 },
113         { FDF_3_820 },
114         { FDF_3_800 },
115         { FDF_3_720 },
116         { 0,0,0,0,0,0,0,0,0,0,0,0 }
117 };
118
119 static struct fd_type fd_types_12m[] = {
120         { FDF_5_1200 },
121         { FDF_5_1230 },
122         { FDF_5_1480 },
123         { FDF_5_1440 },
124         { FDF_5_820 },
125         { FDF_5_800 },
126         { FDF_5_720 },
127         { FDF_5_360 | FL_2STEP },
128         { FDF_5_640 },
129         { 0,0,0,0,0,0,0,0,0,0,0,0 }
130 };
131
132 static struct fd_type fd_types_720k[] =
133 {
134         { FDF_3_720 },
135         { 0,0,0,0,0,0,0,0,0,0,0,0 }
136 };
137
138 static struct fd_type fd_types_360k[] =
139 {
140         { FDF_5_360 },
141         { 0,0,0,0,0,0,0,0,0,0,0,0 }
142 };
143
144
145 /*
146  * Parse a format string, and fill in the parameter pointed to by `out'.
147  *
148  * sectrac,secsize,datalen,gap,ncyls,speed,heads,f_gap,f_inter,offs2,flags[...]
149  *
150  * sectrac = sectors per track
151  * secsize = sector size in bytes
152  * datalen = length of sector if secsize == 128
153  * gap     = gap length when reading
154  * ncyls   = number of cylinders
155  * speed   = transfer speed 250/300/500/1000 KB/s
156  * heads   = number of heads
157  * f_gap   = gap length when formatting
158  * f_inter = sector interleave when formatting
159  * offs2   = offset of sectors on side 2
160  * flags   = +/-mfm | +/-2step | +/-perpend
161  *             mfm - use MFM recording
162  *             2step - use 2 steps between cylinders
163  *             perpend - user perpendicular (vertical) recording
164  *
165  * Any omitted value will be passed on from parameter `in'.
166  */
167 void
168 parse_fmt(const char *s, enum fd_drivetype type,
169           struct fd_type in, struct fd_type *out)
170 {
171         int i, j;
172         const char *cp;
173         char *s1;
174
175         *out = in;
176
177         for (i = 0;; i++) {
178                 if (s == NULL)
179                         break;
180
181                 if ((cp = strchr(s, ',')) == NULL) {
182                         s1 = strdup(s);
183                         if (s1 == NULL)
184                                 abort();
185                         s = 0;
186                 } else {
187                         s1 = malloc(cp - s + 1);
188                         if (s1 == NULL)
189                                 abort();
190                         memcpy(s1, s, cp - s);
191                         s1[cp - s] = 0;
192
193                         s = cp + 1;
194                 }
195                 if (strlen(s1) == 0) {
196                         free(s1);
197                         continue;
198                 }
199
200                 switch (i) {
201                 case 0:         /* sectrac */
202                         if (getnum(s1, &out->sectrac))
203                                 errx(EX_USAGE,
204                                      "bad numeric value for sectrac: %s", s1);
205                         break;
206
207                 case 1:         /* secsize */
208                         if (getnum(s1, &j))
209                                 errx(EX_USAGE,
210                                      "bad numeric value for secsize: %s", s1);
211                         if (j == 128) out->secsize = 0;
212                         else if (j == 256) out->secsize = 1;
213                         else if (j == 512) out->secsize = 2;
214                         else if (j == 1024) out->secsize = 3;
215                         else
216                                 errx(EX_USAGE, "bad sector size %d", j);
217                         break;
218
219                 case 2:         /* datalen */
220                         if (getnum(s1, &j))
221                                 errx(EX_USAGE,
222                                      "bad numeric value for datalen: %s", s1);
223                         if (j >= 256)
224                                 errx(EX_USAGE, "bad datalen %d", j);
225                         out->datalen = j;
226                         break;
227
228                 case 3:         /* gap */
229                         if (getnum(s1, &out->gap))
230                                 errx(EX_USAGE,
231                                      "bad numeric value for gap: %s", s1);
232                         break;
233
234                 case 4:         /* ncyls */
235                         if (getnum(s1, &j))
236                                 errx(EX_USAGE,
237                                      "bad numeric value for ncyls: %s", s1);
238                         if (j > 85)
239                                 errx(EX_USAGE, "bad # of cylinders %d", j);
240                         out->tracks = j;
241                         break;
242
243                 case 5:         /* speed */
244                         if (getnum(s1, &j))
245                                 errx(EX_USAGE,
246                                      "bad numeric value for speed: %s", s1);
247                         switch (type) {
248                         default:
249                                 abort(); /* paranoia */
250
251                         case FDT_360K:
252                         case FDT_720K:
253                                 if (j == 250)
254                                         out->trans = FDC_250KBPS;
255                                 else
256                                         errx(EX_USAGE, "bad speed %d", j);
257                                 break;
258
259                         case FDT_12M:
260                                 if (j == 300)
261                                         out->trans = FDC_300KBPS;
262                                 else if (j == 250)
263                                         out->trans = FDC_250KBPS;
264                                 else if (j == 500)
265                                         out->trans = FDC_500KBPS;
266                                 else
267                                         errx(EX_USAGE, "bad speed %d", j);
268                                 break;
269
270                         case FDT_288M:
271                                 if (j == 1000)
272                                         out->trans = FDC_1MBPS;
273                                 /* FALLTHROUGH */
274                         case FDT_144M:
275                                 if (j == 250)
276                                         out->trans = FDC_250KBPS;
277                                 else if (j == 500)
278                                         out->trans = FDC_500KBPS;
279                                 else
280                                         errx(EX_USAGE, "bad speed %d", j);
281                                 break;
282                         }
283                         break;
284
285                 case 6:         /* heads */
286                         if (getnum(s1, &j))
287                                 errx(EX_USAGE,
288                                      "bad numeric value for heads: %s", s1);
289                         if (j == 1 || j == 2)
290                                 out->heads = j;
291                         else
292                                 errx(EX_USAGE, "bad # of heads %d", j);
293                         break;
294
295                 case 7:         /* f_gap */
296                         if (getnum(s1, &out->f_gap))
297                                 errx(EX_USAGE,
298                                      "bad numeric value for f_gap: %s", s1);
299                         break;
300
301                 case 8:         /* f_inter */
302                         if (getnum(s1, &out->f_inter))
303                                 errx(EX_USAGE,
304                                      "bad numeric value for f_inter: %s", s1);
305                         break;
306
307                 case 9:         /* offs2 */
308                         if (getnum(s1, &out->offset_side2))
309                                 errx(EX_USAGE,
310                                      "bad numeric value for offs2: %s", s1);
311                         break;
312
313                 default:
314                         if (strcmp(s1, "+mfm") == 0)
315                                 out->flags |= FL_MFM;
316                         else if (strcmp(s1, "-mfm") == 0)
317                                 out->flags &= ~FL_MFM;
318                         else if (strcmp(s1, "+auto") == 0)
319                                 out->flags |= FL_AUTO;
320                         else if (strcmp(s1, "-auto") == 0)
321                                 out->flags &= ~FL_AUTO;
322                         else if (strcmp(s1, "+2step") == 0)
323                                 out->flags |= FL_2STEP;
324                         else if (strcmp(s1, "-2step") == 0)
325                                 out->flags &= ~FL_2STEP;
326                         else if (strcmp(s1, "+perpnd") == 0)
327                                 out->flags |= FL_PERPND;
328                         else if (strcmp(s1, "-perpnd") == 0)
329                                 out->flags &= ~FL_PERPND;
330                         else
331                                 errx(EX_USAGE, "bad flag: %s", s1);
332                         break;
333                 }
334                 free(s1);
335         }
336
337         out->size = out->tracks * out->heads * out->sectrac;
338 }
339
340 /*
341  * Print a textual translation of the drive (density) type described
342  * by `in' to stdout.  The string uses the same form that is parseable
343  * by parse_fmt().
344  */
345 void
346 print_fmt(struct fd_type in)
347 {
348         int secsize, speed;
349
350         secsize = 128 << in.secsize;
351         switch (in.trans) {
352         case FDC_250KBPS:       speed = 250; break;
353         case FDC_300KBPS:       speed = 300; break;
354         case FDC_500KBPS:       speed = 500; break;
355         case FDC_1MBPS:         speed = 1000; break;
356         default:                speed = 1; break;
357         }
358
359         printf("%d,%d,%#x,%#x,%d,%d,%d,%#x,%d,%d",
360                in.sectrac, secsize, in.datalen, in.gap, in.tracks,
361                speed, in.heads, in.f_gap, in.f_inter, in.offset_side2);
362         if (in.flags & FL_MFM)
363                 printf(",+mfm");
364         if (in.flags & FL_2STEP)
365                 printf(",+2step");
366         if (in.flags & FL_PERPND)
367                 printf(",+perpnd");
368         if (in.flags & FL_AUTO)
369                 printf(",+auto");
370         putc('\n', stdout);
371 }
372
373 /*
374  * Based on `size' (in kilobytes), walk through the table of known
375  * densities for drive type `type' and see if we can find one.  If
376  * found, return it (as a pointer to static storage), otherwise return
377  * NULL.
378  */
379 struct fd_type *
380 get_fmt(int size, enum fd_drivetype type)
381 {
382         int i, n;
383         struct fd_type *fdtp;
384
385         switch (type) {
386         default:
387                 return (0);
388
389         case FDT_360K:
390                 fdtp = fd_types_360k;
391                 n = sizeof fd_types_360k / sizeof(struct fd_type);
392                 break;
393
394         case FDT_720K:
395                 fdtp = fd_types_720k;
396                 n = sizeof fd_types_720k / sizeof(struct fd_type);
397                 break;
398
399         case FDT_12M:
400                 fdtp = fd_types_12m;
401                 n = sizeof fd_types_12m / sizeof(struct fd_type);
402                 break;
403
404         case FDT_144M:
405                 fdtp = fd_types_144m;
406                 n = sizeof fd_types_144m / sizeof(struct fd_type);
407                 break;
408
409         case FDT_288M:
410                 fdtp = fd_types_288m;
411                 n = sizeof fd_types_288m / sizeof(struct fd_type);
412                 break;
413         }
414
415         if (size == -1)
416                 return fd_types_auto;
417
418         for (i = 0; i < n; i++, fdtp++) {
419                 fdtp->size = fdtp->sectrac * fdtp->heads * fdtp->tracks;
420                 if (((128 << fdtp->secsize) * fdtp->size / 1024) == size)
421                         return (fdtp);
422         }
423         return (0);
424 }
425
426 /*
427  * Parse a number from `s'.  If the string cannot be converted into a
428  * number completely, return -1, otherwise 0.  The result is returned
429  * in `*res'.
430  */
431 int
432 getnum(const char *s, int *res)
433 {
434         unsigned long ul;
435         char *cp;
436
437         ul = strtoul(s, &cp, 0);
438         if (*cp != '\0')
439           return (-1);
440
441         *res = (int)ul;
442         return (0);
443 }
444
445 /*
446  * Return a short name and a verbose description for the drive
447  * described by `t'.
448  */
449 void
450 getname(enum fd_drivetype t, const char **name, const char **descr)
451 {
452
453         switch (t) {
454         default:
455                 *name = "unknown";
456                 *descr = "unknown drive type";
457                 break;
458
459         case FDT_360K:
460                 *name = "360K";
461                 *descr = "5.25\" double-density";
462                 break;
463
464         case FDT_12M:
465                 *name = "1.2M";
466                 *descr = "5.25\" high-density";
467                 break;
468
469         case FDT_720K:
470                 *name = "720K";
471                 *descr = "3.5\" double-density";
472                 break;
473
474         case FDT_144M:
475                 *name = "1.44M";
476                 *descr = "3.5\" high-density";
477                 break;
478
479         case FDT_288M:
480                 *name = "2.88M";
481                 *descr = "3.5\" extra-density";
482                 break;
483         }
484 }