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