carp: add carp_group_demote_adj()
[dragonfly.git] / usr.sbin / sicontrol / sicontrol.c
CommitLineData
984263bc
MD
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.
1de703da
MD
32 *
33 * $FreeBSD: src/usr.sbin/sicontrol/sicontrol.c,v 1.12.2.1 2000/12/11 01:03:39 obrien Exp $
6ad6e49d 34 * $DragonFly: src/usr.sbin/sicontrol/sicontrol.c,v 1.6 2007/04/09 09:15:48 swildner Exp $
984263bc
MD
35 */
36
03d6a592 37#define _KERNEL_STRUCTURES
6ad6e49d
SW
38
39#include <sys/types.h>
40#include <sys/param.h>
41#include <sys/stat.h>
42#include <sys/ioctl.h>
43#include <sys/tty.h>
44
45#include <dev/serial/si/si.h>
46
984263bc
MD
47#include <ctype.h>
48#include <err.h>
49#include <fcntl.h>
50#include <paths.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
984263bc 54
6ad6e49d
SW
55#define U_DEBUG 0
56#define U_TXINT 1
57#define U_RXINT 2
58#define U_NPORT 3
59#define U_MSTATE 4
60#define U_STAT_CCB 5
61#define U_STAT_TTY 6
62#define U_MAX 7
63#define U_ALL -1
984263bc 64
6ad6e49d
SW
65static void ccb_stat(int, char **);
66static void debug(int, char **);
67static void dostat(void);
68static int getnum(char *);
69static int islevel(char *);
70static int lvls2bits(char *);
71static void mstate(int, char **);
72static void nport(int, char **);
73static int opencontrol(void);
74static void prlevels(int);
75static void prusage(int, int);
76static void rxint(int, char **);
77static void tty_stat(int, char **);
78static void txint(int, char **);
79
80static struct lv {
81 const char *lv_name;
984263bc
MD
82 int lv_bit;
83} lv[] = {
84 {"entry", DBG_ENTRY},
85 {"open", DBG_OPEN},
86 {"close", DBG_CLOSE},
87 {"read", DBG_READ},
88 {"write", DBG_WRITE},
89 {"param", DBG_PARAM},
90 {"modem", DBG_MODEM},
91 {"select", DBG_SELECT},
92 {"optim", DBG_OPTIM},
93 {"intr", DBG_INTR},
94 {"start", DBG_START},
95 {"lstart", DBG_LSTART},
96 {"ioctl", DBG_IOCTL},
97 {"fail", DBG_FAIL},
98 {"autoboot", DBG_AUTOBOOT},
99 {"download", DBG_DOWNLOAD},
100 {"drain", DBG_DRAIN},
101 {"poll", DBG_POLL},
102 {0, 0}
103};
104
6ad6e49d
SW
105static struct opt {
106 const char *o_name;
984263bc
MD
107 void (*o_func)(int, char **);
108} opt[] = {
109 {"debug", debug},
110 {"rxint_throttle", rxint},
111 {"int_throttle", txint},
112 {"nport", nport},
113 {"mstate", mstate},
114 {"ccbstat", ccb_stat},
115 {"ttystat", tty_stat},
116 {0, 0}
117};
118
6ad6e49d 119static struct stat_list {
984263bc
MD
120 void (*st_func)(int, char **);
121} stat_list[] = {
122 {mstate},
123 {0}
124};
125
6ad6e49d 126static const char *usagestr[] = {
984263bc
MD
127 "debug [[add|del|set debug_levels] | [off]]\n",
128 "int_throttle [newvalue]\n",
129 "rxint_throttle [newvalue]\n",
130 "nport\n",
131 "mstate\n",
132 "ccbstat\n",
133 "ttystat\n",
134 0
135};
136
6ad6e49d
SW
137static int alldev = 0;
138static int ctlfd;
139static char *Devname;
140static struct si_tcsi tc;
984263bc
MD
141
142int
143main(int argc, char **argv)
144{
145 struct opt *op;
146 void (*func)(int, char **) = NULL;
147
148 if (argc < 2)
149 prusage(U_ALL, 1);
150 Devname = argv[1];
151 if (strcmp(Devname, "-") == 0) {
152 alldev = 1;
153 } else {
154 sidev_t dev;
155 struct stat st;
156
157 if (strchr(Devname, '/') == NULL) {
158 char *acp = malloc(6 + strlen(Devname));
159 strcpy(acp, _PATH_DEV);
160 strcat(acp, Devname);
161 Devname = acp;
162 }
163 if (stat(Devname, &st) < 0)
164 errx(1, "can't stat %s", Devname);
165 dev.sid_card = SI_CARD(minor(st.st_rdev));
166 dev.sid_port = SI_PORT(minor(st.st_rdev));
6ad6e49d 167 dev.sid_control = 0;
984263bc
MD
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{
6ad6e49d 210 const char **cp;
984263bc
MD
211
212 if (strn == U_ALL) {
6ad6e49d
SW
213 fprintf(stderr, "usage: sicontrol %s", usagestr[1]);
214 fprintf(stderr, " sicontrol %s", usagestr[2]);
215 fprintf(stderr, " sicontrol %s", usagestr[3]);
216 fprintf(stderr, " sicontrol devname %s", usagestr[4]);
217 for (cp = &usagestr[5]; *cp; cp++)
984263bc
MD
218 fprintf(stderr, " sicontrol devname %s", *cp);
219 }
220 else if (strn >= 0 && strn <= U_MAX)
6ad6e49d 221 fprintf(stderr, "usage: sicontrol devname %s", usagestr[strn]);
984263bc
MD
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
6ad6e49d 352mstate(int ac, char **av __unused)
984263bc
MD
353{
354 switch (ac) {
355 case 0:
356 printf("%s: ", Devname);
357 case -1:
358 break;
359 default:
360 prusage(U_MSTATE, 1);
361 }
362 if (ioctl(ctlfd, TCSISTATE, &tc) < 0)
363 err(1, "TCSISTATE on %s", Devname);
364 printf("modem bits state - (0x%x)", tc.tc_int);
365 if (tc.tc_int & IP_DCD) printf(" DCD");
366 if (tc.tc_int & IP_DTR) printf(" DTR");
367 if (tc.tc_int & IP_RTS) printf(" RTS");
368 printf("\n");
369}
370
371void
6ad6e49d 372nport(int ac, char **av __unused)
984263bc
MD
373{
374 int ports;
375
376 if (ac != 0)
377 prusage(U_NPORT, 1);
378 if (ioctl(ctlfd, TCSIPORTS, &ports) < 0)
379 err(1, "TCSIPORTS on %s", Devname);
380 printf("SLXOS: total of %d ports\n", ports);
381}
382
383void
6ad6e49d 384ccb_stat(int ac, char **av __unused)
984263bc
MD
385{
386 struct si_pstat sip;
387#define CCB sip.tc_ccb
388
389 if (ac != 0)
390 prusage(U_STAT_CCB, 1);
391 sip.tc_dev = tc.tc_dev;
392 if (ioctl(ctlfd, TCSI_CCB, &sip) < 0)
393 err(1, "TCSI_CCB on %s", Devname);
394 printf("%s: ", Devname);
395
396 /* WORD next - Next Channel */
397 /* WORD addr_uart - Uart address */
398 /* WORD module - address of module struct */
399 printf("\tuart_type 0x%x\n", CCB.type); /* BYTE type - Uart type */
400 /* BYTE fill - */
401 printf("\tx_status 0x%x\n", CCB.x_status); /* BYTE x_status - XON / XOFF status */
402 printf("\tc_status 0x%x\n", CCB.c_status); /* BYTE c_status - cooking status */
403 printf("\thi_rxipos 0x%x\n", CCB.hi_rxipos); /* BYTE hi_rxipos - stuff into rx buff */
404 printf("\thi_rxopos 0x%x\n", CCB.hi_rxopos); /* BYTE hi_rxopos - stuff out of rx buffer */
405 printf("\thi_txopos 0x%x\n", CCB.hi_txopos); /* BYTE hi_txopos - Stuff into tx ptr */
406 printf("\thi_txipos 0x%x\n", CCB.hi_txipos); /* BYTE hi_txipos - ditto out */
407 printf("\thi_stat 0x%x\n", CCB.hi_stat); /* BYTE hi_stat - Command register */
408 printf("\tdsr_bit 0x%x\n", CCB.dsr_bit); /* BYTE dsr_bit - Magic bit for DSR */
409 printf("\ttxon 0x%x\n", CCB.txon); /* BYTE txon - TX XON char */
410 printf("\ttxoff 0x%x\n", CCB.txoff); /* BYTE txoff - ditto XOFF */
411 printf("\trxon 0x%x\n", CCB.rxon); /* BYTE rxon - RX XON char */
412 printf("\trxoff 0x%x\n", CCB.rxoff); /* BYTE rxoff - ditto XOFF */
413 printf("\thi_mr1 0x%x\n", CCB.hi_mr1); /* BYTE hi_mr1 - mode 1 image */
414 printf("\thi_mr2 0x%x\n", CCB.hi_mr2); /* BYTE hi_mr2 - mode 2 image */
415 printf("\thi_csr 0x%x\n", CCB.hi_csr); /* BYTE hi_csr - clock register */
416 printf("\thi_op 0x%x\n", CCB.hi_op); /* BYTE hi_op - Op control */
417 printf("\thi_ip 0x%x\n", CCB.hi_ip); /* BYTE hi_ip - Input pins */
418 printf("\thi_state 0x%x\n", CCB.hi_state); /* BYTE hi_state - status */
419 printf("\thi_prtcl 0x%x\n", CCB.hi_prtcl); /* BYTE hi_prtcl - Protocol */
420 printf("\thi_txon 0x%x\n", CCB.hi_txon); /* BYTE hi_txon - host copy tx xon stuff */
421 printf("\thi_txoff 0x%x\n", CCB.hi_txoff); /* BYTE hi_txoff - */
422 printf("\thi_rxon 0x%x\n", CCB.hi_rxon); /* BYTE hi_rxon - */
423 printf("\thi_rxoff 0x%x\n", CCB.hi_rxoff); /* BYTE hi_rxoff - */
424 printf("\tclose_prev 0x%x\n", CCB.close_prev); /* BYTE close_prev - Was channel previously closed */
425 printf("\thi_break 0x%x\n", CCB.hi_break); /* BYTE hi_break - host copy break process */
426 printf("\tbreak_state 0x%x\n", CCB.break_state); /* BYTE break_state - local copy ditto */
427 printf("\thi_mask 0x%x\n", CCB.hi_mask); /* BYTE hi_mask - Mask for CS7 etc. */
428 printf("\tmask_z280 0x%x\n", CCB.mask_z280); /* BYTE mask_z280 - Z280's copy */
429 /* BYTE res[0x60 - 36] - */
430 /* BYTE hi_txbuf[SLXOS_BUFFERSIZE] - */
431 /* BYTE hi_rxbuf[SLXOS_BUFFERSIZE] - */
432 /* BYTE res1[0xA0] - */
433}
434
435void
6ad6e49d 436tty_stat(int ac, char **av __unused)
984263bc
MD
437{
438 struct si_pstat sip;
439#define TTY sip.tc_tty
440
441 if (ac != 0)
442 prusage(U_STAT_TTY, 1);
443 sip.tc_dev = tc.tc_dev;
444 if (ioctl(ctlfd, TCSI_TTY, &sip) < 0)
445 err(1, "TCSI_TTY on %s", Devname);
446 printf("%s: ", Devname);
447
448 printf("\tt_outq.c_cc %d.\n", TTY.t_outq.c_cc); /* struct clist t_outq */
71dceec1 449 printf("\tt_dev %p\n", TTY.t_dev); /* t_dev */
984263bc
MD
450 printf("\tt_flags 0x%x\n", TTY.t_flags); /* int t_flags */
451 printf("\tt_state 0x%x\n", TTY.t_state); /* int t_state */
452 printf("\tt_ihiwat %d.\n", TTY.t_ihiwat); /* int t_ihiwat */
453 printf("\tt_ilowat %d.\n", TTY.t_ilowat); /* int t_ilowat */
454 printf("\tt_ohiwat %d.\n", TTY.t_ohiwat); /* int t_ohiwat */
455 printf("\tt_olowat %d.\n", TTY.t_olowat); /* int t_olowat */
456 printf("\tt_iflag 0x%x\n", TTY.t_iflag); /* t_iflag */
457 printf("\tt_oflag 0x%x\n", TTY.t_oflag); /* t_oflag */
458 printf("\tt_cflag 0x%x\n", TTY.t_cflag); /* t_cflag */
459 printf("\tt_lflag 0x%x\n", TTY.t_lflag); /* t_lflag */
460 printf("\tt_cc %p\n", (void *)TTY.t_cc); /* t_cc */
461 printf("\tt_termios.c_ispeed 0x%x\n", TTY.t_termios.c_ispeed); /* t_termios.c_ispeed */
462 printf("\tt_termios.c_ospeed 0x%x\n", TTY.t_termios.c_ospeed); /* t_termios.c_ospeed */
463}
464
465int
466islevel(char *tk)
467{
468 struct lv *lvp;
469 char *acp;
470
471 for (acp = tk; *acp; acp++)
472 if (isupper(*acp))
473 *acp = tolower(*acp);
474 for (lvp = lv; lvp->lv_name; lvp++)
475 if (strcmp(lvp->lv_name, tk) == 0)
476 return(lvp->lv_bit);
477 return(0);
478}
479
480/*
481 * Convert a string consisting of tokens separated by white space, commas
482 * or `|' into a bitfield - flag any unrecognised tokens.
483 */
484int
485lvls2bits(char *str)
486{
487 int i, bits = 0;
488 int errflag = 0;
489 char token[20];
490
491 while (sscanf(str, "%[^,| \t]", token) == 1) {
492 str += strlen(token);
493 while (isspace(*str) || *str==',' || *str=='|')
494 str++;
495 if (strcmp(token, "all") == 0)
496 return(0xffffffff);
497 if ((i = islevel(token)) == 0) {
498 warnx("unknown token '%s'", token);
499 errflag++;
500 } else
501 bits |= i;
502 }
503 if (errflag)
504 exit(1);
505
506 return(bits);
507}
508
509int
510getnum(char *str)
511{
512 int x;
513 char *acp = str;
514
515 x = 0;
516 while (*acp) {
517 if (!isdigit(*acp))
518 errx(1, "%s is not a number", str);
519 x *= 10;
520 x += (*acp - '0');
521 acp++;
522 }
523 return(x);
524}
525
526void
527prlevels(int x)
528{
529 struct lv *lvp;
530
531 switch (x) {
532 case 0:
533 printf("(none)\n");
534 break;
535 case 0xffffffff:
536 printf("all\n");
537 break;
538 default:
539 for (lvp = lv; lvp->lv_name; lvp++)
540 if (x & lvp->lv_bit)
541 printf(" %s", lvp->lv_name);
542 printf("\n");
543 }
544}