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$";
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 port_stat(int, char **);
80void debug(int, char **);
81void dostat(void);
82int getnum(char *);
83int islevel(char *);
84int lvls2bits(char *);
85void mstate(int, char **);
86void nport(int, char **);
87void onoff(int, char **, int, char *, char *, int);
88int opencontrol(void);
89void prlevels(int);
90void prusage(int, int);
91void rxint(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	{"portstat",		port_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_PORT	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	"portstat\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		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
185int
186opencontrol(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 */
200void
201prusage(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 */
221void
222dostat(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 */
249void
250debug(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
296void
297rxint(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
321void
322txint(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
344void
345onoff(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
372void
373mstate(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
392void
393nport(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
404const 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}
424const 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}
442const 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}
461const 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}
483const 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
492const 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
503const char *s_state(int state)
504{
505	return (state & ST_BREAK ? "break:on" : "break:off");
506}
507
508const 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}
520const 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
531const char *
532s_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
549const char *
550s_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
567void
568ccb_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
619const char *sp_state(int st)
620{
621
622	if (st & SS_LSTART)
623		return("lstart ");
624	else
625		return("");
626}
627
628void
629port_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
647int
648islevel(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 */
666int
667lvls2bits(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
691int
692getnum(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
708void
709prlevels(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