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