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