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