diff --git a/usr.sbin/sicontrol/Makefile b/usr.sbin/sicontrol/Makefile new file mode 100644 index 000000000000..48dab5812dfc --- /dev/null +++ b/usr.sbin/sicontrol/Makefile @@ -0,0 +1,5 @@ +PROG= sicontrol +SRCS= sicontrol.c +MAN8= sicontrol.8 + +.include diff --git a/usr.sbin/sicontrol/sicontrol.c b/usr.sbin/sicontrol/sicontrol.c new file mode 100644 index 000000000000..ff6bdd410134 --- /dev/null +++ b/usr.sbin/sicontrol/sicontrol.c @@ -0,0 +1,584 @@ +/* + * Device driver for Specialix range (SLXOS) of serial line multiplexors. + * SLXOS configuration and debug interface + * + * Copyright (C) 1990, 1992 Specialix International, + * Copyright (C) 1993, Andy Rutter + * Copyright (C) 1995, Peter Wemm + * + * Derived from: SunOS 4.x version + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notices, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notices, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Andy Rutter of + * Advanced Methods and Tools Ltd. based on original information + * from Specialix International. + * 4. Neither the name of Advanced Methods and Tools, nor Specialix + * International may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHORS BE LIABLE. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct lv { + char *lv_name; + int lv_bit; +} lv[] = { + "entry", DBG_ENTRY, + "open", DBG_OPEN, + "close", DBG_CLOSE, + "read", DBG_READ, + "write", DBG_WRITE, + "param", DBG_PARAM, + "modem", DBG_MODEM, + "select", DBG_SELECT, + "direct", DBG_DIRECT, + "intr", DBG_INTR, + "start", DBG_START, + "lstart", DBG_LSTART, + "ioctl", DBG_IOCTL, + "fail", DBG_FAIL, + "autoboot", DBG_AUTOBOOT, + "download", DBG_DOWNLOAD, + "drain", DBG_DRAIN, + "poll", DBG_POLL, + 0, 0 +}; + +static int alldev = 0; +int getnum(char *str); + +int debug(), rxint(), txint(); +int mstate(), nport(); +int ccb_stat(), tty_stat(); +struct opt { + char *o_name; + int (*o_func)(); +} opt[] = { + "debug", debug, + "rxint_throttle", rxint, + "int_throttle", txint, + "mstate", mstate, + "nport", nport, + "ccbstat", ccb_stat, + "ttystat", tty_stat, + 0, 0, +}; + +struct stat_list { + int (*st_func)(); +} stat_list[] = { + mstate, + 0 +}; + +#define U_DEBUG 0 +#define U_TXINT 1 +#define U_RXINT 2 +#define U_MSTATE 3 +#define U_NPORT 4 +#define U_STAT_CCB 5 +#define U_STAT_TTY 6 +#define U_STAT_PORT 7 + +#define U_MAX 7 +#define U_ALL -1 +char *usage[] = { + "debug [[add|del|set debug_levels] | [off]]\n", + "int_throttle [newvalue]\n", + "rxint_throttle [newvalue]\n", + "mstate\n", + "nport\n", + "ccbstat\n", + "ttystat\n", + "portstat\n", + 0 +}; + +int ctlfd; +char *Devname; +struct si_tcsi tc; + +main(argc, argv) + char **argv; +{ + struct opt *op; + int (*func)() = NULL; + + if (argc < 2) + prusage(U_ALL, 1); + Devname = argv[1]; + if (strcmp(Devname, "-") == 0) { + alldev = 1; + } else { + sidev_t dev; + struct stat st; + + if (strchr(Devname, '/') == NULL) { + char *acp = malloc(6 + strlen(Devname)); + strcpy(acp, "/dev/"); + strcat(acp, Devname); + Devname = acp; + } + if (stat(Devname, &st) < 0) { + fprintf(stderr, "can't stat %s\n", Devname); + exit(1); + } + dev.sid_card = SI_CARD(minor(st.st_rdev)); + dev.sid_port = SI_PORT(minor(st.st_rdev)); + tc.tc_dev = dev; + } + ctlfd = opencontrol(); + if (argc == 2) { + dostat(); + exit(0); + } + + argc--; argv++; + for (op = opt; op->o_name; op++) { + if (strcmp(argv[1], op->o_name) == 0) { + func = op->o_func; + break; + } + } + if (func == NULL) + prusage(U_ALL, 1); + + argc -= 2; + argv += 2; + (*func)(argc, argv); + exit(0); +} + +opencontrol() +{ + int fd; + + fd = open(CONTROLDEV, O_RDWR|O_NDELAY); + if (fd < 0) { + fprintf(stderr, "open on %s - ", CONTROLDEV); + perror(""); + exit(1); + } + return(fd); +} + +/* + * Print a usage message - this relies on U_DEBUG==0 and U_BOOT==1. + * Don't print the DEBUG usage string unless explicity requested. + */ +prusage(strn, eflag) + int strn, eflag; +{ + char **cp; + + if (strn == U_ALL) { + fprintf(stderr, "Usage: siconfig - %s", usage[1]); + fprintf(stderr, " siconfig devname %s", usage[2]); + for (cp = &usage[3]; *cp; cp++) + fprintf(stderr, " %s", *cp); + } + else if (strn >= 0 && strn <= U_MAX) + fprintf(stderr, "Usage: siconfig devname %s", usage[strn]); + else + fprintf(stderr, "siconfig: usage ???\n"); + exit(eflag); +} + +/* print port status */ +dostat() +{ + char *av[1], *acp; + struct stat_list *stp; + struct si_tcsi stc; + int (*func)(); + int donefirst = 0; + + printf("%s: ", alldev ? "ALL" : Devname); + acp = malloc(strlen(Devname) + 3); + memset(acp, ' ', strlen(Devname)); + strcat(acp, " "); + stc = tc; + for (stp = stat_list; stp->st_func != NULL; stp++) { + if (donefirst) + fputs(acp, stdout); + else + donefirst++; + av[0] = NULL; + tc = stc; + (*stp->st_func)(-1, av); + } +} + +/* + * debug + * debug [[set|add|del debug_lvls] | [off]] + */ +debug(ac, av) + char **av; +{ + int level, cmd; + char *str; + + if (ac > 2) + prusage(U_DEBUG, 1); + if (alldev) { + if (ioctl(ctlfd, TCSIGDBG_ALL, &tc.tc_dbglvl) < 0) + Perror("TCSIGDBG_ALL on %s", Devname); + } else { + if (ioctl(ctlfd, TCSIGDBG_LEVEL, &tc) < 0) + Perror("TCSIGDBG_LEVEL on %s", Devname); + } + + switch (ac) { + case 0: + printf("%s: debug levels - ", Devname); + prlevels(tc.tc_dbglvl); + return; + case 1: + if (strcmp(av[0], "off") == 0) { + tc.tc_dbglvl = 0; + break; + } + prusage(U_DEBUG, 1); + /* no return */ + case 2: + level = lvls2bits(av[1]); + if (strcmp(av[0], "add") == 0) + tc.tc_dbglvl |= level; + else if (strcmp(av[0], "del") == 0) + tc.tc_dbglvl &= ~level; + else if (strcmp(av[0], "set") == 0) + tc.tc_dbglvl = level; + else + prusage(U_DEBUG, 1); + } + if (alldev) { + if (ioctl(ctlfd, TCSISDBG_ALL, &tc.tc_dbglvl) < 0) + Perror("TCSISDBG_ALL on %s", Devname); + } else { + if (ioctl(ctlfd, TCSISDBG_LEVEL, &tc) < 0) + Perror("TCSISDBG_LEVEL on %s", Devname); + } +} + +rxint(ac, av) + char **av; +{ + tc.tc_port = 0; + switch (ac) { + case 0: + printf("%s: ", Devname); + case -1: + if (ioctl(ctlfd, TCSIGRXIT, &tc) < 0) + Perror("TCSIGRXIT"); + printf("RX interrupt throttle: %d msec\n", tc.tc_int*10); + break; + case 1: + tc.tc_int = getnum(av[0]) / 10; + if (tc.tc_int == 0) + tc.tc_int = 1; + if (ioctl(ctlfd, TCSIRXIT, &tc) < 0) + Perror("TCSIRXIT on %s at %d msec", Devname, tc.tc_int*10); + break; + default: + prusage(U_RXINT, 1); + } +} + +txint(ac, av) + char **av; +{ + + tc.tc_port = 0; + switch (ac) { + case 0: + printf("%s: ", Devname); + case -1: + if (ioctl(ctlfd, TCSIGIT, &tc) < 0) + Perror("TCSIGIT"); + printf("aggregate interrupt throttle: %d\n", tc.tc_int); + break; + case 1: + tc.tc_int = getnum(av[0]); + if (ioctl(ctlfd, TCSIIT, &tc) < 0) + Perror("TCSIIT on %s at %d", Devname, tc.tc_int); + break; + default: + prusage(U_TXINT, 1); + } +} + +onoff(ac, av, cmd, cmdstr, prstr, usage) + char **av, *cmdstr, *prstr; + int ac, cmd, usage; +{ + if (ac > 1) + prusage(usage, 1); + if (ac == 1) { + if (strcmp(av[0], "on") == 0) + tc.tc_int = 1; + else if (strcmp(av[0], "off") == 0) + tc.tc_int = 0; + else + prusage(usage, 1); + } else + tc.tc_int = -1; + if (ioctl(ctlfd, cmd, &tc) < 0) + Perror("%s on %s", cmdstr, Devname); + switch (ac) { + case 0: + printf("%s: ", Devname); + case -1: + printf("%s ", prstr); + if (tc.tc_int) + printf("on\n"); + else + printf("off\n"); + } +} + +mstate(ac, av) + char **av; +{ + u_char state; + + switch (ac) { + case 0: + printf("%s: ", Devname); + case -1: + break; + default: + prusage(U_MSTATE, 1); + } + if (ioctl(ctlfd, TCSISTATE, &tc) < 0) + Perror("TCSISTATE on %s", Devname); + printf("modem bits state - (0x%x)", tc.tc_int); + if (tc.tc_int & IP_DCD) printf(" DCD"); + if (tc.tc_int & IP_DTR) printf(" DTR"); + if (tc.tc_int & IP_RTS) printf(" RTS"); + printf("\n"); +} + +nport(ac, av) + char **av; +{ + int ports; + + if (ac != 0) + prusage(U_NPORT, 1); + if (ioctl(ctlfd, TCSIPORTS, &ports) < 0) + Perror("TCSIPORTS on %s", Devname); + printf("SLXOS: total of %d ports\n", ports); +} + +ccb_stat(ac, av) +char **av; +{ + struct si_pstat sip; +#define CCB sip.tc_ccb + + if (ac != 0) + prusage(U_STAT_CCB); + sip.tc_dev = tc.tc_dev; + if (ioctl(ctlfd, TCSI_CCB, &sip) < 0) + Perror("TCSI_CCB on %s", Devname); + printf("%s: ", Devname); + + /* WORD next - Next Channel */ + /* WORD addr_uart - Uart address */ + /* WORD module - address of module struct */ + printf("\tuart_type 0x%x\n", CCB.type); /* BYTE type - Uart type */ + /* BYTE fill - */ + printf("\tx_status 0x%x\n", CCB.x_status); /* BYTE x_status - XON / XOFF status */ + printf("\tc_status 0x%x\n", CCB.c_status); /* BYTE c_status - cooking status */ + printf("\thi_rxipos 0x%x\n", CCB.hi_rxipos); /* BYTE hi_rxipos - stuff into rx buff */ + printf("\thi_rxopos 0x%x\n", CCB.hi_rxopos); /* BYTE hi_rxopos - stuff out of rx buffer */ + printf("\thi_txopos 0x%x\n", CCB.hi_txopos); /* BYTE hi_txopos - Stuff into tx ptr */ + printf("\thi_txipos 0x%x\n", CCB.hi_txipos); /* BYTE hi_txipos - ditto out */ + printf("\thi_stat 0x%x\n", CCB.hi_stat); /* BYTE hi_stat - Command register */ + printf("\tdsr_bit 0x%x\n", CCB.dsr_bit); /* BYTE dsr_bit - Magic bit for DSR */ + printf("\ttxon 0x%x\n", CCB.txon); /* BYTE txon - TX XON char */ + printf("\ttxoff 0x%x\n", CCB.txoff); /* BYTE txoff - ditto XOFF */ + printf("\trxon 0x%x\n", CCB.rxon); /* BYTE rxon - RX XON char */ + printf("\trxoff 0x%x\n", CCB.rxoff); /* BYTE rxoff - ditto XOFF */ + printf("\thi_mr1 0x%x\n", CCB.hi_mr1); /* BYTE hi_mr1 - mode 1 image */ + printf("\thi_mr2 0x%x\n", CCB.hi_mr2); /* BYTE hi_mr2 - mode 2 image */ + printf("\thi_csr 0x%x\n", CCB.hi_csr); /* BYTE hi_csr - clock register */ + printf("\thi_op 0x%x\n", CCB.hi_op); /* BYTE hi_op - Op control */ + printf("\thi_ip 0x%x\n", CCB.hi_ip); /* BYTE hi_ip - Input pins */ + printf("\thi_state 0x%x\n", CCB.hi_state); /* BYTE hi_state - status */ + printf("\thi_prtcl 0x%x\n", CCB.hi_prtcl); /* BYTE hi_prtcl - Protocol */ + printf("\thi_txon 0x%x\n", CCB.hi_txon); /* BYTE hi_txon - host copy tx xon stuff */ + printf("\thi_txoff 0x%x\n", CCB.hi_txoff); /* BYTE hi_txoff - */ + printf("\thi_rxon 0x%x\n", CCB.hi_rxon); /* BYTE hi_rxon - */ + printf("\thi_rxoff 0x%x\n", CCB.hi_rxoff); /* BYTE hi_rxoff - */ + printf("\tclose_prev 0x%x\n", CCB.close_prev); /* BYTE close_prev - Was channel previously closed */ + printf("\thi_break 0x%x\n", CCB.hi_break); /* BYTE hi_break - host copy break process */ + printf("\tbreak_state 0x%x\n", CCB.break_state); /* BYTE break_state - local copy ditto */ + printf("\thi_mask 0x%x\n", CCB.hi_mask); /* BYTE hi_mask - Mask for CS7 etc. */ + printf("\tmask_z280 0x%x\n", CCB.mask_z280); /* BYTE mask_z280 - Z280's copy */ + /* BYTE res[0x60 - 36] - */ + /* BYTE hi_txbuf[SLXOS_BUFFERSIZE] - */ + /* BYTE hi_rxbuf[SLXOS_BUFFERSIZE] - */ + /* BYTE res1[0xA0] - */ + +} + +tty_stat(ac, av) +char **av; +{ + struct si_pstat sip; +#define TTY sip.tc_tty + + if (ac != 0) + prusage(U_STAT_TTY); + sip.tc_dev = tc.tc_dev; + if (ioctl(ctlfd, TCSI_TTY, &sip) < 0) + Perror("TCSI_TTY on %s", Devname); + printf("%s: ", Devname); + + printf("\tt_outq.c_cc %d.\n", TTY.t_outq.c_cc); /* struct clist t_outq */ + printf("\tt_dev 0x%x\n", TTY.t_dev); /* dev_t t_dev */ + printf("\tt_flags 0x%x\n", TTY.t_flags); /* int t_flags */ + printf("\tt_state 0x%x\n", TTY.t_state); /* int t_state */ + printf("\tt_hiwat %d.\n", TTY.t_hiwat); /* short t_hiwat */ + printf("\tt_lowat %d.\n", TTY.t_lowat); /* short t_lowat */ + printf("\tt_iflag 0x%x\n", TTY.t_iflag); /* t_iflag */ + printf("\tt_oflag 0x%x\n", TTY.t_oflag); /* t_oflag */ + printf("\tt_cflag 0x%x\n", TTY.t_cflag); /* t_cflag */ + printf("\tt_lflag 0x%x\n", TTY.t_lflag); /* t_lflag */ + printf("\tt_cc 0x%x\n", TTY.t_cc); /* t_cc */ + printf("\tt_termios.c_ispeed 0x%x\n", TTY.t_termios.c_ispeed); /* t_termios.c_ispeed */ + printf("\tt_termios.c_ospeed 0x%x\n", TTY.t_termios.c_ospeed); /* t_termios.c_ospeed */ + +} + +islevel(tk) + char *tk; +{ + register struct lv *lvp; + register char *acp; + + for (acp = tk; *acp; acp++) + if (isupper(*acp)) + *acp = tolower(*acp); + for (lvp = lv; lvp->lv_name; lvp++) + if (strcmp(lvp->lv_name, tk) == 0) + return(lvp->lv_bit); + return(0); +} + +/* + * Convert a string consisting of tokens separated by white space, commas + * or `|' into a bitfield - flag any unrecognised tokens. + */ +lvls2bits(str) + char *str; +{ + int i, bits = 0; + int errflag = 0; + char token[20]; + + while (sscanf(str, "%[^,| \t]", token) == 1) { + str += strlen(token); + while (isspace(*str) || *str==',' || *str=='|') + str++; + if (strcmp(token, "all") == 0) + return(0xffffffff); + if ((i = islevel(token)) == 0) { + fprintf(stderr, "siconfig: unknown token '%s'\n", token); + errflag++; + } else + bits |= i; + } + if (errflag) + exit(1); + + return(bits); +} + +int +getnum(char *str) +{ + int x; + register char *acp = str; + + x = 0; + while (*acp) { + if (!isdigit(*acp)) { + error("%s is not a number\n", str); + exit(1); + } + x *= 10; + x += (*acp - '0'); + acp++; + } + return(x); +} + +prlevels(x) + int x; +{ + struct lv *lvp; + + switch (x) { + case 0: + printf("(none)\n"); + break; + case 0xffffffff: + printf("all\n"); + break; + default: + for (lvp = lv; lvp->lv_name; lvp++) + if (x & lvp->lv_bit) + printf(" %s", lvp->lv_name); + printf("\n"); + } +} + +/* VARARGS */ +Perror(str, a1, a2, a3, a4, a5) + char *str; + int a1, a2, a3, a4, a5; +{ + fprintf(stderr, str, a1, a2, a3, a4, a5); + perror(" "); + exit(1); +} + +/* VARARGS */ +error(str, a1, a2, a3, a4, a5) + char *str; + int a1, a2, a3, a4, a5; +{ + fprintf(stderr, str, a1, a2, a3, a4, a5); + exit(1); +}