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