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
printstatus(struct fdc_status * fdcsp,int terse)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
parse_fmt(const char * s,enum fd_drivetype type,struct fd_type in,struct fd_type * out)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
print_fmt(struct fd_type in)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 *
get_fmt(int size,enum fd_drivetype 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
getnum(const char * s,int * res)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
getname(enum fd_drivetype t,const char ** name,const char ** descr)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 }
487