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