1489f661be61a799bba17aa6f66937adf95b01bd
[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  * $FreeBSD: src/usr.sbin/stallion/stlstats/stlstats.c,v 1.9.2.1 2001/08/30 12:29:58 murray Exp $
37  * $DragonFly: src/usr.sbin/stallion/stlstats/stlstats.c,v 1.4 2006/08/03 16:40:49 swildner Exp $
38  */
39
40 /*****************************************************************************/
41
42 #include <err.h>
43 #include <fcntl.h>
44 #include <ncurses.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <time.h>
49 #include <unistd.h>
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52
53 #include <machine/cdk.h>
54 #include <machine/comstats.h>
55
56 /*****************************************************************************/
57
58 char    *version = "2.0.0";
59 char    *defdevice = "/dev/staliomem0";
60
61 char    *ctrldevice;
62 int     ctrlfd;
63 int     displaybrdnr = 0;
64 int     displaypanelnr = 0;
65 int     displayportnr = 0;
66 int     displayportbank = 0;
67
68 #define MAXBRDS         8
69 #define MAXPORTS        32
70
71 combrd_t        brdstats;
72 comstats_t      stats[MAXPORTS];
73
74 char    *line = "                                                                                ";
75
76 /*****************************************************************************/
77
78 /*
79  *      Declare internal function prototypes here.
80  */
81 static void     usage(void);
82 void    useportdevice(char *devname);
83 void    localexit(int nr);
84 void    menuport();
85 void    displayport();
86 void    menuallports();
87 void    displayallports();
88 void    getallstats();
89 void    getbrdstats();
90 void    clearportstats();
91 void    clearallstats();
92
93 /*****************************************************************************/
94
95 static void
96 usage(void)
97 {
98         fprintf(stderr, "%s\n%s\n",
99         "usage: stlstats [-hVi] [-c control-device] [-b board-number]",
100         "                [-p port-number] [-d port-device]");
101         exit(0);
102 }
103
104 /*****************************************************************************/
105
106 void
107 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
146 getbrdstats(void)
147 {
148         brdstats.brd = displaybrdnr;
149         if (ioctl(ctrlfd, COM_GETBRDSTATS, &brdstats) < 0)
150                 memset((combrd_t *) &brdstats, 0, sizeof(combrd_t));
151 }
152
153 /*****************************************************************************/
154
155 /*
156  *      Zero out stats for the current display port.
157  */
158
159 void
160 clearportstats(void)
161 {
162         stats[displayportnr].brd = displaybrdnr;
163         stats[displayportnr].panel = displaypanelnr;
164         stats[displayportnr].port = displayportnr;
165         ioctl(ctrlfd, COM_CLRPORTSTATS, &stats[displayportnr]);
166 }
167
168 /*****************************************************************************/
169
170 /*
171  *      Zero out all stats for all ports on all boards.
172  */
173
174 void
175 clearallstats(void)
176 {
177         int     brdnr, panelnr, portnr;
178
179         for (brdnr = 0; (brdnr < MAXBRDS); brdnr++) {
180                 for (panelnr = 0; (panelnr < COM_MAXPANELS); panelnr++) {
181                         for (portnr = 0; (portnr < MAXPORTS); portnr++) {
182                                 stats[0].brd = brdnr;
183                                 stats[0].panel = panelnr;
184                                 stats[0].port = portnr;
185                                 ioctl(ctrlfd, COM_CLRPORTSTATS, &stats[0]);
186                         }
187                 }
188         }
189 }
190
191 /*****************************************************************************/
192
193 /*
194  *      Get the stats for the current display board/panel.
195  */
196
197 void
198 getallstats(void)
199 {
200         int     i;
201
202         for (i = 0; (i < brdstats.panels[displaypanelnr].nrports); i++) {
203                 stats[i].brd = displaybrdnr;
204                 stats[i].panel = displaypanelnr;
205                 stats[i].port = i;
206                 if (ioctl(ctrlfd, COM_GETPORTSTATS, &stats[i]) < 0) {
207                         warn("ioctl(COM_GETPORTSTATS) failed");
208                         localexit(1);
209                 }
210         }
211 }
212
213 /*****************************************************************************/
214
215 /*
216  *      Display the per ports stats screen.
217  */
218
219 void
220 displayport(void)
221 {
222         mvprintw(0, 0, "STALLION SERIAL PORT STATISTICS");
223         mvprintw(2, 0,
224                 "Board=%d  Type=%d  HwID=%02x  State=%06x  TotalPorts=%d",
225                 displaybrdnr, brdstats.type, brdstats.hwid, brdstats.state,
226                 brdstats.nrports);
227         mvprintw(3, 0, "Panel=%d  HwID=%02x  Ports=%d", displaypanelnr,
228                 brdstats.panels[displaypanelnr].hwid,
229                 brdstats.panels[displaypanelnr].nrports);
230
231         attron(A_REVERSE);
232         mvprintw(5, 0, line);
233         mvprintw(5, 0, "Port=%d ", displayportnr);
234         attroff(A_REVERSE);
235
236         mvprintw(7,  0, "STATE:      State=%08x", stats[displayportnr].state);
237         mvprintw(7, 29, "Tty=%08x", stats[displayportnr].ttystate);
238         mvprintw(7, 47, "Flags=%08x", stats[displayportnr].flags);
239         mvprintw(7, 65, "HwID=%02x", stats[displayportnr].hwid);
240
241         mvprintw(8,  0, "CONFIG:     Cflag=%08x", stats[displayportnr].cflags);
242         mvprintw(8, 29, "Iflag=%08x", stats[displayportnr].iflags);
243         mvprintw(8, 47, "Oflag=%08x", stats[displayportnr].oflags);
244         mvprintw(8, 65, "Lflag=%08x", stats[displayportnr].lflags);
245
246         mvprintw(10,  0, "TX DATA:    Total=%d", stats[displayportnr].txtotal);
247         mvprintw(10, 29, "Buffered=%d      ", stats[displayportnr].txbuffered);
248         mvprintw(11,  0, "RX DATA:    Total=%d", stats[displayportnr].rxtotal);
249         mvprintw(11, 29, "Buffered=%d      ", stats[displayportnr].rxbuffered);
250         mvprintw(12,  0, "RX ERRORS:  Parity=%d", stats[displayportnr].rxparity);
251         mvprintw(12, 29, "Framing=%d", stats[displayportnr].rxframing);
252         mvprintw(12, 47, "Overrun=%d", stats[displayportnr].rxoverrun);
253         mvprintw(12, 65, "Lost=%d", stats[displayportnr].rxlost);
254
255         mvprintw(14,  0, "FLOW TX:    Xoff=%d", stats[displayportnr].txxoff);
256         mvprintw(14, 29, "Xon=%d", stats[displayportnr].txxon);
257 #if 0
258         mvprintw(14, 47, "CTSoff=%d", stats[displayportnr].txctsoff);
259         mvprintw(14, 65, "CTSon=%d", stats[displayportnr].txctson);
260 #endif
261         mvprintw(15,  0, "FLOW RX:    Xoff=%d", stats[displayportnr].rxxoff);
262         mvprintw(15, 29, "Xon=%d", stats[displayportnr].rxxon);
263         mvprintw(15, 47, "RTSoff=%d", stats[displayportnr].rxrtsoff);
264         mvprintw(15, 65, "RTSon=%d", stats[displayportnr].rxrtson);
265
266         mvprintw(17,  0, "OTHER:      TXbreaks=%d",
267                 stats[displayportnr].txbreaks);
268         mvprintw(17, 29, "RXbreaks=%d", stats[displayportnr].rxbreaks);
269         mvprintw(17, 47, "Modem=%d", stats[displayportnr].modem);
270
271         mvprintw(19, 0, "SIGNALS:    DCD=%d    DTR=%d    CTS=%d    RTS=%d    "
272                 "DSR=%d    RI=%d",
273                 (stats[displayportnr].signals & TIOCM_CD) ? 1 : 0,
274                 (stats[displayportnr].signals & TIOCM_DTR) ? 1 : 0,
275                 (stats[displayportnr].signals & TIOCM_CTS) ? 1 : 0,
276                 (stats[displayportnr].signals & TIOCM_RTS) ? 1 : 0,
277                 (stats[displayportnr].signals & TIOCM_DSR) ? 1 : 0,
278                 (stats[displayportnr].signals & TIOCM_RI) ? 1 : 0);
279
280         attron(A_REVERSE);
281         mvprintw(22, 0, line);
282         attroff(A_REVERSE);
283
284         mvprintw(24, 19, "(q=Quit,0123456789abcdef=Port,Z=ZeroStats)");
285         refresh();
286 }
287
288 /*****************************************************************************/
289
290 /*
291  *      Continuously update and display the per ports stats screen.
292  *      Also checks for keyboard input, and processes it as appropriate.
293  */
294
295 void
296 menuport(void)
297 {
298         int     ch, done;
299
300         clear();
301         done = 0;
302
303         while ((ch = getch()) != 27) {
304                 switch (ch) {
305                 case ERR:
306                         break;
307                 case '\f':
308                         refresh();
309                         break;
310                 case 'a':
311                 case 'b':
312                 case 'c':
313                 case 'd':
314                 case 'e':
315                 case 'f':
316                         ch = (ch - 'a' + '0' + 10);
317                         /* fall thru */
318                 case '0':
319                 case '1':
320                 case '2':
321                 case '3':
322                 case '4':
323                 case '5':
324                 case '6':
325                 case '7':
326                 case '8':
327                 case '9':
328                         ch -= '0';
329                         if (ch >= brdstats.panels[displaypanelnr].nrports) {
330                                 beep();
331                         } else {
332                                 displayportnr = displayportbank + ch;
333                                 clear();
334                         }
335                         break;
336                 case 'Z':
337                         clearportstats();
338                         clear();
339                         break;
340                 case 'q':
341                         done = 1;
342                         break;
343                 default:
344                         beep();
345                         break;
346                 }
347
348                 if (done)
349                         break;
350
351                 getallstats();
352                 displayport();
353         }
354 }
355
356 /*****************************************************************************/
357
358 /*
359  *      Display the all ports stats screen.
360  */
361
362 void
363 displayallports(void)
364 {
365         int     i, nrports, portnr;
366
367         nrports = brdstats.panels[displaypanelnr].nrports;
368
369         mvprintw(0, 0, "STALLION SERIAL PORT STATISTICS");
370         mvprintw(2, 0, "Board=%d  Type=%d  HwID=%02x  State=%06x  TotalPorts=%d",
371                 displaybrdnr, brdstats.type, brdstats.hwid, brdstats.state,
372                 brdstats.nrports);
373         mvprintw(3, 0, "Panel=%d  HwID=%02x  Ports=%d", displaypanelnr,
374                 brdstats.panels[displaypanelnr].hwid, nrports);
375
376         attron(A_REVERSE);
377         mvprintw(5, 0, "Port  State   Tty    Flags  Cflag Iflag Oflag Lflag "
378                 "Sigs    TX Total   RX Total ");
379         attroff(A_REVERSE);
380
381         if (nrports > 0) {
382                 if (nrports > 16)
383                         nrports = 16;
384                 portnr = displayportbank;
385                 for (i = 0; (i < nrports); i++, portnr++) {
386                         mvprintw((6 + i), 1, "%2d", portnr);
387                         mvprintw((6 + i), 5, "%06x", stats[portnr].state);
388                         mvprintw((6 + i), 12, "%06x", stats[portnr].ttystate);
389                         mvprintw((6 + i), 19, "%08x", stats[portnr].flags);
390                         mvprintw((6 + i), 28, "%05x", stats[portnr].cflags);
391                         mvprintw((6 + i), 34, "%05x", stats[portnr].iflags);
392                         mvprintw((6 + i), 40, "%05x", stats[portnr].oflags);
393                         mvprintw((6 + i), 46, "%05x", stats[portnr].lflags);
394                         mvprintw((6 + i), 52, "%04x", stats[portnr].signals);
395                         mvprintw((6 + i), 58, "%10d", stats[portnr].txtotal);
396                         mvprintw((6 + i), 69, "%10d", stats[portnr].rxtotal);
397                 }
398         } else {
399                 mvprintw(12, 32, "NO BOARD %d FOUND", displaybrdnr);
400                 i = 16;
401         }
402
403         attron(A_REVERSE);
404         mvprintw((6 + i), 0, line);
405         attroff(A_REVERSE);
406
407         mvprintw(24, 14,
408                 "(q=Quit,01234567=Board,n=Panels,p=Ports,Z=ZeroStats)");
409         refresh();
410 }
411
412 /*****************************************************************************/
413
414 /*
415  *      Continuously update and display the all ports stats screen.
416  *      Also checks for keyboard input, and processes it as appropriate.
417  */
418
419 void
420 menuallports(void)
421 {
422         int     ch, done;
423
424         clear();
425         getbrdstats();
426
427         done = 0;
428         while ((ch = getch()) != 27) {
429                 switch (ch) {
430                 case ERR:
431                         break;
432                 case '\f':
433                         refresh();
434                         break;
435                 case '0':
436                 case '1':
437                 case '2':
438                 case '3':
439                 case '4':
440                 case '5':
441                 case '6':
442                 case '7':
443                         displaybrdnr = ch - '0';
444                         displaypanelnr = 0;
445                         getbrdstats();
446                         if (brdstats.state == 0)
447                                 beep();
448                         clear();
449                         break;
450                 case 'n':
451                         if (brdstats.panels[displaypanelnr].nrports > 16) {
452                                 if (displayportbank == 0) {
453                                         displayportbank = 16;
454                                         clear();
455                                         break;
456                                 }
457                         }
458                         displayportbank = 0;
459                         displaypanelnr++;
460                         if (displaypanelnr >= brdstats.nrpanels)
461                                 displaypanelnr = 0;
462                         clear();
463                         break;
464                 case 'p':
465                         if (brdstats.panels[displaypanelnr].nrports > 0) {
466                                 displayportnr = displayportbank;
467                                 menuport();
468                                 clear();
469                         } else {
470                                 beep();
471                         }
472                         break;
473                 case 'Z':
474                         clearallstats();
475                         clear();
476                         break;
477                 case 'q':
478                         done = 1;
479                         break;
480                 default:
481                         beep();
482                         break;
483                 }
484
485                 if (done)
486                         break;
487
488                 getallstats();
489                 displayallports();
490         }
491 }
492
493 /*****************************************************************************/
494
495 /* 
496  *      A local exit routine - shuts down curses before exiting.
497  */
498
499 void
500 localexit(int nr)
501 {
502         refresh();
503         endwin();
504         exit(nr);
505 }
506
507 /*****************************************************************************/
508
509 int
510 main(int argc, char *argv[])
511 {
512         struct stat     statinfo;
513         int             c, useport;
514         char            *portdev;
515
516         ctrldevice = defdevice;
517         useport = 0;
518
519         while ((c = getopt(argc, argv, "hvVb:p:d:c:")) != -1) {
520                 switch (c) {
521                 case 'V':
522                         printf("stlstats version %s\n", version);
523                         exit(0);
524                         break;
525                 case 'h':
526                         usage();
527                         break;
528                 case 'b':
529                         displaybrdnr = atoi(optarg);
530                         break;
531                 case 'p':
532                         displaypanelnr = atoi(optarg);
533                         break;
534                 case 'd':
535                         useport++;
536                         portdev = optarg;
537                         break;
538                 case 'c':
539                         ctrldevice = optarg;
540                         break;
541                 case '?':
542                 default:
543                         usage();
544                         break;
545                 }
546         }
547
548 /*
549  *      Check that the control device exits and is a character device.
550  */
551         if (stat(ctrldevice, &statinfo) < 0)
552                 errx(1, "control device %s does not exist", ctrldevice);
553         if ((statinfo.st_mode & S_IFMT) != S_IFCHR)
554                 errx(1, "control device %s is not a char device", ctrldevice);
555         if ((ctrlfd = open(ctrldevice, O_RDWR)) < 0)
556                 errx(1, "open of %s failed", ctrldevice);
557
558 /*
559  *      Validate the panel number supplied by user. We do this now since we
560  *      need to have parsed the entire command line first.
561  */
562         getbrdstats();
563         if (displaypanelnr >= brdstats.nrpanels)
564                 displaypanelnr = 0;
565
566         if (useport)
567                 useportdevice(portdev);
568
569 /*
570  *      Everything is now ready, lets go!
571  */
572         initscr();
573         cbreak();
574         halfdelay(5);
575         noecho();
576         clear();
577         if (useport) {
578                 menuport();
579                 clear();
580         }
581         menuallports();
582         refresh();
583         endwin();
584
585         close(ctrlfd);
586         printf("\n");
587         exit(0);
588 }
589
590 /*****************************************************************************/