Merge branch 'vendor/GCC'
[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.6 2007/04/09 09:15:48 swildner Exp $
35  */
36
37 #define _KERNEL_STRUCTURES
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
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>
54
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
64
65 static void     ccb_stat(int, char **);
66 static void     debug(int, char **);
67 static void     dostat(void);
68 static int      getnum(char *);
69 static int      islevel(char *);
70 static int      lvls2bits(char *);
71 static void     mstate(int, char **);
72 static void     nport(int, char **);
73 static int      opencontrol(void);
74 static void     prlevels(int);
75 static void     prusage(int, int);
76 static void     rxint(int, char **);
77 static void     tty_stat(int, char **);
78 static void     txint(int, char **);
79
80 static struct lv {
81         const char *lv_name;
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
105 static struct opt {
106         const char *o_name;
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
119 static struct stat_list {
120         void (*st_func)(int, char **);
121 } stat_list[] = {
122         {mstate},
123         {0}
124 };
125
126 static const char *usagestr[] = {
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 static int alldev = 0;
138 static int ctlfd;
139 static char *Devname;
140 static struct si_tcsi tc;
141
142 int
143 main(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));
167                 dev.sid_control = 0;
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
192 int
193 opencontrol(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  */
207 void
208 prusage(int strn, int eflag)
209 {
210         const char **cp;
211
212         if (strn == U_ALL) {
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++)
218                         fprintf(stderr, "       sicontrol devname %s", *cp);
219         }
220         else if (strn >= 0 && strn <= U_MAX)
221                 fprintf(stderr, "usage: sicontrol devname %s", usagestr[strn]);
222         else
223                 fprintf(stderr, "sicontrol: usage ???\n");
224         exit(eflag);
225 }
226
227 /* print port status */
228 void
229 dostat(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  */
256 void
257 debug(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
303 void
304 rxint(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
328 void
329 txint(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
351 void
352 mstate(int ac, char **av __unused)
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
371 void
372 nport(int ac, char **av __unused)
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
383 void
384 ccb_stat(int ac, char **av __unused)
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
435 void
436 tty_stat(int ac, char **av __unused)
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 */
449         printf("\tt_dev %p\n", TTY.t_dev);              /* t_dev */
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
465 int
466 islevel(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  */
484 int
485 lvls2bits(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
509 int
510 getnum(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
526 void
527 prlevels(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 }