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