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