fdutil.c revision 134081
179110Sjoerg/* 279110Sjoerg * Copyright (c) 2001 Joerg Wunsch 379110Sjoerg * 479110Sjoerg * All rights reserved. 579110Sjoerg * 679110Sjoerg * Redistribution and use in source and binary forms, with or without 779110Sjoerg * modification, are permitted provided that the following conditions 879110Sjoerg * are met: 979110Sjoerg * 1. Redistributions of source code must retain the above copyright 1079110Sjoerg * notice, this list of conditions and the following disclaimer. 1179110Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1279110Sjoerg * notice, this list of conditions and the following disclaimer in the 1379110Sjoerg * documentation and/or other materials provided with the distribution. 1479110Sjoerg * 1579110Sjoerg * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR 1679110Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1779110Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1879110Sjoerg * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT, 1979110Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2079110Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2179110Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2279110Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2379110Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2479110Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2579110Sjoerg * 2679110Sjoerg * $FreeBSD: head/usr.sbin/fdread/fdutil.c 134081 2004-08-20 15:14:25Z phk $ 2779110Sjoerg */ 2879110Sjoerg 2987992Sjoerg#include <dev/ic/nec765.h> 3087992Sjoerg 3179110Sjoerg#include <sys/fdcio.h> 3279110Sjoerg 3387992Sjoerg#include <err.h> 3479110Sjoerg#include <stdio.h> 3587992Sjoerg#include <stdlib.h> 3679110Sjoerg#include <string.h> 3787992Sjoerg#include <sysexits.h> 3879110Sjoerg 3979110Sjoerg#include "fdutil.h" 4079110Sjoerg 4187992Sjoerg/* 4287992Sjoerg * Decode the FDC status pointed to by `fdcsp', and print a textual 4387992Sjoerg * translation to stderr. If `terse' is false, the numerical FDC 4487992Sjoerg * register status is printed, too. 4587992Sjoerg */ 4679110Sjoergvoid 4779110Sjoergprintstatus(struct fdc_status *fdcsp, int terse) 4879110Sjoerg{ 4979110Sjoerg char msgbuf[100]; 5079110Sjoerg 5179110Sjoerg if (!terse) 5279110Sjoerg fprintf(stderr, 5379110Sjoerg "\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n", 5479110Sjoerg fdcsp->status[0] & 0xff, 5579110Sjoerg fdcsp->status[1] & 0xff, 5679110Sjoerg fdcsp->status[2] & 0xff, 5779110Sjoerg fdcsp->status[3] & 0xff, 5879110Sjoerg fdcsp->status[4] & 0xff, 5979110Sjoerg fdcsp->status[5] & 0xff, 6079110Sjoerg fdcsp->status[6] & 0xff); 6179110Sjoerg 62134081Sphk if ((fdcsp->status[0] & NE7_ST0_IC_RC) == 0) { 63134081Sphk sprintf(msgbuf, "timeout"); 64134081Sphk } else if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) { 6579110Sjoerg sprintf(msgbuf, "unexcpted interrupt code %#x", 6679110Sjoerg fdcsp->status[0] & NE7_ST0_IC_RC); 6779110Sjoerg } else { 6879110Sjoerg strcpy(msgbuf, "unexpected error code in ST1/ST2"); 6979110Sjoerg 7079110Sjoerg if (fdcsp->status[1] & NE7_ST1_EN) 7179110Sjoerg strcpy(msgbuf, "end of cylinder (wrong format)"); 7279110Sjoerg else if (fdcsp->status[1] & NE7_ST1_DE) { 7379110Sjoerg if (fdcsp->status[2] & NE7_ST2_DD) 7479110Sjoerg strcpy(msgbuf, "CRC error in data field"); 7579110Sjoerg else 7679110Sjoerg strcpy(msgbuf, "CRC error in ID field"); 7779110Sjoerg } else if (fdcsp->status[1] & NE7_ST1_MA) { 7879110Sjoerg if (fdcsp->status[2] & NE7_ST2_MD) 7979110Sjoerg strcpy(msgbuf, "no address mark in data field"); 8079110Sjoerg else 8179110Sjoerg strcpy(msgbuf, "no address mark in ID field"); 8279110Sjoerg } else if (fdcsp->status[2] & NE7_ST2_WC) 8379110Sjoerg strcpy(msgbuf, "wrong cylinder (format mismatch)"); 8479110Sjoerg else if (fdcsp->status[1] & NE7_ST1_ND) 8579110Sjoerg strcpy(msgbuf, "no data (sector not found)"); 8679110Sjoerg } 8779110Sjoerg fputs(msgbuf, stderr); 8879110Sjoerg} 8979110Sjoerg 90134081Sphkstatic struct fd_type fd_types_auto[1] = 91134081Sphk { { 0,0,0,0,0,0,0,0,0,0,0,FL_AUTO } }; 92126230Sphk 93127522Snyan 94134081Sphkstatic struct fd_type fd_types_288m[] = { 95127522Snyan#if 0 96134081Sphk { FDF_3_2880 }, 97127522Snyan#endif 98134081Sphk { FDF_3_1722 }, 99134081Sphk { FDF_3_1476 }, 100134081Sphk { FDF_3_1440 }, 101134081Sphk { FDF_3_1200 }, 102134081Sphk { FDF_3_820 }, 103134081Sphk { FDF_3_800 }, 104134081Sphk { FDF_3_720 }, 105134081Sphk { 0 } 106127522Snyan}; 107127522Snyan 108127522Snyanstatic struct fd_type fd_types_144m[] = { 109134081Sphk { FDF_3_1722 }, 110134081Sphk { FDF_3_1476 }, 111134081Sphk { FDF_3_1440 }, 112134081Sphk { FDF_3_1200 }, 113134081Sphk { FDF_3_820 }, 114134081Sphk { FDF_3_800 }, 115134081Sphk { FDF_3_720 }, 116134081Sphk { 0 } 117127522Snyan}; 118127522Snyan 119134081Sphkstatic struct fd_type fd_types_12m[] = { 120134081Sphk { FDF_5_1200 }, 121134081Sphk { FDF_5_1230 }, 122134081Sphk { FDF_5_1480 }, 123134081Sphk { FDF_5_1440 }, 124134081Sphk { FDF_5_820 }, 125134081Sphk { FDF_5_800 }, 126134081Sphk { FDF_5_720 }, 127134081Sphk { FDF_5_360 | FL_2STEP }, 128134081Sphk { FDF_5_640 }, 129134081Sphk { 0 } 13087992Sjoerg}; 13187992Sjoerg 13287992Sjoergstatic struct fd_type fd_types_720k[] = 13387992Sjoerg{ 134134081Sphk { FDF_3_720 }, 135134081Sphk { 0 } 13687992Sjoerg}; 13787992Sjoerg 13887992Sjoergstatic struct fd_type fd_types_360k[] = 13987992Sjoerg{ 140134081Sphk { FDF_5_360 }, 141134081Sphk { 0 } 14287992Sjoerg}; 14387992Sjoerg 144127522Snyan 14587992Sjoerg/* 14687992Sjoerg * Parse a format string, and fill in the parameter pointed to by `out'. 14787992Sjoerg * 14887992Sjoerg * sectrac,secsize,datalen,gap,ncyls,speed,heads,f_gap,f_inter,offs2,flags[...] 14987992Sjoerg * 15087992Sjoerg * sectrac = sectors per track 15187992Sjoerg * secsize = sector size in bytes 15287992Sjoerg * datalen = length of sector if secsize == 128 15387992Sjoerg * gap = gap length when reading 15487992Sjoerg * ncyls = number of cylinders 15587992Sjoerg * speed = transfer speed 250/300/500/1000 KB/s 15687992Sjoerg * heads = number of heads 15787992Sjoerg * f_gap = gap length when formatting 15887992Sjoerg * f_inter = sector interleave when formatting 15987992Sjoerg * offs2 = offset of sectors on side 2 16087992Sjoerg * flags = +/-mfm | +/-2step | +/-perpend 16187992Sjoerg * mfm - use MFM recording 16287992Sjoerg * 2step - use 2 steps between cylinders 16387992Sjoerg * perpend - user perpendicular (vertical) recording 16487992Sjoerg * 16587992Sjoerg * Any omitted value will be passed on from parameter `in'. 16687992Sjoerg */ 16787992Sjoergvoid 16887992Sjoergparse_fmt(const char *s, enum fd_drivetype type, 16987992Sjoerg struct fd_type in, struct fd_type *out) 17087992Sjoerg{ 17187992Sjoerg int i, j; 17287992Sjoerg const char *cp; 17387992Sjoerg char *s1; 17487992Sjoerg 17587992Sjoerg *out = in; 17687992Sjoerg 17787992Sjoerg for (i = 0;; i++) { 17887992Sjoerg if (s == 0) 17987992Sjoerg break; 18087992Sjoerg 18187992Sjoerg if ((cp = strchr(s, ',')) == 0) { 18287992Sjoerg s1 = strdup(s); 18387992Sjoerg if (s1 == NULL) 18487992Sjoerg abort(); 18587992Sjoerg s = 0; 18687992Sjoerg } else { 18787992Sjoerg s1 = malloc(cp - s + 1); 18887992Sjoerg if (s1 == NULL) 18987992Sjoerg abort(); 19087992Sjoerg memcpy(s1, s, cp - s); 19187992Sjoerg s1[cp - s] = 0; 19287992Sjoerg 19387992Sjoerg s = cp + 1; 19487992Sjoerg } 19587992Sjoerg if (strlen(s1) == 0) { 19687992Sjoerg free(s1); 19787992Sjoerg continue; 19887992Sjoerg } 19987992Sjoerg 20087992Sjoerg switch (i) { 20187992Sjoerg case 0: /* sectrac */ 20287992Sjoerg if (getnum(s1, &out->sectrac)) 20387992Sjoerg errx(EX_USAGE, 20487992Sjoerg "bad numeric value for sectrac: %s", s1); 20587992Sjoerg break; 20687992Sjoerg 20787992Sjoerg case 1: /* secsize */ 20887992Sjoerg if (getnum(s1, &j)) 20987992Sjoerg errx(EX_USAGE, 21087992Sjoerg "bad numeric value for secsize: %s", s1); 21187992Sjoerg if (j == 128) out->secsize = 0; 21287992Sjoerg else if (j == 256) out->secsize = 1; 21387992Sjoerg else if (j == 512) out->secsize = 2; 21487992Sjoerg else if (j == 1024) out->secsize = 3; 21587992Sjoerg else 21687992Sjoerg errx(EX_USAGE, "bad sector size %d", j); 21787992Sjoerg break; 21887992Sjoerg 21987992Sjoerg case 2: /* datalen */ 22087992Sjoerg if (getnum(s1, &j)) 22187992Sjoerg errx(EX_USAGE, 22287992Sjoerg "bad numeric value for datalen: %s", s1); 22387992Sjoerg if (j >= 256) 22487992Sjoerg errx(EX_USAGE, "bad datalen %d", j); 22587992Sjoerg out->datalen = j; 22687992Sjoerg break; 22787992Sjoerg 22887992Sjoerg case 3: /* gap */ 22987992Sjoerg if (getnum(s1, &out->gap)) 23087992Sjoerg errx(EX_USAGE, 23187992Sjoerg "bad numeric value for gap: %s", s1); 23287992Sjoerg break; 23387992Sjoerg 23487992Sjoerg case 4: /* ncyls */ 23587992Sjoerg if (getnum(s1, &j)) 23687992Sjoerg errx(EX_USAGE, 23787992Sjoerg "bad numeric value for ncyls: %s", s1); 23887992Sjoerg if (j > 85) 23987992Sjoerg errx(EX_USAGE, "bad # of cylinders %d", j); 24087992Sjoerg out->tracks = j; 24187992Sjoerg break; 24287992Sjoerg 24387992Sjoerg case 5: /* speed */ 24487992Sjoerg if (getnum(s1, &j)) 24587992Sjoerg errx(EX_USAGE, 24687992Sjoerg "bad numeric value for speed: %s", s1); 24787992Sjoerg switch (type) { 24887992Sjoerg default: 24987992Sjoerg abort(); /* paranoia */ 25087992Sjoerg 25187992Sjoerg case FDT_360K: 25287992Sjoerg case FDT_720K: 25387992Sjoerg if (j == 250) 25487992Sjoerg out->trans = FDC_250KBPS; 255127522Snyan else 25687992Sjoerg errx(EX_USAGE, "bad speed %d", j); 25787992Sjoerg break; 25887992Sjoerg 25987992Sjoerg case FDT_12M: 26087992Sjoerg if (j == 300) 26187992Sjoerg out->trans = FDC_300KBPS; 262134081Sphk else if (j == 250) 263134081Sphk out->trans = FDC_250KBPS; 26487992Sjoerg else if (j == 500) 26587992Sjoerg out->trans = FDC_500KBPS; 26687992Sjoerg else 267127522Snyan errx(EX_USAGE, "bad speed %d", j); 26887992Sjoerg break; 26987992Sjoerg 27087992Sjoerg case FDT_288M: 27187992Sjoerg if (j == 1000) 27287992Sjoerg out->trans = FDC_1MBPS; 27387992Sjoerg /* FALLTHROUGH */ 27487992Sjoerg case FDT_144M: 27587992Sjoerg if (j == 250) 27687992Sjoerg out->trans = FDC_250KBPS; 27787992Sjoerg else if (j == 500) 27887992Sjoerg out->trans = FDC_500KBPS; 27987992Sjoerg else 280127522Snyan errx(EX_USAGE, "bad speed %d", j); 28187992Sjoerg break; 28287992Sjoerg } 28387992Sjoerg break; 28487992Sjoerg 28587992Sjoerg case 6: /* heads */ 28687992Sjoerg if (getnum(s1, &j)) 28787992Sjoerg errx(EX_USAGE, 28887992Sjoerg "bad numeric value for heads: %s", s1); 28987992Sjoerg if (j == 1 || j == 2) 29087992Sjoerg out->heads = j; 29187992Sjoerg else 29287992Sjoerg errx(EX_USAGE, "bad # of heads %d", j); 29387992Sjoerg break; 29487992Sjoerg 29587992Sjoerg case 7: /* f_gap */ 29687992Sjoerg if (getnum(s1, &out->f_gap)) 29787992Sjoerg errx(EX_USAGE, 29887992Sjoerg "bad numeric value for f_gap: %s", s1); 29987992Sjoerg break; 30087992Sjoerg 30187992Sjoerg case 8: /* f_inter */ 30287992Sjoerg if (getnum(s1, &out->f_inter)) 30387992Sjoerg errx(EX_USAGE, 30487992Sjoerg "bad numeric value for f_inter: %s", s1); 30587992Sjoerg break; 30687992Sjoerg 30787992Sjoerg case 9: /* offs2 */ 30887992Sjoerg if (getnum(s1, &out->offset_side2)) 30987992Sjoerg errx(EX_USAGE, 31087992Sjoerg "bad numeric value for offs2: %s", s1); 31187992Sjoerg break; 31287992Sjoerg 31387992Sjoerg default: 31487992Sjoerg if (strcmp(s1, "+mfm") == 0) 31587992Sjoerg out->flags |= FL_MFM; 31687992Sjoerg else if (strcmp(s1, "-mfm") == 0) 31787992Sjoerg out->flags &= ~FL_MFM; 318134081Sphk else if (strcmp(s1, "+auto") == 0) 319134081Sphk out->flags |= FL_AUTO; 320134081Sphk else if (strcmp(s1, "-auto") == 0) 321134081Sphk out->flags &= ~FL_AUTO; 32287992Sjoerg else if (strcmp(s1, "+2step") == 0) 32387992Sjoerg out->flags |= FL_2STEP; 32487992Sjoerg else if (strcmp(s1, "-2step") == 0) 32587992Sjoerg out->flags &= ~FL_2STEP; 32687992Sjoerg else if (strcmp(s1, "+perpnd") == 0) 32787992Sjoerg out->flags |= FL_PERPND; 32887992Sjoerg else if (strcmp(s1, "-perpnd") == 0) 32987992Sjoerg out->flags &= ~FL_PERPND; 33087992Sjoerg else 33187992Sjoerg errx(EX_USAGE, "bad flag: %s", s1); 33287992Sjoerg break; 33387992Sjoerg } 33487992Sjoerg free(s1); 33587992Sjoerg } 33687992Sjoerg 337126230Sphk out->size = out->tracks * out->heads * out->sectrac; 33887992Sjoerg} 33987992Sjoerg 34087992Sjoerg/* 34187992Sjoerg * Print a textual translation of the drive (density) type described 34287992Sjoerg * by `in' to stdout. The string uses the same form that is parseable 34387992Sjoerg * by parse_fmt(). 34487992Sjoerg */ 34587992Sjoergvoid 34687992Sjoergprint_fmt(struct fd_type in) 34787992Sjoerg{ 34887992Sjoerg int secsize, speed; 34987992Sjoerg 35087992Sjoerg secsize = 128 << in.secsize; 35187992Sjoerg switch (in.trans) { 35287992Sjoerg case FDC_250KBPS: speed = 250; break; 35387992Sjoerg case FDC_300KBPS: speed = 300; break; 35487992Sjoerg case FDC_500KBPS: speed = 500; break; 35587992Sjoerg case FDC_1MBPS: speed = 1000; break; 35687992Sjoerg default: speed = 1; break; 35787992Sjoerg } 35887992Sjoerg 35987992Sjoerg printf("%d,%d,%#x,%#x,%d,%d,%d,%#x,%d,%d", 36087992Sjoerg in.sectrac, secsize, in.datalen, in.gap, in.tracks, 36187992Sjoerg speed, in.heads, in.f_gap, in.f_inter, in.offset_side2); 36287992Sjoerg if (in.flags & FL_MFM) 36387992Sjoerg printf(",+mfm"); 36487992Sjoerg if (in.flags & FL_2STEP) 36587992Sjoerg printf(",+2step"); 36687992Sjoerg if (in.flags & FL_PERPND) 36787992Sjoerg printf(",+perpnd"); 368134081Sphk if (in.flags & FL_AUTO) 369134081Sphk printf(",+auto"); 37087992Sjoerg putc('\n', stdout); 37187992Sjoerg} 37287992Sjoerg 37387992Sjoerg/* 37487992Sjoerg * Based on `size' (in kilobytes), walk through the table of known 37587992Sjoerg * densities for drive type `type' and see if we can find one. If 37687992Sjoerg * found, return it (as a pointer to static storage), otherwise return 37787992Sjoerg * NULL. 37887992Sjoerg */ 37987992Sjoergstruct fd_type * 38087992Sjoergget_fmt(int size, enum fd_drivetype type) 38187992Sjoerg{ 38287992Sjoerg int i, n; 38387992Sjoerg struct fd_type *fdtp; 38487992Sjoerg 38587992Sjoerg switch (type) { 38687992Sjoerg default: 38787992Sjoerg return (0); 38887992Sjoerg 38987992Sjoerg case FDT_360K: 39087992Sjoerg fdtp = fd_types_360k; 39187992Sjoerg n = sizeof fd_types_360k / sizeof(struct fd_type); 39287992Sjoerg break; 39387992Sjoerg 39487992Sjoerg case FDT_720K: 39587992Sjoerg fdtp = fd_types_720k; 39687992Sjoerg n = sizeof fd_types_720k / sizeof(struct fd_type); 39787992Sjoerg break; 39887992Sjoerg 39987992Sjoerg case FDT_12M: 40087992Sjoerg fdtp = fd_types_12m; 40187992Sjoerg n = sizeof fd_types_12m / sizeof(struct fd_type); 40287992Sjoerg break; 40387992Sjoerg 40487992Sjoerg case FDT_144M: 40587992Sjoerg fdtp = fd_types_144m; 40687992Sjoerg n = sizeof fd_types_144m / sizeof(struct fd_type); 40787992Sjoerg break; 40887992Sjoerg 40987992Sjoerg case FDT_288M: 41087992Sjoerg fdtp = fd_types_288m; 41187992Sjoerg n = sizeof fd_types_288m / sizeof(struct fd_type); 41287992Sjoerg break; 41387992Sjoerg } 41487992Sjoerg 415126230Sphk if (size == -1) 416126230Sphk return fd_types_auto; 417126230Sphk 418134081Sphk for (i = 0; i < n; i++, fdtp++) { 419134081Sphk fdtp->size = fdtp->sectrac * fdtp->heads * fdtp->tracks; 420127522Snyan if (((128 << fdtp->secsize) * fdtp->size / 1024) == size) 421127522Snyan return (fdtp); 422134081Sphk } 42387992Sjoerg return (0); 42487992Sjoerg} 42587992Sjoerg 42687992Sjoerg/* 42787992Sjoerg * Parse a number from `s'. If the string cannot be converted into a 42887992Sjoerg * number completely, return -1, otherwise 0. The result is returned 42987992Sjoerg * in `*res'. 43087992Sjoerg */ 43187992Sjoergint 43287992Sjoerggetnum(const char *s, int *res) 43387992Sjoerg{ 43487992Sjoerg unsigned long ul; 43587992Sjoerg char *cp; 43687992Sjoerg 43787992Sjoerg ul = strtoul(s, &cp, 0); 43887992Sjoerg if (*cp != '\0') 43987992Sjoerg return (-1); 44087992Sjoerg 44187992Sjoerg *res = (int)ul; 44287992Sjoerg return (0); 44387992Sjoerg} 44487992Sjoerg 44587992Sjoerg/* 44687992Sjoerg * Return a short name and a verbose description for the drive 44787992Sjoerg * described by `t'. 44887992Sjoerg */ 44987992Sjoergvoid 45087992Sjoerggetname(enum fd_drivetype t, const char **name, const char **descr) 45187992Sjoerg{ 45287992Sjoerg 45387992Sjoerg switch (t) { 45487992Sjoerg default: 45587992Sjoerg *name = "unknown"; 45687992Sjoerg *descr = "unknown drive type"; 45787992Sjoerg break; 45887992Sjoerg 45987992Sjoerg case FDT_360K: 46087992Sjoerg *name = "360K"; 46187992Sjoerg *descr = "5.25\" double-density"; 46287992Sjoerg break; 46387992Sjoerg 46487992Sjoerg case FDT_12M: 46587992Sjoerg *name = "1.2M"; 46687992Sjoerg *descr = "5.25\" high-density"; 46787992Sjoerg break; 46887992Sjoerg 46987992Sjoerg case FDT_720K: 47087992Sjoerg *name = "720K"; 47187992Sjoerg *descr = "3.5\" double-density"; 47287992Sjoerg break; 47387992Sjoerg 47487992Sjoerg case FDT_144M: 47587992Sjoerg *name = "1.44M"; 47687992Sjoerg *descr = "3.5\" high-density"; 47787992Sjoerg break; 47887992Sjoerg 47987992Sjoerg case FDT_288M: 48087992Sjoerg *name = "2.88M"; 48187992Sjoerg *descr = "3.5\" extra-density"; 48287992Sjoerg break; 48387992Sjoerg } 48487992Sjoerg} 485