1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
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
printstatus(struct fdc_status * fdcsp,int terse)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
parse_fmt(const char * s,enum fd_drivetype type,struct fd_type in,struct fd_type * out)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
print_fmt(struct fd_type in)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 *
get_fmt(int size,enum fd_drivetype 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
getnum(const char * s,int * res)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
getname(enum fd_drivetype t,const char ** name,const char ** descr)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 }
485