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