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