Add my user configuration utility - userconfig().

David wrote the I/O routines for this thing and deserves most of the
credit for thinking the whole idea up.
This commit is contained in:
jkh 1994-10-26 19:18:28 +00:00
parent 329cc40b92
commit 70ece4ed16

429
sys/i386/i386/userconfig.c Normal file
View File

@ -0,0 +1,429 @@
#include <sys/param.h>
#include <sys/types.h>
#include <sys/cdefs.h>
#include <i386/isa/isa_device.h>
#include <i386/isa/isa.c>
#include <machine/console.h>
#include <machine/limits.h>
#define PARM_DEVSPEC 0x1
#define PARM_INT 0x2
#define PARM_ADDR 0x3
typedef struct _cmdparm {
int type;
union {
struct isa_device *dparm;
int iparm;
void *aparm;
} parm;
} CmdParm;
typedef int (*CmdFunc)(CmdParm *);
typedef struct _cmd {
char *name;
CmdFunc handler;
CmdParm *parms;
} Cmd;
static void lsdevtab(struct isa_device *);
static struct isa_device *find_device(char *, int);
static struct isa_device *search_devtable(struct isa_device *, char *, int);
static void cngets(char *, int);
static Cmd *parse_cmd(char *);
static int parse_args(char *, CmdParm *);
long strtol(const char *, char **, int);
int strncmp(const char *, const char *, size_t);
static int list_devices(CmdParm *);
static int set_device_ioaddr(CmdParm *);
static int set_device_irq(CmdParm *);
static int set_device_drq(CmdParm *);
static int set_device_mem(CmdParm *);
static int set_device_enable(CmdParm *);
static int set_device_disable(CmdParm *);
static int quitfunc(CmdParm *);
static int helpfunc(CmdParm *);
CmdParm addr_parms[] = {
{ PARM_DEVSPEC, {} },
{ PARM_ADDR, {} },
{ -1, {} },
};
CmdParm int_parms[] = {
{ PARM_DEVSPEC, {} },
{ PARM_INT, {} },
{ -1, {} },
};
CmdParm dev_parms[] = {
{ PARM_DEVSPEC, {} },
{ -1, {} },
};
Cmd CmdList[] = {
{ "ls", list_devices, NULL }, /* ls */
{ "list", list_devices, NULL }, /* "" */
{ "io", set_device_ioaddr, addr_parms }, /* io dev addr */
{ "irq", set_device_irq, int_parms }, /* irq dev # */
{ "drq", set_device_drq, int_parms }, /* drq dev # */
{ "mem", set_device_mem, int_parms }, /* mem dev # */
{ "enable", set_device_enable, dev_parms }, /* enable dev */
{ "disable", set_device_disable, dev_parms }, /* disable dev */
{ "quit", quitfunc, NULL }, /* quit */
{ "q", quitfunc, NULL }, /* "" */
{ "exit", quitfunc, NULL }, /* "" */
{ "help", helpfunc, NULL }, /* help */
{ "?", helpfunc, NULL }, /* "" */
{ NULL, NULL, NULL },
};
void
userconfig(void)
{
char command[80];
char input[80];
int rval;
struct isa_device *dt;
Cmd *cmd;
while (1) {
printf("config> ");
cngets(input, 80);
if (input[0] == NULL)
continue;
cmd = parse_cmd(input);
if (!cmd) {
printf("Invalid command or syntax. Type `?' for help.\n");
continue;
}
rval = (*cmd->handler)(cmd->parms);
if (rval)
return;
}
}
static Cmd *
parse_cmd(char *cmd)
{
Cmd *cp;
for (cp = CmdList; cp->name; cp++) {
int len = strlen(cp->name);
if (!strncmp(cp->name, cmd, len)) {
if (parse_args(cmd + len, cp->parms))
return NULL;
else
return cp;
}
}
return NULL;
}
static int
parse_args(char *cmd, CmdParm *parms)
{
while (*cmd) {
char *ptr;
if (parms->type == -1)
return 0;
if (*cmd == ' ' || *cmd == '\t') {
++cmd;
continue;
}
if (parms->type == PARM_DEVSPEC) {
int i = 0;
char devname[64];
int unit = 0;
while (*cmd && !(*cmd == ' ' || *cmd == '\t' ||
(*cmd >= '0' && *cmd <= '9')))
devname[i++] = *(cmd++);
devname[i] = NULL;
if (*cmd >= '0' && *cmd <= '9') {
unit = strtol(cmd, &ptr, 10);
cmd = ptr;
}
if ((parms->parm.dparm = find_device(devname, unit)) == NULL) {
printf("No such device: %s%d\n", devname, unit);
return 1;
}
++parms;
continue;
}
if (parms->type == PARM_INT) {
parms->parm.iparm = strtol(cmd, &ptr, 10);
if (cmd == ptr) {
printf("Invalid numeric argument\n");
return 1;
}
cmd = ptr;
++parms;
continue;
}
if (parms->type == PARM_ADDR) {
parms->parm.aparm = (void *)strtol(cmd, &ptr, 16);
if (cmd == ptr) {
printf("Invalid address argument\n");
return 1;
}
cmd = ptr;
++parms;
continue;
}
}
return 0;
}
static int
list_devices(CmdParm *parms)
{
printf("Device IOaddr IRQ DRQ MemAddr Flags Enabled\n");
lsdevtab(&isa_devtab_bio[0]);
lsdevtab(&isa_devtab_tty[0]);
lsdevtab(&isa_devtab_net[0]);
lsdevtab(&isa_devtab_null[0]);
return 0;
}
static int
set_device_ioaddr(CmdParm *parms)
{
parms[0].parm.dparm->id_iobase = parms[1].parm.aparm;
return 0;
}
static int
set_device_irq(CmdParm *parms)
{
parms[0].parm.dparm->id_irq = parms[1].parm.iparm;
return 0;
}
static int
set_device_drq(CmdParm *parms)
{
parms[0].parm.dparm->id_drq = parms[1].parm.iparm;
return 0;
}
static int
set_device_mem(CmdParm *parms)
{
parms[0].parm.dparm->id_maddr = parms[1].parm.aparm;
return 0;
}
static int
set_device_enable(CmdParm *parms)
{
return 0;
}
static int
set_device_disable(CmdParm *parms)
{
return 0;
}
static int
quitfunc(CmdParm *parms)
{
return 1;
}
static int
helpfunc(CmdParm *parms)
{
printf("Command\t\tDescription\n");
printf("-------\t\t-----------\n");
printf("ls\t\t\tList currently configured devices\n");
printf("io <devname> <addr>\tSet device io address\n");
printf("irq <devname> <irq>\tSet device IRQ\n");
printf("drq <devname> <drq>\tSet device DRQ\n");
printf("mem <devname> <addr>\tSet device memory address\n");
printf("enable <devname>\tEnable device\n");
printf("disable <devname>\tDisable device (will not be probed)\n");
printf("quit\t\t\tExit this configuration utility\n");
printf("help\t\t\tThis message\n");
return 0;
}
static void
lsdevtab(struct isa_device *dt)
{
int i;
for (i = 0; dt->id_id != 0; dt++) {
printf("%s%d 0x%x %d %d 0x%x 0x%x %s\n",
dt->id_driver->name, dt->id_unit, dt->id_iobase,
ffs(dt->id_irq) - 1, dt->id_drq, dt->id_maddr,
dt->id_flags, "Yes");
}
}
static struct isa_device *
find_device(char *devname, int unit)
{
struct isa_device *ret;
if ((ret = search_devtable(&isa_devtab_bio[0], devname, unit)) != NULL)
return ret;
if ((ret = search_devtable(&isa_devtab_tty[0], devname, unit)) != NULL)
return ret;
if ((ret = search_devtable(&isa_devtab_net[0], devname, unit)) != NULL)
return ret;
if ((ret = search_devtable(&isa_devtab_null[0], devname, unit)) != NULL)
return ret;
return NULL;
}
static struct isa_device *
search_devtable(struct isa_device *dt, char *devname, int unit)
{
int i;
for (i = 0; dt->id_id != 0; dt++)
if (!strcmp(dt->id_driver->name, devname) && dt->id_unit == unit)
return dt;
return NULL;
}
void
cngets(char *input, int maxin)
{
int c, nchars = 0;
while (1) {
c = cngetc();
if (c == NOKEY)
continue;
/* Treat ^H or ^? as backspace */
if ((c == '\010' || c == '\177')) {
if (nchars) {
printf("\010 \010");
*--input = NULL, --nchars;
}
continue;
}
/* Treat ^U or ^X as kill line */
else if ((c == '\025' || c == '\030')) {
while (nchars--) {
*--input = NULL;
printf("\010 \010");
}
continue;
}
printf("%c", c);
if ((++nchars == maxin) || (c == '\n')) {
*input = NULL;
break;
}
*input++ = (u_char)c;
}
}
int
strncmp(const char *s1, const char *s2, size_t n)
{
if (n == 0)
return (0);
do {
if (*s1 != *s2++)
return (*(unsigned char *)s1 - *(unsigned char *)--s2);
if (*s1++ == 0)
break;
} while (--n != 0);
return (0);
}
/*
* Convert a string to a long integer.
*
* Ignores `locale' stuff. Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*
* Slightly lobotomized for inclusion here.
*/
long
strtol(const char *nptr, char **endptr, int base)
{
register const char *s = nptr;
register unsigned long acc;
register int c;
register unsigned long cutoff;
register int neg = 0, any, cutlim;
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
do {
c = *s++;
} while (c == ' ' || c == '\t');
if (c == '-') {
neg = 1;
c = *s++;
} else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X')) {
c = s[1];
s += 2;
base = 16;
}
if (base == 0)
base = c == '0' ? 8 : 10;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
cutlim = cutoff % (unsigned long)base;
cutoff /= (unsigned long)base;
for (acc = 0, any = 0;; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
c -= (c >= 'A' && c <= 'Z') ? 'A' - 10 : 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}