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