#include <dev/ic/nec765.h>
#include <sys/fdcio.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include "fdutil.h"
void
printstatus(struct fdc_status *fdcsp, int terse)
{
char msgbuf[100];
if (!terse)
fprintf(stderr,
"\nFDC status ST0=%#x ST1=%#x ST2=%#x C=%u H=%u R=%u N=%u:\n",
fdcsp->status[0] & 0xff,
fdcsp->status[1] & 0xff,
fdcsp->status[2] & 0xff,
fdcsp->status[3] & 0xff,
fdcsp->status[4] & 0xff,
fdcsp->status[5] & 0xff,
fdcsp->status[6] & 0xff);
if ((fdcsp->status[0] & NE7_ST0_IC_RC) == 0) {
sprintf(msgbuf, "timeout");
} else if ((fdcsp->status[0] & NE7_ST0_IC_RC) != NE7_ST0_IC_AT) {
sprintf(msgbuf, "unexcpted interrupt code %#x",
fdcsp->status[0] & NE7_ST0_IC_RC);
} else {
strcpy(msgbuf, "unexpected error code in ST1/ST2");
if (fdcsp->status[1] & NE7_ST1_EN)
strcpy(msgbuf, "end of cylinder (wrong format)");
else if (fdcsp->status[1] & NE7_ST1_DE) {
if (fdcsp->status[2] & NE7_ST2_DD)
strcpy(msgbuf, "CRC error in data field");
else
strcpy(msgbuf, "CRC error in ID field");
} else if (fdcsp->status[1] & NE7_ST1_MA) {
if (fdcsp->status[2] & NE7_ST2_MD)
strcpy(msgbuf, "no address mark in data field");
else
strcpy(msgbuf, "no address mark in ID field");
} else if (fdcsp->status[2] & NE7_ST2_WC)
strcpy(msgbuf, "wrong cylinder (format mismatch)");
else if (fdcsp->status[1] & NE7_ST1_ND)
strcpy(msgbuf, "no data (sector not found)");
}
fputs(msgbuf, stderr);
}
static struct fd_type fd_types_auto[1] =
{ { 0,0,0,0,0,0,0,0,0,0,0,FL_AUTO } };
static struct fd_type fd_types_288m[] = {
#if 0
{ FDF_3_2880 },
#endif
{ FDF_3_1722 },
{ FDF_3_1476 },
{ FDF_3_1440 },
{ FDF_3_1200 },
{ FDF_3_820 },
{ FDF_3_800 },
{ FDF_3_720 },
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
};
static struct fd_type fd_types_144m[] = {
{ FDF_3_1722 },
{ FDF_3_1476 },
{ FDF_3_1440 },
{ FDF_3_1200 },
{ FDF_3_820 },
{ FDF_3_800 },
{ FDF_3_720 },
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
};
static struct fd_type fd_types_12m[] = {
{ FDF_5_1200 },
{ FDF_5_1230 },
{ FDF_5_1480 },
{ FDF_5_1440 },
{ FDF_5_820 },
{ FDF_5_800 },
{ FDF_5_720 },
{ FDF_5_360 | FL_2STEP },
{ FDF_5_640 },
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
};
static struct fd_type fd_types_720k[] =
{
{ FDF_3_720 },
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
};
static struct fd_type fd_types_360k[] =
{
{ FDF_5_360 },
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
};
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 == NULL)
break;
if ((cp = strchr(s, ',')) == NULL) {
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:
if (getnum(s1, &out->sectrac))
errx(EX_USAGE,
"bad numeric value for sectrac: %s", s1);
break;
case 1:
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:
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:
if (getnum(s1, &out->gap))
errx(EX_USAGE,
"bad numeric value for gap: %s", s1);
break;
case 4:
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:
if (getnum(s1, &j))
errx(EX_USAGE,
"bad numeric value for speed: %s", s1);
switch (type) {
default:
abort();
case FDT_360K:
case FDT_720K:
if (j == 250)
out->trans = FDC_250KBPS;
else
errx(EX_USAGE, "bad speed %d", j);
break;
case FDT_12M:
if (j == 300)
out->trans = FDC_300KBPS;
else if (j == 250)
out->trans = FDC_250KBPS;
else if (j == 500)
out->trans = FDC_500KBPS;
else
errx(EX_USAGE, "bad speed %d", j);
break;
case FDT_288M:
if (j == 1000)
out->trans = FDC_1MBPS;
case FDT_144M:
if (j == 250)
out->trans = FDC_250KBPS;
else if (j == 500)
out->trans = FDC_500KBPS;
else
errx(EX_USAGE, "bad speed %d", j);
break;
}
break;
case 6:
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:
if (getnum(s1, &out->f_gap))
errx(EX_USAGE,
"bad numeric value for f_gap: %s", s1);
break;
case 8:
if (getnum(s1, &out->f_inter))
errx(EX_USAGE,
"bad numeric value for f_inter: %s", s1);
break;
case 9:
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, "+auto") == 0)
out->flags |= FL_AUTO;
else if (strcmp(s1, "-auto") == 0)
out->flags &= ~FL_AUTO;
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;
}
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");
if (in.flags & FL_AUTO)
printf(",+auto");
putc('\n', stdout);
}
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;
}
if (size == -1)
return fd_types_auto;
for (i = 0; i < n; i++, fdtp++) {
fdtp->size = fdtp->sectrac * fdtp->heads * fdtp->tracks;
if (((128 << fdtp->secsize) * fdtp->size / 1024) == size)
return (fdtp);
}
return (0);
}
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);
}
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;
}
}