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