sicontrol.c revision 69793
1/* 2 * Device driver for Specialix range (SLXOS) of serial line multiplexors. 3 * SLXOS configuration and debug interface 4 * 5 * Copyright (C) 1990, 1992 Specialix International, 6 * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk> 7 * Copyright (C) 1995, Peter Wemm <peter@haywire.dialix.com> 8 * 9 * Derived from: SunOS 4.x version 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notices, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notices, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by Andy Rutter of 22 * Advanced Methods and Tools Ltd. based on original information 23 * from Specialix International. 24 * 4. Neither the name of Advanced Methods and Tools, nor Specialix 25 * International may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 30 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 31 * NO EVENT SHALL THE AUTHORS BE LIABLE. 32 */ 33 34#ifndef lint 35static const char rcsid[] = 36 "$FreeBSD: head/usr.sbin/sicontrol/sicontrol.c 69793 2000-12-09 09:35:55Z obrien $"; 37#endif /* not lint */ 38 39#include <ctype.h> 40#include <err.h> 41#include <fcntl.h> 42#include <paths.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <sys/types.h> 47#include <sys/param.h> 48#include <sys/stat.h> 49#include <sys/ioctl.h> 50#include <sys/tty.h> 51 52#include <dev/si/si.h> 53 54struct lv { 55 char *lv_name; 56 int lv_bit; 57} lv[] = { 58 {"entry", DBG_ENTRY}, 59 {"open", DBG_OPEN}, 60 {"close", DBG_CLOSE}, 61 {"read", DBG_READ}, 62 {"write", DBG_WRITE}, 63 {"param", DBG_PARAM}, 64 {"modem", DBG_MODEM}, 65 {"select", DBG_SELECT}, 66 {"optim", DBG_OPTIM}, 67 {"intr", DBG_INTR}, 68 {"start", DBG_START}, 69 {"lstart", DBG_LSTART}, 70 {"ioctl", DBG_IOCTL}, 71 {"fail", DBG_FAIL}, 72 {"autoboot", DBG_AUTOBOOT}, 73 {"download", DBG_DOWNLOAD}, 74 {"drain", DBG_DRAIN}, 75 {"poll", DBG_POLL}, 76 {0, 0} 77}; 78 79static int alldev = 0; 80 81void ccb_stat(int, char **); 82void debug(int, char **); 83void dostat(void); 84int getnum(char *); 85int islevel(char *); 86int lvls2bits(char *); 87void mstate(int, char **); 88void nport(int, char **); 89void onoff(int, char **, int, char *, char *, int); 90int opencontrol(void); 91void prlevels(int); 92void prusage(int, int); 93void rxint(int, char **); 94void tty_stat(int, char **); 95void txint(int, char **); 96 97struct opt { 98 char *o_name; 99 void (*o_func)(int, char **); 100} opt[] = { 101 {"debug", debug}, 102 {"rxint_throttle", rxint}, 103 {"int_throttle", txint}, 104 {"nport", nport}, 105 {"mstate", mstate}, 106 {"ccbstat", ccb_stat}, 107 {"ttystat", tty_stat}, 108 {0, 0} 109}; 110 111struct stat_list { 112 void (*st_func)(int, char **); 113} stat_list[] = { 114 {mstate}, 115 {0} 116}; 117 118#define U_DEBUG 0 119#define U_TXINT 1 120#define U_RXINT 2 121#define U_NPORT 3 122#define U_MSTATE 4 123#define U_STAT_CCB 5 124#define U_STAT_TTY 6 125 126#define U_MAX 7 127#define U_ALL -1 128char *usage[] = { 129 "debug [[add|del|set debug_levels] | [off]]\n", 130 "int_throttle [newvalue]\n", 131 "rxint_throttle [newvalue]\n", 132 "nport\n", 133 "mstate\n", 134 "ccbstat\n", 135 "ttystat\n", 136 0 137}; 138 139int ctlfd; 140char *Devname; 141struct si_tcsi tc; 142 143int 144main(int argc, char **argv) 145{ 146 struct opt *op; 147 void (*func)(int, char **) = NULL; 148 149 if (argc < 2) 150 prusage(U_ALL, 1); 151 Devname = argv[1]; 152 if (strcmp(Devname, "-") == 0) { 153 alldev = 1; 154 } else { 155 sidev_t dev; 156 struct stat st; 157 158 if (strchr(Devname, '/') == NULL) { 159 char *acp = malloc(6 + strlen(Devname)); 160 strcpy(acp, _PATH_DEV); 161 strcat(acp, Devname); 162 Devname = acp; 163 } 164 if (stat(Devname, &st) < 0) 165 errx(1, "can't stat %s", Devname); 166 dev.sid_card = SI_CARD(minor(st.st_rdev)); 167 dev.sid_port = SI_PORT(minor(st.st_rdev)); 168 tc.tc_dev = dev; 169 } 170 ctlfd = opencontrol(); 171 if (argc == 2) { 172 dostat(); 173 exit(0); 174 } 175 176 argc--; argv++; 177 for (op = opt; op->o_name; op++) { 178 if (strcmp(argv[1], op->o_name) == 0) { 179 func = op->o_func; 180 break; 181 } 182 } 183 if (func == NULL) 184 prusage(U_ALL, 1); 185 186 argc -= 2; 187 argv += 2; 188 (*func)(argc, argv); 189 exit(0); 190} 191 192int 193opencontrol(void) 194{ 195 int fd; 196 197 fd = open(CONTROLDEV, O_RDWR|O_NDELAY); 198 if (fd < 0) 199 err(1, "open on %s", CONTROLDEV); 200 return(fd); 201} 202 203/* 204 * Print a usage message - this relies on U_DEBUG==0 and U_BOOT==1. 205 * Don't print the DEBUG usage string unless explicity requested. 206 */ 207void 208prusage(int strn, int eflag) 209{ 210 char **cp; 211 212 if (strn == U_ALL) { 213 fprintf(stderr, "usage: sicontrol %s", usage[1]); 214 fprintf(stderr, " sicontrol %s", usage[2]); 215 fprintf(stderr, " sicontrol %s", usage[3]); 216 fprintf(stderr, " sicontrol devname %s", usage[4]); 217 for (cp = &usage[5]; *cp; cp++) 218 fprintf(stderr, " sicontrol devname %s", *cp); 219 } 220 else if (strn >= 0 && strn <= U_MAX) 221 fprintf(stderr, "usage: sicontrol devname %s", usage[strn]); 222 else 223 fprintf(stderr, "sicontrol: usage ???\n"); 224 exit(eflag); 225} 226 227/* print port status */ 228void 229dostat(void) 230{ 231 char *av[1], *acp; 232 struct stat_list *stp; 233 struct si_tcsi stc; 234 int donefirst = 0; 235 236 printf("%s: ", alldev ? "ALL" : Devname); 237 acp = malloc(strlen(Devname) + 3); 238 memset(acp, ' ', strlen(Devname)); 239 strcat(acp, " "); 240 stc = tc; 241 for (stp = stat_list; stp->st_func != NULL; stp++) { 242 if (donefirst) 243 fputs(acp, stdout); 244 else 245 donefirst++; 246 av[0] = NULL; 247 tc = stc; 248 (*stp->st_func)(-1, av); 249 } 250} 251 252/* 253 * debug 254 * debug [[set|add|del debug_lvls] | [off]] 255 */ 256void 257debug(int ac, char **av) 258{ 259 int level; 260 261 if (ac > 2) 262 prusage(U_DEBUG, 1); 263 if (alldev) { 264 if (ioctl(ctlfd, TCSIGDBG_ALL, &tc.tc_dbglvl) < 0) 265 err(1, "TCSIGDBG_ALL on %s", Devname); 266 } else { 267 if (ioctl(ctlfd, TCSIGDBG_LEVEL, &tc) < 0) 268 err(1, "TCSIGDBG_LEVEL on %s", Devname); 269 } 270 271 switch (ac) { 272 case 0: 273 printf("%s: debug levels - ", Devname); 274 prlevels(tc.tc_dbglvl); 275 return; 276 case 1: 277 if (strcmp(av[0], "off") == 0) { 278 tc.tc_dbglvl = 0; 279 break; 280 } 281 prusage(U_DEBUG, 1); 282 /* no return */ 283 case 2: 284 level = lvls2bits(av[1]); 285 if (strcmp(av[0], "add") == 0) 286 tc.tc_dbglvl |= level; 287 else if (strcmp(av[0], "del") == 0) 288 tc.tc_dbglvl &= ~level; 289 else if (strcmp(av[0], "set") == 0) 290 tc.tc_dbglvl = level; 291 else 292 prusage(U_DEBUG, 1); 293 } 294 if (alldev) { 295 if (ioctl(ctlfd, TCSISDBG_ALL, &tc.tc_dbglvl) < 0) 296 err(1, "TCSISDBG_ALL on %s", Devname); 297 } else { 298 if (ioctl(ctlfd, TCSISDBG_LEVEL, &tc) < 0) 299 err(1, "TCSISDBG_LEVEL on %s", Devname); 300 } 301} 302 303void 304rxint(int ac, char **av) 305{ 306 tc.tc_port = 0; 307 switch (ac) { 308 case 0: 309 printf("%s: ", Devname); 310 case -1: 311 if (ioctl(ctlfd, TCSIGRXIT, &tc) < 0) 312 err(1, "TCSIGRXIT"); 313 printf("RX interrupt throttle: %d msec\n", tc.tc_int*10); 314 break; 315 case 1: 316 tc.tc_int = getnum(av[0]) / 10; 317 if (tc.tc_int == 0) 318 tc.tc_int = 1; 319 if (ioctl(ctlfd, TCSIRXIT, &tc) < 0) 320 err(1, "TCSIRXIT on %s at %d msec", 321 Devname, tc.tc_int*10); 322 break; 323 default: 324 prusage(U_RXINT, 1); 325 } 326} 327 328void 329txint(int ac, char **av) 330{ 331 332 tc.tc_port = 0; 333 switch (ac) { 334 case 0: 335 printf("%s: ", Devname); 336 case -1: 337 if (ioctl(ctlfd, TCSIGIT, &tc) < 0) 338 err(1, "TCSIGIT"); 339 printf("aggregate interrupt throttle: %d\n", tc.tc_int); 340 break; 341 case 1: 342 tc.tc_int = getnum(av[0]); 343 if (ioctl(ctlfd, TCSIIT, &tc) < 0) 344 err(1, "TCSIIT on %s at %d", Devname, tc.tc_int); 345 break; 346 default: 347 prusage(U_TXINT, 1); 348 } 349} 350 351void 352onoff(int ac, char **av, int cmd, char *cmdstr, char *prstr, int usage) 353{ 354 if (ac > 1) 355 prusage(usage, 1); 356 if (ac == 1) { 357 if (strcmp(av[0], "on") == 0) 358 tc.tc_int = 1; 359 else if (strcmp(av[0], "off") == 0) 360 tc.tc_int = 0; 361 else 362 prusage(usage, 1); 363 } else 364 tc.tc_int = -1; 365 if (ioctl(ctlfd, cmd, &tc) < 0) 366 err(1, "%s on %s", cmdstr, Devname); 367 switch (ac) { 368 case 0: 369 printf("%s: ", Devname); 370 case -1: 371 printf("%s ", prstr); 372 if (tc.tc_int) 373 printf("on\n"); 374 else 375 printf("off\n"); 376 } 377} 378 379void 380mstate(int ac, char **av) 381{ 382 switch (ac) { 383 case 0: 384 printf("%s: ", Devname); 385 case -1: 386 break; 387 default: 388 prusage(U_MSTATE, 1); 389 } 390 if (ioctl(ctlfd, TCSISTATE, &tc) < 0) 391 err(1, "TCSISTATE on %s", Devname); 392 printf("modem bits state - (0x%x)", tc.tc_int); 393 if (tc.tc_int & IP_DCD) printf(" DCD"); 394 if (tc.tc_int & IP_DTR) printf(" DTR"); 395 if (tc.tc_int & IP_RTS) printf(" RTS"); 396 printf("\n"); 397} 398 399void 400nport(int ac, char **av) 401{ 402 int ports; 403 404 if (ac != 0) 405 prusage(U_NPORT, 1); 406 if (ioctl(ctlfd, TCSIPORTS, &ports) < 0) 407 err(1, "TCSIPORTS on %s", Devname); 408 printf("SLXOS: total of %d ports\n", ports); 409} 410 411void 412ccb_stat(int ac, char **av) 413{ 414 struct si_pstat sip; 415#define CCB sip.tc_ccb 416 417 if (ac != 0) 418 prusage(U_STAT_CCB, 1); 419 sip.tc_dev = tc.tc_dev; 420 if (ioctl(ctlfd, TCSI_CCB, &sip) < 0) 421 err(1, "TCSI_CCB on %s", Devname); 422 printf("%s: ", Devname); 423 424 /* WORD next - Next Channel */ 425 /* WORD addr_uart - Uart address */ 426 /* WORD module - address of module struct */ 427 printf("\tuart_type 0x%x\n", CCB.type); /* BYTE type - Uart type */ 428 /* BYTE fill - */ 429 printf("\tx_status 0x%x\n", CCB.x_status); /* BYTE x_status - XON / XOFF status */ 430 printf("\tc_status 0x%x\n", CCB.c_status); /* BYTE c_status - cooking status */ 431 printf("\thi_rxipos 0x%x\n", CCB.hi_rxipos); /* BYTE hi_rxipos - stuff into rx buff */ 432 printf("\thi_rxopos 0x%x\n", CCB.hi_rxopos); /* BYTE hi_rxopos - stuff out of rx buffer */ 433 printf("\thi_txopos 0x%x\n", CCB.hi_txopos); /* BYTE hi_txopos - Stuff into tx ptr */ 434 printf("\thi_txipos 0x%x\n", CCB.hi_txipos); /* BYTE hi_txipos - ditto out */ 435 printf("\thi_stat 0x%x\n", CCB.hi_stat); /* BYTE hi_stat - Command register */ 436 printf("\tdsr_bit 0x%x\n", CCB.dsr_bit); /* BYTE dsr_bit - Magic bit for DSR */ 437 printf("\ttxon 0x%x\n", CCB.txon); /* BYTE txon - TX XON char */ 438 printf("\ttxoff 0x%x\n", CCB.txoff); /* BYTE txoff - ditto XOFF */ 439 printf("\trxon 0x%x\n", CCB.rxon); /* BYTE rxon - RX XON char */ 440 printf("\trxoff 0x%x\n", CCB.rxoff); /* BYTE rxoff - ditto XOFF */ 441 printf("\thi_mr1 0x%x\n", CCB.hi_mr1); /* BYTE hi_mr1 - mode 1 image */ 442 printf("\thi_mr2 0x%x\n", CCB.hi_mr2); /* BYTE hi_mr2 - mode 2 image */ 443 printf("\thi_csr 0x%x\n", CCB.hi_csr); /* BYTE hi_csr - clock register */ 444 printf("\thi_op 0x%x\n", CCB.hi_op); /* BYTE hi_op - Op control */ 445 printf("\thi_ip 0x%x\n", CCB.hi_ip); /* BYTE hi_ip - Input pins */ 446 printf("\thi_state 0x%x\n", CCB.hi_state); /* BYTE hi_state - status */ 447 printf("\thi_prtcl 0x%x\n", CCB.hi_prtcl); /* BYTE hi_prtcl - Protocol */ 448 printf("\thi_txon 0x%x\n", CCB.hi_txon); /* BYTE hi_txon - host copy tx xon stuff */ 449 printf("\thi_txoff 0x%x\n", CCB.hi_txoff); /* BYTE hi_txoff - */ 450 printf("\thi_rxon 0x%x\n", CCB.hi_rxon); /* BYTE hi_rxon - */ 451 printf("\thi_rxoff 0x%x\n", CCB.hi_rxoff); /* BYTE hi_rxoff - */ 452 printf("\tclose_prev 0x%x\n", CCB.close_prev); /* BYTE close_prev - Was channel previously closed */ 453 printf("\thi_break 0x%x\n", CCB.hi_break); /* BYTE hi_break - host copy break process */ 454 printf("\tbreak_state 0x%x\n", CCB.break_state); /* BYTE break_state - local copy ditto */ 455 printf("\thi_mask 0x%x\n", CCB.hi_mask); /* BYTE hi_mask - Mask for CS7 etc. */ 456 printf("\tmask_z280 0x%x\n", CCB.mask_z280); /* BYTE mask_z280 - Z280's copy */ 457 /* BYTE res[0x60 - 36] - */ 458 /* BYTE hi_txbuf[SLXOS_BUFFERSIZE] - */ 459 /* BYTE hi_rxbuf[SLXOS_BUFFERSIZE] - */ 460 /* BYTE res1[0xA0] - */ 461} 462 463void 464tty_stat(int ac, char **av) 465{ 466 struct si_pstat sip; 467#define TTY sip.tc_tty 468 469 if (ac != 0) 470 prusage(U_STAT_TTY, 1); 471 sip.tc_dev = tc.tc_dev; 472 if (ioctl(ctlfd, TCSI_TTY, &sip) < 0) 473 err(1, "TCSI_TTY on %s", Devname); 474 printf("%s: ", Devname); 475 476 printf("\tt_outq.c_cc %d.\n", TTY.t_outq.c_cc); /* struct clist t_outq */ 477 printf("\tt_dev 0x%x\n", TTY.t_dev); /* dev_t t_dev */ 478 printf("\tt_flags 0x%x\n", TTY.t_flags); /* int t_flags */ 479 printf("\tt_state 0x%x\n", TTY.t_state); /* int t_state */ 480 printf("\tt_ihiwat %d.\n", TTY.t_ihiwat); /* int t_ihiwat */ 481 printf("\tt_ilowat %d.\n", TTY.t_ilowat); /* int t_ilowat */ 482 printf("\tt_ohiwat %d.\n", TTY.t_ohiwat); /* int t_ohiwat */ 483 printf("\tt_olowat %d.\n", TTY.t_olowat); /* int t_olowat */ 484 printf("\tt_iflag 0x%x\n", TTY.t_iflag); /* t_iflag */ 485 printf("\tt_oflag 0x%x\n", TTY.t_oflag); /* t_oflag */ 486 printf("\tt_cflag 0x%x\n", TTY.t_cflag); /* t_cflag */ 487 printf("\tt_lflag 0x%x\n", TTY.t_lflag); /* t_lflag */ 488 printf("\tt_cc %p\n", (void *)TTY.t_cc); /* t_cc */ 489 printf("\tt_termios.c_ispeed 0x%x\n", TTY.t_termios.c_ispeed); /* t_termios.c_ispeed */ 490 printf("\tt_termios.c_ospeed 0x%x\n", TTY.t_termios.c_ospeed); /* t_termios.c_ospeed */ 491} 492 493int 494islevel(char *tk) 495{ 496 struct lv *lvp; 497 char *acp; 498 499 for (acp = tk; *acp; acp++) 500 if (isupper(*acp)) 501 *acp = tolower(*acp); 502 for (lvp = lv; lvp->lv_name; lvp++) 503 if (strcmp(lvp->lv_name, tk) == 0) 504 return(lvp->lv_bit); 505 return(0); 506} 507 508/* 509 * Convert a string consisting of tokens separated by white space, commas 510 * or `|' into a bitfield - flag any unrecognised tokens. 511 */ 512int 513lvls2bits(char *str) 514{ 515 int i, bits = 0; 516 int errflag = 0; 517 char token[20]; 518 519 while (sscanf(str, "%[^,| \t]", token) == 1) { 520 str += strlen(token); 521 while (isspace(*str) || *str==',' || *str=='|') 522 str++; 523 if (strcmp(token, "all") == 0) 524 return(0xffffffff); 525 if ((i = islevel(token)) == 0) { 526 warnx("unknown token '%s'", token); 527 errflag++; 528 } else 529 bits |= i; 530 } 531 if (errflag) 532 exit(1); 533 534 return(bits); 535} 536 537int 538getnum(char *str) 539{ 540 int x; 541 char *acp = str; 542 543 x = 0; 544 while (*acp) { 545 if (!isdigit(*acp)) 546 errx(1, "%s is not a number", str); 547 x *= 10; 548 x += (*acp - '0'); 549 acp++; 550 } 551 return(x); 552} 553 554void 555prlevels(int x) 556{ 557 struct lv *lvp; 558 559 switch (x) { 560 case 0: 561 printf("(none)\n"); 562 break; 563 case 0xffffffff: 564 printf("all\n"); 565 break; 566 default: 567 for (lvp = lv; lvp->lv_name; lvp++) 568 if (x & lvp->lv_bit) 569 printf(" %s", lvp->lv_name); 570 printf("\n"); 571 } 572} 573