]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - usr.sbin/sicontrol/sicontrol.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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  * 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
30 static const char rcsid[] =
31   "$FreeBSD$";
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
51 struct 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
76 static int alldev = 0;
77
78 void ccb_stat(int, char **);
79 void debug(int, char **);
80 void dostat(void);
81 int getnum(char *);
82 int islevel(char *);
83 int lvls2bits(char *);
84 void mstate(int, char **);
85 void nport(int, char **);
86 void onoff(int, char **, int, char *, char *, int);
87 int opencontrol(void);
88 void prlevels(int);
89 void prusage(int, int);
90 void rxint(int, char **);
91 void tty_stat(int, char **);
92 void txint(int, char **);
93
94 struct 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
108 struct 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
125 char *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
136 int ctlfd;
137 char *Devname;
138 struct si_tcsi tc;
139
140 int
141 main(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
193 int
194 opencontrol(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  */
208 void
209 prusage(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 */
229 void
230 dostat(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  */
257 void
258 debug(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
304 void
305 rxint(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
329 void
330 txint(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
352 void
353 onoff(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
380 void
381 mstate(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
400 void
401 nport(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
412 void
413 ccb_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
464 void
465 tty_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
494 int
495 islevel(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  */
513 int
514 lvls2bits(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
538 int
539 getnum(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
555 void
556 prlevels(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 }