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