Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / stallion / stlstats / stlstats.c
1 /*****************************************************************************/
2
3 /*
4  * stlstats.c  -- stallion intelligent multiport stats display.
5  *
6  * Copyright (c) 1994-1998 Greg Ungerer (gerg@stallion.oz.au).
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by Greg Ungerer.
20  * 4. Neither the name of the author nor the names of any co-contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 /*****************************************************************************/
38
39 #ifndef lint
40 static const char rcsid[] =
41   "$FreeBSD: src/usr.sbin/stallion/stlstats/stlstats.c,v 1.9.2.1 2001/08/30 12:29:58 murray Exp $";
42 #endif /* not lint */
43
44 #include <err.h>
45 #include <fcntl.h>
46 #include <ncurses.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include <sys/stat.h>
53 #include <sys/ioctl.h>
54
55 #include <machine/cdk.h>
56 #include <machine/comstats.h>
57
58 /*****************************************************************************/
59
60 char    *version = "2.0.0";
61 char    *defdevice = "/dev/staliomem0";
62
63 char    *ctrldevice;
64 int     ctrlfd;
65 int     displaybrdnr = 0;
66 int     displaypanelnr = 0;
67 int     displayportnr = 0;
68 int     displayportbank = 0;
69
70 #define MAXBRDS         8
71 #define MAXPORTS        32
72
73 combrd_t        brdstats;
74 comstats_t      stats[MAXPORTS];
75
76 char    *line = "                                                                                ";
77
78 /*****************************************************************************/
79
80 /*
81  *      Declare internal function prototypes here.
82  */
83 static void     usage(void);
84 void    useportdevice(char *devname);
85 void    localexit(int nr);
86 void    menuport();
87 void    displayport();
88 void    menuallports();
89 void    displayallports();
90 void    getallstats();
91 void    getbrdstats();
92 void    clearportstats();
93 void    clearallstats();
94
95 /*****************************************************************************/
96
97 static void usage()
98 {
99         fprintf(stderr, "%s\n%s\n",
100         "usage: stlstats [-hVi] [-c control-device] [-b board-number]",
101         "                [-p port-number] [-d port-device]");
102         exit(0);
103 }
104
105 /*****************************************************************************/
106
107 void useportdevice(char *devname)
108 {
109         struct stat     statinfo;
110         int             portnr, portcnt;
111         int             i;
112
113         if (stat(devname, &statinfo) < 0)
114                 errx(1, "port device %s does not exist", devname);
115         if ((statinfo.st_mode & S_IFMT) != S_IFCHR)
116                 errx(1, "port device %s is not a char device", devname);
117
118         displaybrdnr = (statinfo.st_rdev & 0x00700000) >> 20;
119         portnr = (statinfo.st_rdev & 0x1f) |
120                 ((statinfo.st_rdev & 0x00010000) >> 11);
121         getbrdstats();
122         if (brdstats.ioaddr == 0)
123                 errx(1, "device %s does not exist", devname);
124
125         for (portcnt = 0, i = 0; (i < brdstats.nrpanels); i++) {
126                 if ((portnr >= portcnt) &&
127                     (portnr < (portcnt + brdstats.panels[i].nrports)))
128                         break;
129                 portcnt += brdstats.panels[i].nrports;
130         }
131         if (i >= brdstats.nrpanels)
132                 errx(1, "device %s does not exist", devname);
133         displaypanelnr = i;
134         displayportnr = portnr - portcnt;
135         if (displayportnr >= 16)
136                 displayportbank = 16;
137 }
138
139 /*****************************************************************************/
140
141 /*
142  *      Get the board stats for the current display board.
143  */
144
145 void getbrdstats()
146 {
147         brdstats.brd = displaybrdnr;
148         if (ioctl(ctrlfd, COM_GETBRDSTATS, &brdstats) < 0)
149                 memset((combrd_t *) &brdstats, 0, sizeof(combrd_t));
150 }
151
152 /*****************************************************************************/
153
154 /*
155  *      Zero out stats for the current display port.
156  */
157
158 void clearportstats()
159 {
160         stats[displayportnr].brd = displaybrdnr;
161         stats[displayportnr].panel = displaypanelnr;
162         stats[displayportnr].port = displayportnr;
163         ioctl(ctrlfd, COM_CLRPORTSTATS, &stats[displayportnr]);
164 }
165
166 /*****************************************************************************/
167
168 /*
169  *      Zero out all stats for all ports on all boards.
170  */
171
172 void clearallstats()
173 {
174         int     brdnr, panelnr, portnr;
175
176         for (brdnr = 0; (brdnr < MAXBRDS); brdnr++) {
177                 for (panelnr = 0; (panelnr < COM_MAXPANELS); panelnr++) {
178                         for (portnr = 0; (portnr < MAXPORTS); portnr++) {
179                                 stats[0].brd = brdnr;
180                                 stats[0].panel = panelnr;
181                                 stats[0].port = portnr;
182                                 ioctl(ctrlfd, COM_CLRPORTSTATS, &stats[0]);
183                         }
184                 }
185         }
186 }
187
188 /*****************************************************************************/
189
190 /*
191  *      Get the stats for the current display board/panel.
192  */
193
194 void getallstats()
195 {
196         int     i;
197
198         for (i = 0; (i < brdstats.panels[displaypanelnr].nrports); i++) {
199                 stats[i].brd = displaybrdnr;
200                 stats[i].panel = displaypanelnr;
201                 stats[i].port = i;
202                 if (ioctl(ctrlfd, COM_GETPORTSTATS, &stats[i]) < 0) {
203                         warn("ioctl(COM_GETPORTSTATS) failed");
204                         localexit(1);
205                 }
206         }
207 }
208
209 /*****************************************************************************/
210
211 /*
212  *      Display the per ports stats screen.
213  */
214
215 void displayport()
216 {
217         mvprintw(0, 0, "STALLION SERIAL PORT STATISTICS");
218         mvprintw(2, 0,
219                 "Board=%d  Type=%d  HwID=%02x  State=%06x  TotalPorts=%d",
220                 displaybrdnr, brdstats.type, brdstats.hwid, brdstats.state,
221                 brdstats.nrports);
222         mvprintw(3, 0, "Panel=%d  HwID=%02x  Ports=%d", displaypanelnr,
223                 brdstats.panels[displaypanelnr].hwid,
224                 brdstats.panels[displaypanelnr].nrports);
225
226         attron(A_REVERSE);
227         mvprintw(5, 0, line);
228         mvprintw(5, 0, "Port=%d ", displayportnr);
229         attroff(A_REVERSE);
230
231         mvprintw(7,  0, "STATE:      State=%08x", stats[displayportnr].state);
232         mvprintw(7, 29, "Tty=%08x", stats[displayportnr].ttystate);
233         mvprintw(7, 47, "Flags=%08x", stats[displayportnr].flags);
234         mvprintw(7, 65, "HwID=%02x", stats[displayportnr].hwid);
235
236         mvprintw(8,  0, "CONFIG:     Cflag=%08x", stats[displayportnr].cflags);
237         mvprintw(8, 29, "Iflag=%08x", stats[displayportnr].iflags);
238         mvprintw(8, 47, "Oflag=%08x", stats[displayportnr].oflags);
239         mvprintw(8, 65, "Lflag=%08x", stats[displayportnr].lflags);
240
241         mvprintw(10,  0, "TX DATA:    Total=%d", stats[displayportnr].txtotal);
242         mvprintw(10, 29, "Buffered=%d      ", stats[displayportnr].txbuffered);
243         mvprintw(11,  0, "RX DATA:    Total=%d", stats[displayportnr].rxtotal);
244         mvprintw(11, 29, "Buffered=%d      ", stats[displayportnr].rxbuffered);
245         mvprintw(12,  0, "RX ERRORS:  Parity=%d", stats[displayportnr].rxparity);
246         mvprintw(12, 29, "Framing=%d", stats[displayportnr].rxframing);
247         mvprintw(12, 47, "Overrun=%d", stats[displayportnr].rxoverrun);
248         mvprintw(12, 65, "Lost=%d", stats[displayportnr].rxlost);
249
250         mvprintw(14,  0, "FLOW TX:    Xoff=%d", stats[displayportnr].txxoff);
251         mvprintw(14, 29, "Xon=%d", stats[displayportnr].txxon);
252 #if 0
253         mvprintw(14, 47, "CTSoff=%d", stats[displayportnr].txctsoff);
254         mvprintw(14, 65, "CTSon=%d", stats[displayportnr].txctson);
255 #endif
256         mvprintw(15,  0, "FLOW RX:    Xoff=%d", stats[displayportnr].rxxoff);
257         mvprintw(15, 29, "Xon=%d", stats[displayportnr].rxxon);
258         mvprintw(15, 47, "RTSoff=%d", stats[displayportnr].rxrtsoff);
259         mvprintw(15, 65, "RTSon=%d", stats[displayportnr].rxrtson);
260
261         mvprintw(17,  0, "OTHER:      TXbreaks=%d",
262                 stats[displayportnr].txbreaks);
263         mvprintw(17, 29, "RXbreaks=%d", stats[displayportnr].rxbreaks);
264         mvprintw(17, 47, "Modem=%d", stats[displayportnr].modem);
265
266         mvprintw(19, 0, "SIGNALS:    DCD=%d    DTR=%d    CTS=%d    RTS=%d    "
267                 "DSR=%d    RI=%d",
268                 (stats[displayportnr].signals & TIOCM_CD) ? 1 : 0,
269                 (stats[displayportnr].signals & TIOCM_DTR) ? 1 : 0,
270                 (stats[displayportnr].signals & TIOCM_CTS) ? 1 : 0,
271                 (stats[displayportnr].signals & TIOCM_RTS) ? 1 : 0,
272                 (stats[displayportnr].signals & TIOCM_DSR) ? 1 : 0,
273                 (stats[displayportnr].signals & TIOCM_RI) ? 1 : 0);
274
275         attron(A_REVERSE);
276         mvprintw(22, 0, line);
277         attroff(A_REVERSE);
278
279         mvprintw(24, 19, "(q=Quit,0123456789abcdef=Port,Z=ZeroStats)");
280         refresh();
281 }
282
283 /*****************************************************************************/
284
285 /*
286  *      Continuously update and display the per ports stats screen.
287  *      Also checks for keyboard input, and processes it as appropriate.
288  */
289
290 void menuport()
291 {
292         int     ch, done;
293
294         clear();
295         done = 0;
296
297         while ((ch = getch()) != 27) {
298                 switch (ch) {
299                 case ERR:
300                         break;
301                 case '\f':
302                         refresh();
303                         break;
304                 case 'a':
305                 case 'b':
306                 case 'c':
307                 case 'd':
308                 case 'e':
309                 case 'f':
310                         ch = (ch - 'a' + '0' + 10);
311                         /* fall thru */
312                 case '0':
313                 case '1':
314                 case '2':
315                 case '3':
316                 case '4':
317                 case '5':
318                 case '6':
319                 case '7':
320                 case '8':
321                 case '9':
322                         ch -= '0';
323                         if (ch >= brdstats.panels[displaypanelnr].nrports) {
324                                 beep();
325                         } else {
326                                 displayportnr = displayportbank + ch;
327                                 clear();
328                         }
329                         break;
330                 case 'Z':
331                         clearportstats();
332                         clear();
333                         break;
334                 case 'q':
335                         done = 1;
336                         break;
337                 default:
338                         beep();
339                         break;
340                 }
341
342                 if (done)
343                         break;
344
345                 getallstats();
346                 displayport();
347         }
348 }
349
350 /*****************************************************************************/
351
352 /*
353  *      Display the all ports stats screen.
354  */
355
356 void displayallports()
357 {
358         int     i, nrports, portnr;;
359
360         nrports = brdstats.panels[displaypanelnr].nrports;
361
362         mvprintw(0, 0, "STALLION SERIAL PORT STATISTICS");
363         mvprintw(2, 0, "Board=%d  Type=%d  HwID=%02x  State=%06x  TotalPorts=%d",
364                 displaybrdnr, brdstats.type, brdstats.hwid, brdstats.state,
365                 brdstats.nrports);
366         mvprintw(3, 0, "Panel=%d  HwID=%02x  Ports=%d", displaypanelnr,
367                 brdstats.panels[displaypanelnr].hwid, nrports);
368
369         attron(A_REVERSE);
370         mvprintw(5, 0, "Port  State   Tty    Flags  Cflag Iflag Oflag Lflag "
371                 "Sigs    TX Total   RX Total ");
372         attroff(A_REVERSE);
373
374         if (nrports > 0) {
375                 if (nrports > 16)
376                         nrports = 16;
377                 portnr = displayportbank;
378                 for (i = 0; (i < nrports); i++, portnr++) {
379                         mvprintw((6 + i), 1, "%2d", portnr);
380                         mvprintw((6 + i), 5, "%06x", stats[portnr].state);
381                         mvprintw((6 + i), 12, "%06x", stats[portnr].ttystate);
382                         mvprintw((6 + i), 19, "%08x", stats[portnr].flags);
383                         mvprintw((6 + i), 28, "%05x", stats[portnr].cflags);
384                         mvprintw((6 + i), 34, "%05x", stats[portnr].iflags);
385                         mvprintw((6 + i), 40, "%05x", stats[portnr].oflags);
386                         mvprintw((6 + i), 46, "%05x", stats[portnr].lflags);
387                         mvprintw((6 + i), 52, "%04x", stats[portnr].signals);
388                         mvprintw((6 + i), 58, "%10d", stats[portnr].txtotal);
389                         mvprintw((6 + i), 69, "%10d", stats[portnr].rxtotal);
390                 }
391         } else {
392                 mvprintw(12, 32, "NO BOARD %d FOUND", displaybrdnr);
393                 i = 16;
394         }
395
396         attron(A_REVERSE);
397         mvprintw((6 + i), 0, line);
398         attroff(A_REVERSE);
399
400         mvprintw(24, 14,
401                 "(q=Quit,01234567=Board,n=Panels,p=Ports,Z=ZeroStats)");
402         refresh();
403 }
404
405 /*****************************************************************************/
406
407 /*
408  *      Continuously update and display the all ports stats screen.
409  *      Also checks for keyboard input, and processes it as appropriate.
410  */
411
412 void menuallports()
413 {
414         int     ch, done;
415
416         clear();
417         getbrdstats();
418
419         done = 0;
420         while ((ch = getch()) != 27) {
421                 switch (ch) {
422                 case ERR:
423                         break;
424                 case '\f':
425                         refresh();
426                         break;
427                 case '0':
428                 case '1':
429                 case '2':
430                 case '3':
431                 case '4':
432                 case '5':
433                 case '6':
434                 case '7':
435                         displaybrdnr = ch - '0';
436                         displaypanelnr = 0;
437                         getbrdstats();
438                         if (brdstats.state == 0)
439                                 beep();
440                         clear();
441                         break;
442                 case 'n':
443                         if (brdstats.panels[displaypanelnr].nrports > 16) {
444                                 if (displayportbank == 0) {
445                                         displayportbank = 16;
446                                         clear();
447                                         break;
448                                 }
449                         }
450                         displayportbank = 0;
451                         displaypanelnr++;
452                         if (displaypanelnr >= brdstats.nrpanels)
453                                 displaypanelnr = 0;
454                         clear();
455                         break;
456                 case 'p':
457                         if (brdstats.panels[displaypanelnr].nrports > 0) {
458                                 displayportnr = displayportbank;
459                                 menuport();
460                                 clear();
461                         } else {
462                                 beep();
463                         }
464                         break;
465                 case 'Z':
466                         clearallstats();
467                         clear();
468                         break;
469                 case 'q':
470                         done = 1;
471                         break;
472                 default:
473                         beep();
474                         break;
475                 }
476
477                 if (done)
478                         break;
479
480                 getallstats();
481                 displayallports();
482         }
483 }
484
485 /*****************************************************************************/
486
487 /* 
488  *      A local exit routine - shuts down curses before exiting.
489  */
490
491 void localexit(int nr)
492 {
493         refresh();
494         endwin();
495         exit(nr);
496 }
497
498 /*****************************************************************************/
499
500 int main(int argc, char *argv[])
501 {
502         struct stat     statinfo;
503         int             c, useport;
504         char            *portdev;
505
506         ctrldevice = defdevice;
507         useport = 0;
508
509         while ((c = getopt(argc, argv, "hvVb:p:d:c:")) != -1) {
510                 switch (c) {
511                 case 'V':
512                         printf("stlstats version %s\n", version);
513                         exit(0);
514                         break;
515                 case 'h':
516                         usage();
517                         break;
518                 case 'b':
519                         displaybrdnr = atoi(optarg);
520                         break;
521                 case 'p':
522                         displaypanelnr = atoi(optarg);
523                         break;
524                 case 'd':
525                         useport++;
526                         portdev = optarg;
527                         break;
528                 case 'c':
529                         ctrldevice = optarg;
530                         break;
531                 case '?':
532                 default:
533                         usage();
534                         break;
535                 }
536         }
537
538 /*
539  *      Check that the control device exits and is a character device.
540  */
541         if (stat(ctrldevice, &statinfo) < 0)
542                 errx(1, "control device %s does not exist", ctrldevice);
543         if ((statinfo.st_mode & S_IFMT) != S_IFCHR)
544                 errx(1, "control device %s is not a char device", ctrldevice);
545         if ((ctrlfd = open(ctrldevice, O_RDWR)) < 0)
546                 errx(1, "open of %s failed", ctrldevice);
547
548 /*
549  *      Validate the panel number supplied by user. We do this now since we
550  *      need to have parsed the entire command line first.
551  */
552         getbrdstats();
553         if (displaypanelnr >= brdstats.nrpanels)
554                 displaypanelnr = 0;
555
556         if (useport)
557                 useportdevice(portdev);
558
559 /*
560  *      Everything is now ready, lets go!
561  */
562         initscr();
563         cbreak();
564         halfdelay(5);
565         noecho();
566         clear();
567         if (useport) {
568                 menuport();
569                 clear();
570         }
571         menuallports();
572         refresh();
573         endwin();
574
575         close(ctrlfd);
576         printf("\n");
577         exit(0);
578 }
579
580 /*****************************************************************************/