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 #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 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 == NULL) 204 break; 205 206 if ((cp = strchr(s, ',')) == NULL) { 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 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 * 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 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 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