]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/sicontrol/sicontrol.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / sicontrol / sicontrol.c
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
30 static const char rcsid[] =
31   "$FreeBSD$";
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
51 struct 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
76 static int alldev = 0;
77
78 void ccb_stat(int, char **);
79 void port_stat(int, char **);
80 void debug(int, char **);
81 void dostat(void);
82 int getnum(char *);
83 int islevel(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);
89 void prlevels(int);
90 void prusage(int, int);
91 void rxint(int, char **);
92 void txint(int, char **);
93
94 struct 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         {"portstat",            port_stat},
105         {0,                     0}
106 };
107
108 struct 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_PORT     6
122
123 #define U_MAX           7
124 #define U_ALL           -1
125 char *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         "portstat\n",
133         0
134 };
135
136 int ctlfd;
137 char *Devname;
138 struct si_tcsi tc;
139
140 int
141 main(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                 int n;
154                 int card, port;
155
156                 n = sscanf(Devname, "%d:%d", &card, &port);
157                 if (n != 2)
158                         errx(1, "Devname must be in form card:port.  eg: 0:7");
159                 dev.sid_card = card;
160                 dev.sid_port = port;
161                 tc.tc_dev = dev;
162         }
163         ctlfd = opencontrol();
164         if (argc == 2) {
165                 dostat();
166                 exit(0);
167         }
168
169         argc--; argv++;
170         for (op = opt; op->o_name; op++) {
171                 if (strcmp(argv[1], op->o_name) == 0) {
172                         func = op->o_func;
173                         break;
174                 }
175         }
176         if (func == NULL)
177                 prusage(U_ALL, 1);
178
179         argc -= 2;
180         argv += 2;
181         (*func)(argc, argv);
182         exit(0);
183 }
184
185 int
186 opencontrol(void)
187 {
188         int fd;
189
190         fd = open(CONTROLDEV, O_RDWR|O_NDELAY);
191         if (fd < 0)
192                 err(1, "open on %s", CONTROLDEV);
193         return(fd);
194 }
195
196 /*
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.
199  */
200 void
201 prusage(int strn, int eflag)
202 {
203         char **cp;
204
205         if (strn == U_ALL) {
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);
212         }
213         else if (strn >= 0 && strn <= U_MAX)
214                 fprintf(stderr, "usage: sicontrol devname %s", usage[strn]);
215         else
216                 fprintf(stderr, "sicontrol: usage ???\n");
217         exit(eflag);
218 }
219
220 /* print port status */
221 void
222 dostat(void)
223 {
224         char *av[1], *acp;
225         struct stat_list *stp;
226         struct si_tcsi stc;
227         int donefirst = 0;
228
229         printf("%s: ", alldev ? "ALL" : Devname);
230         acp = malloc(strlen(Devname) + 3);
231         memset(acp, ' ', strlen(Devname));
232         strcat(acp, "  ");
233         stc = tc;
234         for (stp = stat_list; stp->st_func != NULL; stp++) {
235                 if (donefirst)
236                         fputs(acp, stdout);
237                 else
238                         donefirst++;
239                 av[0] = NULL;
240                 tc = stc;
241                 (*stp->st_func)(-1, av);
242         }
243 }
244
245 /*
246  * debug
247  * debug [[set|add|del debug_lvls] | [off]]
248  */
249 void
250 debug(int ac, char **av)
251 {
252         int level;
253
254         if (ac > 2)
255                 prusage(U_DEBUG, 1);
256         if (alldev) {
257                 if (ioctl(ctlfd, TCSIGDBG_ALL, &tc.tc_dbglvl) < 0)
258                         err(1, "TCSIGDBG_ALL on %s", Devname);
259         } else {
260                 if (ioctl(ctlfd, TCSIGDBG_LEVEL, &tc) < 0)
261                         err(1, "TCSIGDBG_LEVEL on %s", Devname);
262         }
263
264         switch (ac) {
265         case 0:
266                 printf("%s: debug levels - ", Devname);
267                 prlevels(tc.tc_dbglvl);
268                 return;
269         case 1:
270                 if (strcmp(av[0], "off") == 0) {
271                         tc.tc_dbglvl = 0;
272                         break;
273                 }
274                 prusage(U_DEBUG, 1);
275                 /* no return */
276         case 2:
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;
284                 else
285                         prusage(U_DEBUG, 1);
286         }
287         if (alldev) {
288                 if (ioctl(ctlfd, TCSISDBG_ALL, &tc.tc_dbglvl) < 0)
289                         err(1, "TCSISDBG_ALL on %s", Devname);
290         } else {
291                 if (ioctl(ctlfd, TCSISDBG_LEVEL, &tc) < 0)
292                         err(1, "TCSISDBG_LEVEL on %s", Devname);
293         }
294 }
295
296 void
297 rxint(int ac, char **av)
298 {
299         tc.tc_port = 0;
300         switch (ac) {
301         case 0:
302                 printf("%s: ", Devname);
303         case -1:
304                 if (ioctl(ctlfd, TCSIGRXIT, &tc) < 0)
305                         err(1, "TCSIGRXIT");
306                 printf("RX interrupt throttle: %d msec\n", tc.tc_int*10);
307                 break;
308         case 1:
309                 tc.tc_int = getnum(av[0]) / 10;
310                 if (tc.tc_int == 0)
311                         tc.tc_int = 1;
312                 if (ioctl(ctlfd, TCSIRXIT, &tc) < 0)
313                         err(1, "TCSIRXIT on %s at %d msec",
314                                 Devname, tc.tc_int*10);
315                 break;
316         default:
317                 prusage(U_RXINT, 1);
318         }
319 }
320
321 void
322 txint(int ac, char **av)
323 {
324
325         tc.tc_port = 0;
326         switch (ac) {
327         case 0:
328                 printf("%s: ", Devname);
329         case -1:
330                 if (ioctl(ctlfd, TCSIGIT, &tc) < 0)
331                         err(1, "TCSIGIT");
332                 printf("aggregate interrupt throttle: %d\n", tc.tc_int);
333                 break;
334         case 1:
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);
338                 break;
339         default:
340                 prusage(U_TXINT, 1);
341         }
342 }
343
344 void
345 onoff(int ac, char **av, int cmd, char *cmdstr, char *prstr, int usage)
346 {
347         if (ac > 1)
348                 prusage(usage, 1);
349         if (ac == 1) {
350                 if (strcmp(av[0], "on") == 0)
351                         tc.tc_int = 1;
352                 else if (strcmp(av[0], "off") == 0)
353                         tc.tc_int = 0;
354                 else
355                         prusage(usage, 1);
356         } else
357                 tc.tc_int = -1;
358         if (ioctl(ctlfd, cmd, &tc) < 0)
359                 err(1, "%s on %s", cmdstr, Devname);
360         switch (ac) {
361         case 0:
362                 printf("%s: ", Devname);
363         case -1:
364                 printf("%s ", prstr);
365                 if (tc.tc_int)
366                         printf("on\n");
367                 else
368                         printf("off\n");
369         }
370 }
371
372 void
373 mstate(int ac, char **av)
374 {
375         switch (ac) {
376         case 0:
377                 printf("%s: ", Devname);
378         case -1:
379                 break;
380         default:
381                 prusage(U_MSTATE, 1);
382         }
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");
389         printf("\n");
390 }
391
392 void
393 nport(int ac, char **av)
394 {
395         int ports;
396
397         if (ac != 0)
398                 prusage(U_NPORT, 1);
399         if (ioctl(ctlfd, TCSIPORTS, &ports) < 0)
400                 err(1, "TCSIPORTS on %s", Devname);
401         printf("SLXOS: total of %d ports\n", ports);
402 }
403
404 const char *s_stat(int stat)
405 {
406         switch (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 "??";
422         }
423 }
424 const char *s_mr1(int mr1)
425 {
426         static char msg[200];
427
428         sprintf(msg, "%dbit, %s, parity:[", 5 + (mr1 & MR1_8_BITS), mr1 & MR1_ODD ? "odd" : "even");
429         if (mr1 & MR1_WITH)
430                 strcat(msg, "with;");
431         if (mr1 & MR1_FORCE)
432                 strcat(msg, "force;");
433         if (mr1 & MR1_NONE)
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");
440         return (msg);
441 }
442 const char *s_mr2(int mr2)
443 {
444         static char msg[200];
445
446         switch (mr2 & 0xf) {
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;
450         }
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;
458         }
459         return (msg);
460 }
461 const char *s_clk(int clk)
462 {
463         switch (clk & 0xf) {
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";
480         }
481         return ("gcc sucks");
482 }
483 const char *s_op(int op)
484 {
485         static char msg[200];
486         
487         sprintf(msg, "cts:%s", (op & OP_CTS) ? "on" : "off");
488         sprintf(msg + strlen(msg), ", dsr:%s", (op & OP_DSR) ? "on" : "off");
489         return (msg);
490 }
491
492 const char *s_ip(int ip)
493 {
494         static char msg[200];
495         
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");
500         return (msg);
501 }
502
503 const char *s_state(int state)
504 {
505         return (state & ST_BREAK ? "break:on" : "break:off");
506 }
507
508 const char *s_prtcl(int pr)
509 {
510         static char msg[200];
511
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");
518         return (msg);
519 }
520 const char *s_break(int br)
521 {
522         static char msg[200];
523
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");
528         return (msg);
529 }
530
531 const char *
532 s_xstat(int xs)
533 {
534         static char msg[200];
535
536         msg[0] = 0;
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 */
546         return (msg);
547 }
548
549 const char *
550 s_cstat(int cs)
551 {
552         static char msg[200];
553
554         msg[0] = 0;
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) */
564         return (msg);
565 }
566
567 void
568 ccb_stat(int ac, char **av)
569 {
570         struct si_pstat sip;
571 #define CCB     sip.tc_ccb
572
573         if (ac != 0)
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);
579
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 */
584                                                         /* BYTE fill - */
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] - */
617 }
618
619 const char *sp_state(int st)
620 {
621
622         if (st & SS_LSTART)
623                 return("lstart ");
624         else
625                 return("");
626 }
627
628 void
629 port_stat(int ac, char **av)
630 {
631         struct si_pstat sip;
632 #define PRT     sip.tc_siport
633
634         if (ac != 0)
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);
640
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);
645 }
646
647 int
648 islevel(char *tk)
649 {
650         struct lv *lvp;
651         char *acp;
652
653         for (acp = tk; *acp; acp++)
654                 if (isupper(*acp))
655                         *acp = tolower(*acp);
656         for (lvp = lv; lvp->lv_name; lvp++)
657                 if (strcmp(lvp->lv_name, tk) == 0)
658                         return(lvp->lv_bit);
659         return(0);
660 }
661
662 /*
663  * Convert a string consisting of tokens separated by white space, commas
664  * or `|' into a bitfield - flag any unrecognised tokens.
665  */
666 int
667 lvls2bits(char *str)
668 {
669         int i, bits = 0;
670         int errflag = 0;
671         char token[20];
672
673         while (sscanf(str, "%[^,| \t]", token) == 1) {
674                 str += strlen(token);
675                 while (isspace(*str) || *str==',' || *str=='|')
676                         str++;
677                 if (strcmp(token, "all") == 0)
678                         return(0xffffffff);
679                 if ((i = islevel(token)) == 0) {
680                         warnx("unknown token '%s'", token);
681                         errflag++;
682                 } else
683                         bits |= i;
684         }
685         if (errflag)
686                 exit(1);
687
688         return(bits);
689 }
690
691 int
692 getnum(char *str)
693 {
694         int x;
695         char *acp = str;
696
697         x = 0;
698         while (*acp) {
699                 if (!isdigit(*acp))
700                         errx(1, "%s is not a number", str);
701                 x *= 10;
702                 x += (*acp - '0');
703                 acp++;
704         }
705         return(x);
706 }
707
708 void
709 prlevels(int x)
710 {
711         struct lv *lvp;
712
713         switch (x) {
714         case 0:
715                 printf("(none)\n");
716                 break;
717         case 0xffffffff:
718                 printf("all\n");
719                 break;
720         default:
721                 for (lvp = lv; lvp->lv_name; lvp++)
722                         if (x & lvp->lv_bit)
723                                 printf(" %s", lvp->lv_name);
724                 printf("\n");
725         }
726 }