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