2 * Device driver for Specialix range (SLXOS) of serial line multiplexors.
3 * SLXOS configuration and debug interface
5 * Copyright (C) 1990, 1992 Specialix International,
6 * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk>
7 * Copyright (C) 1995, Peter Wemm
9 * Derived from: SunOS 4.x version
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
30 static const char rcsid[] =
41 #include <sys/types.h>
42 #include <sys/param.h>
44 #include <sys/ioctl.h>
48 #include <dev/si/si.h>
49 #include <dev/si/sivar.h>
62 {"select", DBG_SELECT},
66 {"lstart", DBG_LSTART},
69 {"autoboot", DBG_AUTOBOOT},
70 {"download", DBG_DOWNLOAD},
76 static int alldev = 0;
78 void ccb_stat(int, char **);
79 void port_stat(int, char **);
80 void debug(int, char **);
84 int lvls2bits(char *);
85 void mstate(int, char **);
86 void nport(int, char **);
87 void onoff(int, char **, int, char *, char *, int);
88 int opencontrol(void);
90 void prusage(int, int);
91 void rxint(int, char **);
92 void txint(int, char **);
96 void (*o_func)(int, char **);
99 {"rxint_throttle", rxint},
100 {"int_throttle", txint},
103 {"ccbstat", ccb_stat},
104 {"portstat", port_stat},
109 void (*st_func)(int, char **);
121 #define U_STAT_PORT 6
126 "debug [[add|del|set debug_levels] | [off]]\n",
127 "int_throttle [newvalue]\n",
128 "rxint_throttle [newvalue]\n",
141 main(int argc, char **argv)
144 void (*func)(int, char **) = NULL;
149 if (strcmp(Devname, "-") == 0) {
156 n = sscanf(Devname, "%d:%d", &card, &port);
158 errx(1, "Devname must be in form card:port. eg: 0:7");
163 ctlfd = opencontrol();
170 for (op = opt; op->o_name; op++) {
171 if (strcmp(argv[1], op->o_name) == 0) {
190 fd = open(CONTROLDEV, O_RDWR|O_NDELAY);
192 err(1, "open on %s", CONTROLDEV);
197 * Print a usage message - this relies on U_DEBUG==0 and U_BOOT==1.
198 * Don't print the DEBUG usage string unless explicity requested.
201 prusage(int strn, int eflag)
206 fprintf(stderr, "usage: sicontrol %s", usage[1]);
207 fprintf(stderr, " sicontrol %s", usage[2]);
208 fprintf(stderr, " sicontrol %s", usage[3]);
209 fprintf(stderr, " sicontrol devname %s", usage[4]);
210 for (cp = &usage[5]; *cp; cp++)
211 fprintf(stderr, " sicontrol devname %s", *cp);
213 else if (strn >= 0 && strn <= U_MAX)
214 fprintf(stderr, "usage: sicontrol devname %s", usage[strn]);
216 fprintf(stderr, "sicontrol: usage ???\n");
220 /* print port status */
225 struct stat_list *stp;
229 printf("%s: ", alldev ? "ALL" : Devname);
230 acp = malloc(strlen(Devname) + 3);
231 memset(acp, ' ', strlen(Devname));
234 for (stp = stat_list; stp->st_func != NULL; stp++) {
241 (*stp->st_func)(-1, av);
247 * debug [[set|add|del debug_lvls] | [off]]
250 debug(int ac, char **av)
257 if (ioctl(ctlfd, TCSIGDBG_ALL, &tc.tc_dbglvl) < 0)
258 err(1, "TCSIGDBG_ALL on %s", Devname);
260 if (ioctl(ctlfd, TCSIGDBG_LEVEL, &tc) < 0)
261 err(1, "TCSIGDBG_LEVEL on %s", Devname);
266 printf("%s: debug levels - ", Devname);
267 prlevels(tc.tc_dbglvl);
270 if (strcmp(av[0], "off") == 0) {
277 level = lvls2bits(av[1]);
278 if (strcmp(av[0], "add") == 0)
279 tc.tc_dbglvl |= level;
280 else if (strcmp(av[0], "del") == 0)
281 tc.tc_dbglvl &= ~level;
282 else if (strcmp(av[0], "set") == 0)
283 tc.tc_dbglvl = level;
288 if (ioctl(ctlfd, TCSISDBG_ALL, &tc.tc_dbglvl) < 0)
289 err(1, "TCSISDBG_ALL on %s", Devname);
291 if (ioctl(ctlfd, TCSISDBG_LEVEL, &tc) < 0)
292 err(1, "TCSISDBG_LEVEL on %s", Devname);
297 rxint(int ac, char **av)
302 printf("%s: ", Devname);
304 if (ioctl(ctlfd, TCSIGRXIT, &tc) < 0)
306 printf("RX interrupt throttle: %d msec\n", tc.tc_int*10);
309 tc.tc_int = getnum(av[0]) / 10;
312 if (ioctl(ctlfd, TCSIRXIT, &tc) < 0)
313 err(1, "TCSIRXIT on %s at %d msec",
314 Devname, tc.tc_int*10);
322 txint(int ac, char **av)
328 printf("%s: ", Devname);
330 if (ioctl(ctlfd, TCSIGIT, &tc) < 0)
332 printf("aggregate interrupt throttle: %d\n", tc.tc_int);
335 tc.tc_int = getnum(av[0]);
336 if (ioctl(ctlfd, TCSIIT, &tc) < 0)
337 err(1, "TCSIIT on %s at %d", Devname, tc.tc_int);
345 onoff(int ac, char **av, int cmd, char *cmdstr, char *prstr, int usage)
350 if (strcmp(av[0], "on") == 0)
352 else if (strcmp(av[0], "off") == 0)
358 if (ioctl(ctlfd, cmd, &tc) < 0)
359 err(1, "%s on %s", cmdstr, Devname);
362 printf("%s: ", Devname);
364 printf("%s ", prstr);
373 mstate(int ac, char **av)
377 printf("%s: ", Devname);
381 prusage(U_MSTATE, 1);
383 if (ioctl(ctlfd, TCSISTATE, &tc) < 0)
384 err(1, "TCSISTATE on %s", Devname);
385 printf("modem bits state - (0x%x)", tc.tc_int);
386 if (tc.tc_int & IP_DCD) printf(" DCD");
387 if (tc.tc_int & IP_DTR) printf(" DTR");
388 if (tc.tc_int & IP_RTS) printf(" RTS");
393 nport(int ac, char **av)
399 if (ioctl(ctlfd, TCSIPORTS, &ports) < 0)
400 err(1, "TCSIPORTS on %s", Devname);
401 printf("SLXOS: total of %d ports\n", ports);
404 const char *s_stat(int stat)
407 case IDLE_OPEN: return "IDLE_OPEN";
408 case LOPEN: return "LOPEN";
409 case MOPEN: return "MOPEN";
410 case MPEND: return "MPEND";
411 case CONFIG: return "CONFIG";
412 case CLOSE: return "CLOSE";
413 case SBREAK: return "SBREAK";
414 case EBREAK: return "EBREAK";
415 case IDLE_CLOSE:return "IDLE_CLOSE";
416 case IDLE_BREAK:return "IDLE_BREAK";
417 case FCLOSE: return "FCLOSE";
418 case RESUME: return "RESUME";
419 case WFLUSH: return "WFLUSH";
420 case RFLUSH: return "RFLUSH";
421 default: return "??";
424 const char *s_mr1(int mr1)
426 static char msg[200];
428 sprintf(msg, "%dbit, %s, parity:[", 5 + (mr1 & MR1_8_BITS), mr1 & MR1_ODD ? "odd" : "even");
430 strcat(msg, "with;");
432 strcat(msg, "force;");
434 strcat(msg, "none;");
435 if (mr1 & MR1_SPECIAL)
436 strcat(msg, "special;");
437 strcpy(msg + strlen(msg) - 1, "]");
438 sprintf(msg + strlen(msg), ", err: %s", mr1 & MR1_BLOCK ? "block" : "none");
439 sprintf(msg + strlen(msg), ", cts: %s", mr1 & MR1_CTSCONT ? "auto" : "none");
442 const char *s_mr2(int mr2)
444 static char msg[200];
447 case MR2_1_STOP: strcpy(msg, "1stop"); break;
448 case MR2_2_STOP: strcpy(msg, "2stop"); break;
449 default: sprintf(msg, "??stop (0x%x)", mr2 & 0xf); break;
451 if (mr2 & MR2_RTSCONT) strcat(msg, ", rtscont");
452 if (mr2 & MR2_CTSCONT) strcat(msg, ", ctscont");
453 switch (mr2 & 0xc0) {
454 case MR2_NORMAL: strcat(msg, ", mode:normal"); break;
455 case MR2_AUTO: strcat(msg, ", mode:auto"); break;
456 case MR2_LOCAL: strcat(msg, ", mode:local"); break;
457 case MR2_REMOTE: strcat(msg, ", mode:remote"); break;
461 const char *s_clk(int clk)
464 case 0x0: return "75";
465 case 0x1: return "110/115200";
466 case 0x2: return "38400";
467 case 0x3: return "150";
468 case 0x4: return "300";
469 case 0x5: return "600";
470 case 0x6: return "1200";
471 case 0x7: return "2000";
472 case 0x8: return "2400";
473 case 0x9: return "4800";
474 case 0xa: return "7200";
475 case 0xb: return "9600";
476 case 0xc: return "19200";
477 case 0xd: return "57600";
478 case 0xe: return "?0xe";
479 case 0xf: return "?0xf";
481 return ("gcc sucks");
483 const char *s_op(int op)
485 static char msg[200];
487 sprintf(msg, "cts:%s", (op & OP_CTS) ? "on" : "off");
488 sprintf(msg + strlen(msg), ", dsr:%s", (op & OP_DSR) ? "on" : "off");
492 const char *s_ip(int ip)
494 static char msg[200];
496 sprintf(msg, "rts:%s", (ip & IP_RTS) ? "on" : "off");
497 sprintf(msg + strlen(msg), ", dcd:%s", (ip & IP_DCD) ? "on" : "off");
498 sprintf(msg + strlen(msg), ", dtr:%s", (ip & IP_DTR) ? "on" : "off");
499 sprintf(msg + strlen(msg), ", ri:%s", (ip & IP_RI) ? "on" : "off");
503 const char *s_state(int state)
505 return (state & ST_BREAK ? "break:on" : "break:off");
508 const char *s_prtcl(int pr)
510 static char msg[200];
512 sprintf(msg, "tx xon any:%s", (pr & SP_TANY) ? "on" : "off");
513 sprintf(msg + strlen(msg), ", tx xon/xoff:%s", (pr & SP_TXEN) ? "on" : "off");
514 sprintf(msg + strlen(msg), ", cooking:%s", (pr & SP_CEN) ? "on" : "off");
515 sprintf(msg + strlen(msg), ", rx xon/xoff:%s", (pr & SP_RXEN) ? "on" : "off");
516 sprintf(msg + strlen(msg), ", dcd/dsr check:%s", (pr & SP_DCEN) ? "on" : "off");
517 sprintf(msg + strlen(msg), ", parity check:%s", (pr & SP_PAEN) ? "on" : "off");
520 const char *s_break(int br)
522 static char msg[200];
524 sprintf(msg, "ignore rx brk:%s", (br & BR_IGN) ? "on" : "off");
525 sprintf(msg + strlen(msg), ", brk interrupt:%s", (br & BR_INT) ? "on" : "off");
526 sprintf(msg + strlen(msg), ", parmrking:%s", (br & BR_PARMRK) ? "on" : "off");
527 sprintf(msg + strlen(msg), ", parign:%s", (br & BR_PARIGN) ? "on" : "off");
534 static char msg[200];
537 /* MTA definitions, not TA */
538 if (xs & 0x01) strcat(msg, "TION "); /* Tx interrupts on (MTA only) */
539 if (xs & 0x02) strcat(msg, "RTSEN "); /* RTS FLOW enabled (MTA only) */
540 if (xs & 0x04) strcat(msg, "RTSLOW "); /* XOFF received (TA only) */
541 if (xs & 0x08) strcat(msg, "RXEN "); /* Rx XON/XOFF enabled */
542 if (xs & 0x10) strcat(msg, "ANYXO "); /* XOFF pending/sent or RTS dropped */
543 if (xs & 0x20) strcat(msg, "RXSE "); /* Rx XOFF sent */
544 if (xs & 0x40) strcat(msg, "NPEND "); /* Rx XON pending or XOFF pending */
545 if (xs & 0x40) strcat(msg, "FPEND "); /* Rx XOFF pending */
552 static char msg[200];
555 /* MTA definitions, not TA */
556 if (cs & 0x01) strcat(msg, "TEMR "); /* Tx empty requested (MTA only) */
557 if (cs & 0x02) strcat(msg, "TEMA "); /* Tx empty acked (MTA only) */
558 if (cs & 0x04) strcat(msg, "EN "); /* Cooking enabled (on MTA means port is also || */
559 if (cs & 0x08) strcat(msg, "HIGH "); /* Buffer previously hit high water */
560 if (cs & 0x10) strcat(msg, "CTSEN "); /* CTS automatic flow-control enabled */
561 if (cs & 0x20) strcat(msg, "DCDEN "); /* DCD/DTR checking enabled */
562 if (cs & 0x40) strcat(msg, "BREAK "); /* Break detected */
563 if (cs & 0x80) strcat(msg, "RTSEN "); /* RTS automatic flow control enabled (MTA only) */
568 ccb_stat(int ac, char **av)
571 #define CCB sip.tc_ccb
574 prusage(U_STAT_CCB, 1);
575 sip.tc_dev = tc.tc_dev;
576 if (ioctl(ctlfd, TCSI_CCB, &sip) < 0)
577 err(1, "TCSI_CCB on %s", Devname);
578 printf("%s: ", Devname);
580 /* WORD next - Next Channel */
581 /* WORD addr_uart - Uart address */
582 /* WORD module - address of module struct */
583 printf("\tuart_type 0x%x\n", CCB.type); /* BYTE type - Uart type */
585 printf("\tx_status 0x%x %s\n", CCB.x_status, s_xstat(CCB.x_status)); /* BYTE x_status - XON / XOFF status */
586 printf("\tc_status 0x%x %s\n", CCB.c_status, s_cstat(CCB.c_status)); /* BYTE c_status - cooking status */
587 printf("\thi_rxipos 0x%x\n", CCB.hi_rxipos); /* BYTE hi_rxipos - stuff into rx buff */
588 printf("\thi_rxopos 0x%x\n", CCB.hi_rxopos); /* BYTE hi_rxopos - stuff out of rx buffer */
589 printf("\thi_txopos 0x%x\n", CCB.hi_txopos); /* BYTE hi_txopos - Stuff into tx ptr */
590 printf("\thi_txipos 0x%x\n", CCB.hi_txipos); /* BYTE hi_txipos - ditto out */
591 printf("\thi_stat 0x%x %s\n", CCB.hi_stat, s_stat(CCB.hi_stat));/* BYTE hi_stat - Command register */
592 printf("\tdsr_bit 0x%x\n", CCB.dsr_bit); /* BYTE dsr_bit - Magic bit for DSR */
593 printf("\ttxon 0x%x\n", CCB.txon); /* BYTE txon - TX XON char */
594 printf("\ttxoff 0x%x\n", CCB.txoff); /* BYTE txoff - ditto XOFF */
595 printf("\trxon 0x%x\n", CCB.rxon); /* BYTE rxon - RX XON char */
596 printf("\trxoff 0x%x\n", CCB.rxoff); /* BYTE rxoff - ditto XOFF */
597 printf("\thi_mr1 0x%x %s\n", CCB.hi_mr1, s_mr1(CCB.hi_mr1)); /* BYTE hi_mr1 - mode 1 image */
598 printf("\thi_mr2 0x%x %s\n", CCB.hi_mr2, s_mr2(CCB.hi_mr2)); /* BYTE hi_mr2 - mode 2 image */
599 printf("\thi_csr 0x%x in:%s out:%s\n", CCB.hi_csr, s_clk(CCB.hi_csr >> 4), s_clk(CCB.hi_csr)); /* BYTE hi_csr - clock register */
600 printf("\thi_op 0x%x %s\n", CCB.hi_op, s_op(CCB.hi_op)); /* BYTE hi_op - Op control */
601 printf("\thi_ip 0x%x %s\n", CCB.hi_ip, s_ip(CCB.hi_ip)); /* BYTE hi_ip - Input pins */
602 printf("\thi_state 0x%x %s\n", CCB.hi_state, s_state(CCB.hi_state)); /* BYTE hi_state - status */
603 printf("\thi_prtcl 0x%x %s\n", CCB.hi_prtcl, s_prtcl(CCB.hi_prtcl)); /* BYTE hi_prtcl - Protocol */
604 printf("\thi_txon 0x%x\n", CCB.hi_txon); /* BYTE hi_txon - host copy tx xon stuff */
605 printf("\thi_txoff 0x%x\n", CCB.hi_txoff); /* BYTE hi_txoff - */
606 printf("\thi_rxon 0x%x\n", CCB.hi_rxon); /* BYTE hi_rxon - */
607 printf("\thi_rxoff 0x%x\n", CCB.hi_rxoff); /* BYTE hi_rxoff - */
608 printf("\tclose_prev 0x%x\n", CCB.close_prev); /* BYTE close_prev - Was channel previously closed */
609 printf("\thi_break 0x%x %s\n", CCB.hi_break, s_break(CCB.hi_break)); /* BYTE hi_break - host copy break process */
610 printf("\tbreak_state 0x%x\n", CCB.break_state); /* BYTE break_state - local copy ditto */
611 printf("\thi_mask 0x%x\n", CCB.hi_mask); /* BYTE hi_mask - Mask for CS7 etc. */
612 printf("\tmask_z280 0x%x\n", CCB.mask_z280); /* BYTE mask_z280 - Z280's copy */
613 /* BYTE res[0x60 - 36] - */
614 /* BYTE hi_txbuf[SLXOS_BUFFERSIZE] - */
615 /* BYTE hi_rxbuf[SLXOS_BUFFERSIZE] - */
616 /* BYTE res1[0xA0] - */
619 const char *sp_state(int st)
629 port_stat(int ac, char **av)
632 #define PRT sip.tc_siport
635 prusage(U_STAT_PORT, 1);
636 sip.tc_dev = tc.tc_dev;
637 if (ioctl(ctlfd, TCSI_PORT, &sip) < 0)
638 err(1, "TCSI_PORT on %s", Devname);
639 printf("%s: ", Devname);
641 printf("\tsp_pend 0x%x %s\n", PRT.sp_pend, s_stat(PRT.sp_pend));
642 printf("\tsp_last_hi_ip 0x%x %s\n", PRT.sp_last_hi_ip, s_ip(PRT.sp_last_hi_ip));
643 printf("\tsp_state 0x%x %s\n", PRT.sp_state, sp_state(PRT.sp_state));
644 printf("\tsp_delta_overflows 0x%d\n", PRT.sp_delta_overflows);
653 for (acp = tk; *acp; acp++)
655 *acp = tolower(*acp);
656 for (lvp = lv; lvp->lv_name; lvp++)
657 if (strcmp(lvp->lv_name, tk) == 0)
663 * Convert a string consisting of tokens separated by white space, commas
664 * or `|' into a bitfield - flag any unrecognised tokens.
673 while (sscanf(str, "%[^,| \t]", token) == 1) {
674 str += strlen(token);
675 while (isspace(*str) || *str==',' || *str=='|')
677 if (strcmp(token, "all") == 0)
679 if ((i = islevel(token)) == 0) {
680 warnx("unknown token '%s'", token);
700 errx(1, "%s is not a number", str);
721 for (lvp = lv; lvp->lv_name; lvp++)
723 printf(" %s", lvp->lv_name);