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 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 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 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 * 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 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 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