summaryrefslogtreecommitdiffstats
path: root/usr.sbin/fdread/fdutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/fdread/fdutil.c')
-rw-r--r--usr.sbin/fdread/fdutil.c392
1 files changed, 389 insertions, 3 deletions
diff --git a/usr.sbin/fdread/fdutil.c b/usr.sbin/fdread/fdutil.c
index fb61b30..9990790 100644
--- a/usr.sbin/fdread/fdutil.c
+++ b/usr.sbin/fdread/fdutil.c
@@ -26,16 +26,23 @@
* $FreeBSD$
*/
-#include <sys/types.h>
+#include <dev/ic/nec765.h>
+
#include <sys/fdcio.h>
+#include <err.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-
-#include <dev/ic/nec765.h>
+#include <sysexits.h>
#include "fdutil.h"
+/*
+ * Decode the FDC status pointed to by `fdcsp', and print a textual
+ * translation to stderr. If `terse' is false, the numerical FDC
+ * register status is printed, too.
+ */
void
printstatus(struct fdc_status *fdcsp, int terse)
{
@@ -78,3 +85,382 @@ printstatus(struct fdc_status *fdcsp, int terse)
fputs(msgbuf, stderr);
}
+static struct fd_type fd_types_288m[] =
+{
+#if 0
+{ 36,2,0xFF,0x1B,80,5760,FDC_1MBPS, 2,0x4C,1,1,FL_MFM|FL_PERPND } /*2.88M*/
+#endif
+{ 21,2,0xFF,0x04,82,3444,FDC_500KBPS,2,0x0C,2,0,FL_MFM }, /* 1.72M */
+{ 18,2,0xFF,0x1B,82,2952,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.48M */
+{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */
+{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
+{ 10,2,0xFF,0x10,82,1640,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
+{ 10,2,0xFF,0x10,80,1600,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
+{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+};
+
+static struct fd_type fd_types_144m[] =
+{
+{ 21,2,0xFF,0x04,82,3444,FDC_500KBPS,2,0x0C,2,0,FL_MFM }, /* 1.72M */
+{ 18,2,0xFF,0x1B,82,2952,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.48M */
+{ 18,2,0xFF,0x1B,80,2880,FDC_500KBPS,2,0x6C,1,0,FL_MFM }, /* 1.44M */
+{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
+{ 10,2,0xFF,0x10,82,1640,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
+{ 10,2,0xFF,0x10,80,1600,FDC_250KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
+{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+};
+
+static struct fd_type fd_types_12m[] =
+{
+{ 15,2,0xFF,0x1B,80,2400,FDC_500KBPS,2,0x54,1,0,FL_MFM }, /* 1.2M */
+{ 8,3,0xFF,0x35,77,1232,FDC_500KBPS,2,0x74,1,0,FL_MFM }, /* 1.23M */
+{ 18,2,0xFF,0x02,82,2952,FDC_500KBPS,2,0x02,2,0,FL_MFM }, /* 1.48M */
+{ 18,2,0xFF,0x02,80,2880,FDC_500KBPS,2,0x02,2,0,FL_MFM }, /* 1.44M */
+{ 10,2,0xFF,0x10,82,1640,FDC_300KBPS,2,0x2E,1,0,FL_MFM }, /* 820K */
+{ 10,2,0xFF,0x10,80,1600,FDC_300KBPS,2,0x2E,1,0,FL_MFM }, /* 800K */
+{ 9,2,0xFF,0x20,80,1440,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+{ 9,2,0xFF,0x23,40, 720,FDC_300KBPS,2,0x50,1,0,FL_MFM|FL_2STEP }, /* 360K */
+{ 8,2,0xFF,0x2A,80,1280,FDC_300KBPS,2,0x50,1,0,FL_MFM }, /* 640K */
+};
+
+static struct fd_type fd_types_720k[] =
+{
+{ 9,2,0xFF,0x20,80,1440,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 720K */
+};
+
+static struct fd_type fd_types_360k[] =
+{
+{ 9,2,0xFF,0x2A,40, 720,FDC_250KBPS,2,0x50,1,0,FL_MFM }, /* 360K */
+};
+
+/*
+ * Parse a format string, and fill in the parameter pointed to by `out'.
+ *
+ * sectrac,secsize,datalen,gap,ncyls,speed,heads,f_gap,f_inter,offs2,flags[...]
+ *
+ * sectrac = sectors per track
+ * secsize = sector size in bytes
+ * datalen = length of sector if secsize == 128
+ * gap = gap length when reading
+ * ncyls = number of cylinders
+ * speed = transfer speed 250/300/500/1000 KB/s
+ * heads = number of heads
+ * f_gap = gap length when formatting
+ * f_inter = sector interleave when formatting
+ * offs2 = offset of sectors on side 2
+ * flags = +/-mfm | +/-2step | +/-perpend
+ * mfm - use MFM recording
+ * 2step - use 2 steps between cylinders
+ * perpend - user perpendicular (vertical) recording
+ *
+ * Any omitted value will be passed on from parameter `in'.
+ */
+void
+parse_fmt(const char *s, enum fd_drivetype type,
+ struct fd_type in, struct fd_type *out)
+{
+ int i, j;
+ const char *cp;
+ char *s1;
+
+ *out = in;
+
+ for (i = 0;; i++) {
+ if (s == 0)
+ break;
+
+ if ((cp = strchr(s, ',')) == 0) {
+ s1 = strdup(s);
+ if (s1 == NULL)
+ abort();
+ s = 0;
+ } else {
+ s1 = malloc(cp - s + 1);
+ if (s1 == NULL)
+ abort();
+ memcpy(s1, s, cp - s);
+ s1[cp - s] = 0;
+
+ s = cp + 1;
+ }
+ if (strlen(s1) == 0) {
+ free(s1);
+ continue;
+ }
+
+ switch (i) {
+ case 0: /* sectrac */
+ if (getnum(s1, &out->sectrac))
+ errx(EX_USAGE,
+ "bad numeric value for sectrac: %s", s1);
+ break;
+
+ case 1: /* secsize */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for secsize: %s", s1);
+ if (j == 128) out->secsize = 0;
+ else if (j == 256) out->secsize = 1;
+ else if (j == 512) out->secsize = 2;
+ else if (j == 1024) out->secsize = 3;
+ else
+ errx(EX_USAGE, "bad sector size %d", j);
+ break;
+
+ case 2: /* datalen */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for datalen: %s", s1);
+ if (j >= 256)
+ errx(EX_USAGE, "bad datalen %d", j);
+ out->datalen = j;
+ break;
+
+ case 3: /* gap */
+ if (getnum(s1, &out->gap))
+ errx(EX_USAGE,
+ "bad numeric value for gap: %s", s1);
+ break;
+
+ case 4: /* ncyls */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for ncyls: %s", s1);
+ if (j > 85)
+ errx(EX_USAGE, "bad # of cylinders %d", j);
+ out->tracks = j;
+ break;
+
+ case 5: /* speed */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for speed: %s", s1);
+ switch (type) {
+ default:
+ abort(); /* paranoia */
+
+ case FDT_360K:
+ case FDT_720K:
+ if (j == 250)
+ out->trans = FDC_250KBPS;
+ else {
+ badspeed:
+ errx(EX_USAGE, "bad speed %d", j);
+ }
+ break;
+
+ case FDT_12M:
+ if (j == 300)
+ out->trans = FDC_300KBPS;
+ else if (j == 500)
+ out->trans = FDC_500KBPS;
+ else
+ goto badspeed;
+ break;
+
+ case FDT_288M:
+ if (j == 1000)
+ out->trans = FDC_1MBPS;
+ /* FALLTHROUGH */
+ case FDT_144M:
+ if (j == 250)
+ out->trans = FDC_250KBPS;
+ else if (j == 500)
+ out->trans = FDC_500KBPS;
+ else
+ goto badspeed;
+ break;
+ }
+ break;
+
+ case 6: /* heads */
+ if (getnum(s1, &j))
+ errx(EX_USAGE,
+ "bad numeric value for heads: %s", s1);
+ if (j == 1 || j == 2)
+ out->heads = j;
+ else
+ errx(EX_USAGE, "bad # of heads %d", j);
+ break;
+
+ case 7: /* f_gap */
+ if (getnum(s1, &out->f_gap))
+ errx(EX_USAGE,
+ "bad numeric value for f_gap: %s", s1);
+ break;
+
+ case 8: /* f_inter */
+ if (getnum(s1, &out->f_inter))
+ errx(EX_USAGE,
+ "bad numeric value for f_inter: %s", s1);
+ break;
+
+ case 9: /* offs2 */
+ if (getnum(s1, &out->offset_side2))
+ errx(EX_USAGE,
+ "bad numeric value for offs2: %s", s1);
+ break;
+
+ default:
+ if (strcmp(s1, "+mfm") == 0)
+ out->flags |= FL_MFM;
+ else if (strcmp(s1, "-mfm") == 0)
+ out->flags &= ~FL_MFM;
+ else if (strcmp(s1, "+2step") == 0)
+ out->flags |= FL_2STEP;
+ else if (strcmp(s1, "-2step") == 0)
+ out->flags &= ~FL_2STEP;
+ else if (strcmp(s1, "+perpnd") == 0)
+ out->flags |= FL_PERPND;
+ else if (strcmp(s1, "-perpnd") == 0)
+ out->flags &= ~FL_PERPND;
+ else
+ errx(EX_USAGE, "bad flag: %s", s1);
+ break;
+ }
+ free(s1);
+ }
+
+ out->size = out->tracks * out->heads * out->sectrac *
+ (128 << out->secsize) / 512;
+}
+
+/*
+ * Print a textual translation of the drive (density) type described
+ * by `in' to stdout. The string uses the same form that is parseable
+ * by parse_fmt().
+ */
+void
+print_fmt(struct fd_type in)
+{
+ int secsize, speed;
+
+ secsize = 128 << in.secsize;
+ switch (in.trans) {
+ case FDC_250KBPS: speed = 250; break;
+ case FDC_300KBPS: speed = 300; break;
+ case FDC_500KBPS: speed = 500; break;
+ case FDC_1MBPS: speed = 1000; break;
+ default: speed = 1; break;
+ }
+
+ printf("%d,%d,%#x,%#x,%d,%d,%d,%#x,%d,%d",
+ in.sectrac, secsize, in.datalen, in.gap, in.tracks,
+ speed, in.heads, in.f_gap, in.f_inter, in.offset_side2);
+ if (in.flags & FL_MFM)
+ printf(",+mfm");
+ if (in.flags & FL_2STEP)
+ printf(",+2step");
+ if (in.flags & FL_PERPND)
+ printf(",+perpnd");
+ putc('\n', stdout);
+}
+
+/*
+ * Based on `size' (in kilobytes), walk through the table of known
+ * densities for drive type `type' and see if we can find one. If
+ * found, return it (as a pointer to static storage), otherwise return
+ * NULL.
+ */
+struct fd_type *
+get_fmt(int size, enum fd_drivetype type)
+{
+ int i, n;
+ struct fd_type *fdtp;
+
+ switch (type) {
+ default:
+ return (0);
+
+ case FDT_360K:
+ fdtp = fd_types_360k;
+ n = sizeof fd_types_360k / sizeof(struct fd_type);
+ break;
+
+ case FDT_720K:
+ fdtp = fd_types_720k;
+ n = sizeof fd_types_720k / sizeof(struct fd_type);
+ break;
+
+ case FDT_12M:
+ fdtp = fd_types_12m;
+ n = sizeof fd_types_12m / sizeof(struct fd_type);
+ break;
+
+ case FDT_144M:
+ fdtp = fd_types_144m;
+ n = sizeof fd_types_144m / sizeof(struct fd_type);
+ break;
+
+ case FDT_288M:
+ fdtp = fd_types_288m;
+ n = sizeof fd_types_288m / sizeof(struct fd_type);
+ break;
+ }
+
+ for (i = 0; i < n; i++, fdtp++)
+ if (fdtp->size / 2 == size)
+ return (fdtp);
+
+ return (0);
+}
+
+/*
+ * Parse a number from `s'. If the string cannot be converted into a
+ * number completely, return -1, otherwise 0. The result is returned
+ * in `*res'.
+ */
+int
+getnum(const char *s, int *res)
+{
+ unsigned long ul;
+ char *cp;
+
+ ul = strtoul(s, &cp, 0);
+ if (*cp != '\0')
+ return (-1);
+
+ *res = (int)ul;
+ return (0);
+}
+
+/*
+ * Return a short name and a verbose description for the drive
+ * described by `t'.
+ */
+void
+getname(enum fd_drivetype t, const char **name, const char **descr)
+{
+
+ switch (t) {
+ default:
+ *name = "unknown";
+ *descr = "unknown drive type";
+ break;
+
+ case FDT_360K:
+ *name = "360K";
+ *descr = "5.25\" double-density";
+ break;
+
+ case FDT_12M:
+ *name = "1.2M";
+ *descr = "5.25\" high-density";
+ break;
+
+ case FDT_720K:
+ *name = "720K";
+ *descr = "3.5\" double-density";
+ break;
+
+ case FDT_144M:
+ *name = "1.44M";
+ *descr = "3.5\" high-density";
+ break;
+
+ case FDT_288M:
+ *name = "2.88M";
+ *descr = "3.5\" extra-density";
+ break;
+ }
+}
OpenPOWER on IntegriCloud