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