xref: /NextBSD/usr.sbin/sicontrol/sicontrol.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
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
main(int argc,char ** argv)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
opencontrol(void)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
prusage(int strn,int eflag)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
dostat(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
debug(int ac,char ** av)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
rxint(int ac,char ** av)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
txint(int ac,char ** av)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
onoff(int ac,char ** av,int cmd,char * cmdstr,char * prstr,int usage)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
mstate(int ac,char ** av)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
nport(int ac,char ** av)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 
s_stat(int stat)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 }
s_mr1(int mr1)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 }
s_mr2(int mr2)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 }
s_clk(int clk)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 }
s_op(int op)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 
s_ip(int ip)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 
s_state(int state)503 const char *s_state(int state)
504 {
505 	return (state & ST_BREAK ? "break:on" : "break:off");
506 }
507 
s_prtcl(int pr)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 }
s_break(int br)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 *
s_xstat(int xs)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 *
s_cstat(int cs)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
ccb_stat(int ac,char ** av)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 
sp_state(int st)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
port_stat(int ac,char ** av)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
islevel(char * tk)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
lvls2bits(char * str)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
getnum(char * str)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
prlevels(int x)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 }
727