1/*
2 * First author: Michael Graff.
3 * Copyright (c) 1997-2000 Lan Media Corp. (www.lanmedia.com).
4 * All rights reserved.
5 *
6 * Second author: Andrew Stanley-Jones.
7 * Copyright (c) 2000-2002 SBE Corp. (www.sbei.com).
8 * All rights reserved.
9 *
10 * Third author: David Boggs.
11 * Copyright (c) 2002-2004 David Boggs. (boggs@boggs.palo-alto.ca.us).
12 * All rights reserved.
13 *
14 * BSD License:
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * GNU General Public License:
38 *
39 * This program is free software; you can redistribute it and/or modify it
40 * under the terms of the GNU General Public License as published by the Free
41 * Software Foundation; either version 2 of the License, or (at your option)
42 * any later version.
43 *
44 * This program is distributed in the hope that it will be useful, but WITHOUT
45 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
46 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
47 * more details.
48 *
49 * You should have received a copy of the GNU General Public License along with
50 * this program; if not, write to the Free Software Foundation, Inc., 59
51 * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
52 *
53 * Description:
54 *
55 * This program configures the Unix/Linux device driver for SBE Corp's
56 *  wanADAPT and wanPMC series of Wide Area Network Interface Cards.
57 * There is a man page for this program; go find it.
58 *
59 * If Netgraph is present (FreeBSD only):
60 *    cc -o lmcconfig -l netgraph -D NETGRAPH lmcconfig.c
61 * If Netgraph is NOT present:
62 *    cc -o lmcconfig lmcconfig.c
63 * Install the executable program in /usr/local/sbin/lmcconfig.
64 *
65 * $FreeBSD: stable/11/usr.sbin/lmcconfig/lmcconfig.c 360675 2020-05-05 21:01:43Z dim $
66 */
67
68#include <sys/param.h>
69#include <sys/ioctl.h>
70#include <sys/socket.h>
71
72#include <errno.h>
73#include <inttypes.h>
74#include <stdio.h>
75#include <stdlib.h>
76#include <string.h>
77#include <strings.h>
78#include <time.h>
79#include <unistd.h>
80#if defined(NETGRAPH)
81# include <netgraph.h>
82#endif
83#include <net/if.h>
84
85#include <dev/lmc/if_lmc.h>
86
87/* program global variables */
88char *		progname;	/* name of this program */
89char *		ifname;		/* interface name */
90int		fdcs;		/* ifnet File Desc or ng Ctl Socket */
91struct status	status;		/* card status (read only) */
92struct config	config;		/* card configuration (read/write) */
93int		netgraph = 0;	/* non-zero if netgraph present */
94int		summary  = 0;	/* print summary at end */
95int		update   = 0;	/* update driver config */
96int             verbose  = 0;	/* verbose output */
97u_int8_t	checksum;	/* gate array ucode file checksum */
98
99/* Functions currently unused. Keep compiler happy and provide prototypes. */
100void ioctl_snmp_loop(u_int32_t);
101void init_srom(int);
102
103static void
104usage(void)
105{
106  fprintf(stderr, "Usage: %s interface [-abBcCdDeEfhiLmMpPsStTuUvVwWxXyYzZ?]\n", progname);
107  fprintf(stderr, "or\n");
108  fprintf(stderr, "Usage: %s interface -1 [-aABcdeEfFgiIlLpPstTuUvxX]\n", progname);
109  fprintf(stderr, "or\n");
110  fprintf(stderr, "Usage: %s interface -3 [-aABcdefFlLsSvV]\n\n", progname);
111  fprintf(stderr, "\tInterface is the interface name, e.g. '%s'\n", ifname);
112#if defined(NETGRAPH)
113  fprintf(stderr, "\tIf interface name ends with ':' then use netgraph\n");
114#endif
115  fprintf(stderr, "\t-1 following parameters apply to T1E1 cards\n");
116  fprintf(stderr, "\t-3 following parameters apply to T3 cards\n");
117  fprintf(stderr, "\t-a <number> Set Tx clock source, where:\n");
118  fprintf(stderr, "\t   1:modem Tx clk 2:int src 3:modem Rx Clk 4:ext conn\n");
119  fprintf(stderr, "\t-b Read and print bios rom addrs 0-255\n");
120  fprintf(stderr, "\t-B Write bios rom with address pattern\n");
121  fprintf(stderr, "\t-c Set 16-bit CRC (default)\n");
122  fprintf(stderr, "\t-C Set 32-bit CRC\n");
123  fprintf(stderr, "\t-d Clear driver DEBUG flag\n");
124  fprintf(stderr, "\t-D Set driver DEBUG flag (more log msgs)\n");
125  fprintf(stderr, "\t-e Set DTE mode (default)\n");
126  fprintf(stderr, "\t-E Set DCE mode\n");
127  fprintf(stderr, "\t-f <number> Set synth osc freq in bits/sec\n");
128  fprintf(stderr, "\t-F Set SPPP line protocol to Frame-Relay\n");
129  fprintf(stderr, "\t-h Help: this usage message\n");
130  fprintf(stderr, "\t-i Interface name (eg, lmc0)\n");
131  fprintf(stderr, "\t-L <number> Set loopback: 1:none 2:payload 3:line 4:other\n");
132  fprintf(stderr, "\t   5:inward 6:dual 16:Tulip 17:pins 18:LA/LL 19:LB/RL\n");
133  fprintf(stderr, "\t-m Read and print MII regs\n");
134  fprintf(stderr, "\t-M <addr> <data> Write MII reg\n");
135  fprintf(stderr, "\t-p Read and print PCI config regs\n");
136  fprintf(stderr, "\t-P <addr> <data> Write PCI config reg\n");
137  fprintf(stderr, "\t-s Read and print Tulip SROM\n");
138  fprintf(stderr, "\t-S <number> Initialize Tulip SROM\n");
139  fprintf(stderr, "\t-t Read and print Tulip Control/Status regs\n");
140  fprintf(stderr, "\t-T <addr> <data> Write Tulip Control/status reg\n");
141  fprintf(stderr, "\t-u Reset event counters\n");
142  fprintf(stderr, "\t-U Reset gate array\n");
143  fprintf(stderr, "\t-v Set verbose printout mode\n");
144  fprintf(stderr, "\t-V Print card configuration\n");
145  fprintf(stderr, "\t-w Load gate array from ROM\n");
146  fprintf(stderr, "\t-W <filename> Load gate array from file\n");
147  fprintf(stderr, "\t-x select RAWIP mode and bypass line protocols\n");
148  fprintf(stderr, "\t-X Select line protocols: SPPP, P2P or HDLC\n");
149  fprintf(stderr, "\t-y disable SPPP keep-alive packets\n");
150  fprintf(stderr, "\t-Y enable SPPP keep-alive packets\n");
151  fprintf(stderr, "\t-z Set SPPP line protocol to Cisco-HDLC\n");
152  fprintf(stderr, "\t-Z Set SPPP line protocol to PPP\n");
153
154  fprintf(stderr, "The -1 switch precedes T1/E1 commands.\n");
155  fprintf(stderr, "\t-a <y|b|a> Stop  sending Yellow|Blue|AIS signal\n");
156  fprintf(stderr, "\t-A <y|b|a> Start sending Yellow|Blue|AIS signal\n");
157  fprintf(stderr, "\t-B <number> Send BOP msg 25 times\n");
158  fprintf(stderr, "\t-c <number> Set cable length in meters\n");
159  fprintf(stderr, "\t-d Print status of T1 DSU/CSU\n");
160  fprintf(stderr, "\t-e <number> Set framing format, where:\n");
161  fprintf(stderr, "\t   27:T1-ESF 9:T1-SF 0:E1-FAS 8:E1-FAS+CRC\n");
162  fprintf(stderr, "\t   16:E1-FAS+CAS 24:E1-FAS+CRC+CAS 32:E1-NO-FRAMING\n");
163  fprintf(stderr, "\t-E <32-bit hex number> 1 activates a channel and 0 deactivates it.\n");
164  fprintf(stderr, "\t   Use this to config a link in fractional T1/E1 mode\n");
165  fprintf(stderr, "\t-f Read and print Framer/LIU registers\n");
166  fprintf(stderr, "\t-F <addr> <data> Write Framer/LIU register\n");
167  fprintf(stderr, "\t-g <number> Set receiver gain, where:\n");
168  fprintf(stderr, "\t   0:short range  1:medium range\n");
169  fprintf(stderr, "\t   2:long range   3:extended range\n");
170  fprintf(stderr, "\t   4:auto-set based on cable length\n");
171  fprintf(stderr, "\t-i Send 'CSU Loop Down' inband msg\n");
172  fprintf(stderr, "\t-I Send 'CSU Loop Up' inband msg\n");
173  fprintf(stderr, "\t-l Send 'Line Loop Down' BOP msg\n");
174  fprintf(stderr, "\t-L Send 'Line Loop Up' BOP msg\n");
175  fprintf(stderr, "\t-p Send 'Payload Loop Down' BOP msg\n");
176  fprintf(stderr, "\t-P Send 'Payload Loop Up' BOP msg\n");
177  fprintf(stderr, "\t-s Print status of T1 DSU/CSU\n");
178  fprintf(stderr, "\t-t Stop sending test pattern\n");
179  fprintf(stderr, "\t-T <number> Start sending test pattern, where:\n");
180  fprintf(stderr, "\t    0:unframed 2^11       1:unframed 2^15\n");
181  fprintf(stderr, "\t    2:unframed 2^20       3:unframed 2^23\n");
182  fprintf(stderr, "\t    4:unframed 2^11 w/ZS  5:unframed 2^15 w/ZS\n");
183  fprintf(stderr, "\t    6:unframed QRSS       7:unframed 2^23 w/ZS\n");
184  fprintf(stderr, "\t    8:  framed 2^11       9:  framed 2^15\n");
185  fprintf(stderr, "\t   10:  framed 2^20      11:  framed 2^23\n");
186  fprintf(stderr, "\t   12:  framed 2^11 w/ZS 13:  framed 2^15 w/ZS\n");
187  fprintf(stderr, "\t   14:  framed QRSS      15:  framed 2^23 w/ZS\n");
188  fprintf(stderr, "\t-u <number> Set transmitter pulse shape, where:\n");
189  fprintf(stderr, "\t   0:T1-DSX   0-40m       1:T1-DSX  40-80m\n");
190  fprintf(stderr, "\t   2:T1-DSX  80-120m      3:T1-DSX 120-160m\n");
191  fprintf(stderr, "\t   4:T1-DSX 160-200m      5:E1-G.703 75ohm coax\n");
192  fprintf(stderr, "\t   6:E1-G.703 120ohm TP   7:T1-CSU Long range\n");
193  fprintf(stderr, "\t   8:auto-set based on cable length (T1 only)\n");
194  fprintf(stderr, "\t-U <number> Set line build out where:\n");
195  fprintf(stderr, "\t   0:0dB 1:7.5dB 2:15dB 3:22.5dB\n");
196  fprintf(stderr, "\t   4:auto-set based on cable length\n");
197  fprintf(stderr, "\t-v Set verbose printout mode\n");
198  fprintf(stderr, "\t-x disable Transmitter outputs\n");
199  fprintf(stderr, "\t-X enable  Transmitter outputs\n");
200
201  fprintf(stderr, "The -3 switch precedes T3 commands.\n");
202  fprintf(stderr, "\t-a <y|b|a|i> Stop  sending Yellow|Blue|AIS|Idle signal\n");
203  fprintf(stderr, "\t-A <y|b|a|i> Start sending Yellow|Blue|AIS|Idle signal\n");
204  fprintf(stderr, "\t-B <bopcode> Send BOP msg 10 times\n");
205  fprintf(stderr, "\t-c <number> Set cable length in meters\n");
206  fprintf(stderr, "\t-d Print status of T3 DSU/CSU\n");
207  fprintf(stderr, "\t-e <number> Set T3 frame format, where:\n");
208  fprintf(stderr, "\t   100:C-Bit Parity  101:M13\n");
209  fprintf(stderr, "\t-f Read and print Framer registers\n");
210  fprintf(stderr, "\t-F <addr> <data> Write Framer register\n");
211  fprintf(stderr, "\t-l Send 'Line Loop Down' BOP msg\n");
212  fprintf(stderr, "\t-L Send 'Line Loop Up' BOP msg\n");
213  fprintf(stderr, "\t-s Print status of T3 DSU/CSU\n");
214  fprintf(stderr, "\t-S <number> Set DS3 scrambler mode, where:\n");
215  fprintf(stderr, "\t   1:OFF 2:DigitalLink|Kentrox 3:Larse\n");
216  fprintf(stderr, "\t-v Set verbose printout mode\n");
217  fprintf(stderr, "\t-V <number> Write to T3 VCXO freq control DAC\n");
218}
219
220static void
221call_driver(unsigned long cmd, struct iohdr *iohdr)
222{
223  int error = 0;
224
225  strlcpy(iohdr->ifname, ifname, sizeof(iohdr->ifname));
226  iohdr->cookie = NGM_LMC_COOKIE;
227  iohdr->iohdr = iohdr;
228
229  /* Exchange data with a running device driver. */
230#if defined(NETGRAPH)
231  if (netgraph)
232    {
233    NgSendMsg(fdcs, ifname, NGM_LMC_COOKIE, cmd, iohdr, IOCPARM_LEN(cmd));
234    if (cmd & IOC_OUT)
235      {
236      int replen = sizeof(struct ng_mesg) + IOCPARM_LEN(cmd);
237      char rep[replen];  /* storage for the reply */
238      struct ng_mesg *reply = (struct ng_mesg *)rep;
239      int rl = NgRecvMsg(fdcs, reply, replen, NULL);
240      if (rl == replen)
241        bcopy(&reply->data, iohdr, IOCPARM_LEN(cmd));
242      else
243        {
244        fprintf(stderr, "%s: NgRecvMsg returned %d bytes, expected %d\n",
245          progname, rl, replen);
246        exit(1);
247	}
248      }
249    }
250  else
251#endif
252    {
253    if ((error = ioctl(fdcs, cmd, (caddr_t)iohdr)) < 0)
254      {
255      fprintf(stderr, "%s: ioctl() returned error code %d: %s\n",
256       progname, errno, strerror(errno));
257      if (errno == ENETDOWN)
258        printf("Type: 'ifconfig %s up' then try again.\n", ifname);
259      exit(1);
260      }
261    }
262
263  if (iohdr->cookie != NGM_LMC_COOKIE)
264    {
265    fprintf(stderr, "%s: cookie = 0x%08X, expected 0x%08X\n", progname, iohdr->cookie, NGM_LMC_COOKIE);
266    fprintf(stderr, "%s: This version of %s is incompatible with the device driver\n", progname, progname);
267    exit(1);
268    }
269}
270
271static u_int32_t
272read_pci_config(u_int8_t addr)
273{
274  struct ioctl ioctl;
275
276  ioctl.iohdr.direction = DIR_IOWR;
277  ioctl.iohdr.length = sizeof(struct ioctl);
278  ioctl.cmd = IOCTL_RW_PCI;
279  ioctl.address = addr;
280
281  call_driver(LMCIOCREAD, &ioctl.iohdr);
282
283  return ioctl.data;
284}
285
286static void
287write_pci_config(u_int8_t addr, u_int32_t data)
288{
289  struct ioctl ioctl;
290
291  ioctl.iohdr.direction = DIR_IOW;
292  ioctl.iohdr.length = sizeof(struct ioctl);
293  ioctl.cmd = IOCTL_RW_PCI;
294  ioctl.address = addr;
295  ioctl.data = data;
296
297  call_driver(LMCIOCWRITE, &ioctl.iohdr);
298}
299
300static u_int32_t
301read_csr(u_int8_t addr)
302{
303  struct ioctl ioctl;
304
305  ioctl.iohdr.direction = DIR_IOWR;
306  ioctl.iohdr.length = sizeof(struct ioctl);
307  ioctl.cmd = IOCTL_RW_CSR;
308  ioctl.address = addr;
309
310  call_driver(LMCIOCREAD, &ioctl.iohdr);
311
312  return ioctl.data;
313}
314
315static void
316write_csr(u_int8_t addr, u_int32_t data)
317{
318  struct ioctl ioctl;
319
320  ioctl.iohdr.direction = DIR_IOW;
321  ioctl.iohdr.length = sizeof(struct ioctl);
322  ioctl.cmd = IOCTL_RW_CSR;
323  ioctl.address = addr;
324  ioctl.data = data;
325
326  call_driver(LMCIOCWRITE, &ioctl.iohdr);
327}
328
329static u_int16_t
330read_srom(u_int8_t addr)
331{
332  struct ioctl ioctl;
333
334  ioctl.iohdr.direction = DIR_IOWR;
335  ioctl.iohdr.length = sizeof(struct ioctl);
336  ioctl.cmd = IOCTL_RW_SROM;
337  ioctl.address = addr;
338
339  call_driver(LMCIOCREAD, &ioctl.iohdr);
340
341  return ioctl.data;
342}
343
344static void
345write_srom(u_int8_t addr, u_int16_t data)
346{
347  struct ioctl ioctl;
348
349  ioctl.iohdr.direction = DIR_IOW;
350  ioctl.iohdr.length = sizeof(struct ioctl);
351  ioctl.cmd = IOCTL_RW_SROM;
352  ioctl.address = addr;
353  ioctl.data = data;
354
355  call_driver(LMCIOCWRITE, &ioctl.iohdr);
356}
357
358static u_int8_t
359read_bios_rom(u_int32_t addr)
360{
361  struct ioctl ioctl;
362
363  ioctl.iohdr.direction = DIR_IOWR;
364  ioctl.iohdr.length = sizeof(struct ioctl);
365  ioctl.cmd = IOCTL_RW_BIOS;
366  ioctl.address = addr;
367
368  call_driver(LMCIOCREAD, &ioctl.iohdr);
369
370  return ioctl.data;
371}
372
373static void
374write_bios_rom(u_int32_t addr, u_int8_t data)
375{
376  struct ioctl ioctl;
377
378  ioctl.iohdr.direction = DIR_IOW;
379  ioctl.iohdr.length = sizeof(struct ioctl);
380  ioctl.cmd = IOCTL_RW_BIOS;
381  ioctl.address = addr;
382  ioctl.data = data;
383
384  call_driver(LMCIOCWRITE, &ioctl.iohdr);
385}
386
387static u_int16_t
388read_mii(u_int8_t addr)
389{
390  struct ioctl ioctl;
391
392  ioctl.iohdr.direction = DIR_IOWR;
393  ioctl.iohdr.length = sizeof(struct ioctl);
394  ioctl.cmd = IOCTL_RW_MII;
395  ioctl.address = addr;
396
397  call_driver(LMCIOCREAD, &ioctl.iohdr);
398
399  return ioctl.data;
400}
401
402static void
403write_mii(u_int8_t addr, u_int16_t data)
404{
405  struct ioctl ioctl;
406
407  ioctl.iohdr.direction = DIR_IOW;
408  ioctl.iohdr.length = sizeof(struct ioctl);
409  ioctl.cmd = IOCTL_RW_MII;
410  ioctl.address = addr;
411  ioctl.data = data;
412
413  call_driver(LMCIOCWRITE, &ioctl.iohdr);
414}
415
416static unsigned char
417read_framer(u_int16_t addr)
418{
419  struct ioctl ioctl;
420
421  ioctl.iohdr.direction = DIR_IOWR;
422  ioctl.iohdr.length = sizeof(struct ioctl);
423  ioctl.cmd = IOCTL_RW_FRAME;
424  ioctl.address = addr;
425
426  call_driver(LMCIOCREAD, &ioctl.iohdr);
427
428  return ioctl.data;
429}
430
431static void
432write_framer(u_int16_t addr, u_int8_t data)
433{
434  struct ioctl ioctl;
435
436  ioctl.iohdr.direction = DIR_IOW;
437  ioctl.iohdr.length = sizeof(struct ioctl);
438  ioctl.cmd = IOCTL_RW_FRAME;
439  ioctl.address = addr;
440  ioctl.data = data;
441
442  call_driver(LMCIOCWRITE, &ioctl.iohdr);
443}
444
445static void
446write_synth(struct synth synth)
447{
448  struct ioctl ioctl;
449
450  ioctl.iohdr.direction = DIR_IOW;
451  ioctl.iohdr.length = sizeof(struct ioctl);
452  ioctl.cmd = IOCTL_WO_SYNTH;
453  bcopy(&synth, &ioctl.data, sizeof(synth));
454
455  call_driver(LMCIOCWRITE, &ioctl.iohdr);
456}
457
458static void
459write_dac(u_int16_t data)
460{
461  struct ioctl ioctl;
462
463  ioctl.iohdr.direction = DIR_IOW;
464  ioctl.iohdr.length = sizeof(struct ioctl);
465  ioctl.cmd = IOCTL_WO_DAC;
466  ioctl.data = data;
467
468  call_driver(LMCIOCWRITE, &ioctl.iohdr);
469}
470
471static void
472reset_xilinx(void)
473{
474  struct ioctl ioctl;
475
476  ioctl.iohdr.direction = DIR_IOWR;
477  ioctl.iohdr.length = sizeof(struct ioctl);
478  ioctl.cmd = IOCTL_XILINX_RESET;
479
480  call_driver(LMCIOCTL, &ioctl.iohdr);
481}
482
483static void
484load_xilinx_from_rom(void)
485{
486  struct ioctl ioctl;
487
488  ioctl.iohdr.direction = DIR_IOWR;
489  ioctl.iohdr.length = sizeof(struct ioctl);
490  ioctl.cmd = IOCTL_XILINX_ROM;
491
492  call_driver(LMCIOCTL, &ioctl.iohdr);
493}
494
495static void
496load_xilinx_from_file(char *ucode, u_int32_t len)
497{
498  struct ioctl ioctl;
499
500  ioctl.iohdr.direction = DIR_IOWR;
501  ioctl.iohdr.length = sizeof(struct ioctl);
502  ioctl.cmd = IOCTL_XILINX_FILE;
503  ioctl.data = len;
504  ioctl.ucode = ucode;
505
506  call_driver(LMCIOCTL, &ioctl.iohdr);
507}
508
509static void
510ioctl_snmp_send(u_int32_t send)
511{
512  struct ioctl ioctl;
513
514  ioctl.iohdr.direction = DIR_IOWR;
515  ioctl.iohdr.length = sizeof(struct ioctl);
516  ioctl.cmd = IOCTL_SNMP_SEND;
517  ioctl.data = send;
518
519  call_driver(LMCIOCTL, &ioctl.iohdr);
520}
521
522void
523ioctl_snmp_loop(u_int32_t loop)
524{
525  struct ioctl ioctl;
526
527  ioctl.iohdr.direction = DIR_IOWR;
528  ioctl.iohdr.length = sizeof(struct ioctl);
529  ioctl.cmd = IOCTL_SNMP_LOOP;
530  ioctl.data = loop;
531
532  call_driver(LMCIOCTL, &ioctl.iohdr);
533}
534
535static void
536ioctl_reset_cntrs(void)
537{
538  struct ioctl ioctl;
539
540  ioctl.iohdr.direction = DIR_IOWR;
541  ioctl.iohdr.length = sizeof(struct ioctl);
542  ioctl.cmd = IOCTL_RESET_CNTRS;
543
544  call_driver(LMCIOCTL, &ioctl.iohdr);
545}
546
547static void
548ioctl_read_config(void)
549{
550  config.iohdr.direction = DIR_IOWR;
551  config.iohdr.length = sizeof(struct config);
552
553  call_driver(LMCIOCGCFG, &config.iohdr);
554}
555
556static void
557ioctl_write_config(void)
558{
559  config.iohdr.direction = DIR_IOW;
560  config.iohdr.length = sizeof(struct config);
561
562  call_driver(LMCIOCSCFG, &config.iohdr);
563}
564
565static void
566ioctl_read_status(void)
567{
568  status.iohdr.direction = DIR_IOWR;
569  status.iohdr.length = sizeof(struct status);
570
571  call_driver(LMCIOCGSTAT, &status.iohdr);
572}
573
574static void
575print_card_name(void)
576{
577  printf("Card name:\t\t%s\n", ifname);
578}
579
580static void
581print_card_type(void)
582{
583  printf("Card type:\t\t");
584  switch(status.card_type)
585    {
586    case TLP_CSID_HSSI:
587      printf("HSSI (lmc5200)\n");
588      break;
589    case TLP_CSID_T3:
590      printf("T3 (lmc5245)\n");
591      break;
592    case TLP_CSID_SSI:
593      printf("SSI (lmc1000)\n");
594      break;
595    case TLP_CSID_T1E1:
596      printf("T1E1 (lmc1200)\n");
597      break;
598    case TLP_CSID_HSSIc:
599      printf("HSSI (lmc5200C)\n");
600      break;
601    default:
602      printf("unknown card_type: %d\n", status.card_type);
603      break;
604    }
605}
606
607static void
608print_status(void)
609{
610  char *status_string;
611
612  if      (status.oper_status == STATUS_UP)
613    status_string = "Up";
614  else if (status.oper_status == STATUS_DOWN)
615    status_string = "Down";
616  else if (status.oper_status == STATUS_TEST)
617    status_string = "Test";
618  else
619    status_string = "Unknown";
620  printf("Link status:\t\t%s\n", status_string);
621}
622
623static void
624print_tx_speed(void)
625{
626  printf("Tx Speed:\t\t%u\n", status.tx_speed);
627}
628
629static void
630print_debug(void)
631{
632  if (config.debug != 0)
633    printf("Debug:\t\t\t%s\n", "On");
634}
635
636static void
637print_line_prot(void)
638{
639  char *on = "On", *off = "Off";
640
641  printf("Line Prot/Pkg:\t\t");
642  switch (status.line_prot)
643    {
644    case 0:
645      printf("NotSet/");
646      break;
647    case PROT_PPP:
648      printf("PPP/");
649      break;
650    case PROT_C_HDLC:
651      printf("Cisco-HDLC/");
652      break;
653    case PROT_FRM_RLY:
654      printf("Frame-Relay/");
655      break;
656    case PROT_IP_HDLC:
657      printf("IP-in-HDLC/");
658      break;
659    case PROT_ETH_HDLC:
660      printf("Ether-in-HDLC/");
661      break;
662    case PROT_X25:
663      printf("X25+LAPB/");
664      break;
665    default:
666      printf("unknown line_prot: %d/", status.line_prot);
667      break;
668    }
669
670  switch (status.line_pkg)
671    {
672    case 0:
673      printf("NotSet\n");
674      break;
675    case PKG_RAWIP:
676      printf("Driver\n");
677      break;
678    case PKG_NG:
679      printf("Netgraph\n");
680      break;
681    case PKG_GEN_HDLC:
682      printf("GenHDLC\n");
683      break;
684    case PKG_SPPP:
685      printf("SPPP\n");
686      break;
687    case PKG_P2P:
688      printf("P2P\n");
689      break;
690    default:
691      printf("unknown line_pkg: %d\n", status.line_pkg);
692      break;
693    }
694
695  if (status.line_pkg == PKG_SPPP)
696    printf("SPPP Keep-alives:\t%s\n",
697     config.keep_alive ? on : off);
698}
699
700static void
701print_crc_len(void)
702{
703  printf("CRC length:\t\t");
704  if (config.crc_len == CFG_CRC_0)
705    printf("no CRC\n");
706  else if (config.crc_len == CFG_CRC_16)
707    printf("16 bits\n");
708  else if (config.crc_len == CFG_CRC_32)
709    printf("32 bits\n");
710  else
711    printf("bad crc_len: %d\n", config.crc_len);
712}
713
714static void
715print_loop_back(void)
716{
717  printf("Loopback:\t\t");
718  switch (config.loop_back)
719    {
720    case CFG_LOOP_NONE:
721      printf("None\n");
722      break;
723    case CFG_LOOP_PAYLOAD:
724      printf("Outward thru framer (payload loop)\n");
725      break;
726    case CFG_LOOP_LINE:
727      printf("Outward thru line interface (line loop)\n");
728      break;
729    case CFG_LOOP_OTHER:
730      printf("Inward thru line interface\n");
731      break;
732    case CFG_LOOP_INWARD:
733      printf("Inward thru framer\n");
734      break;
735    case CFG_LOOP_DUAL:
736      printf("Inward & outward (dual loop)\n");
737      break;
738    case CFG_LOOP_TULIP:
739      printf("Inward thru Tulip chip\n");
740      break;
741    case CFG_LOOP_PINS:
742      printf("Inward thru drvrs/rcvrs\n");
743      break;
744    case CFG_LOOP_LL:
745      printf("LA/LL asserted\n");
746      break;
747    case CFG_LOOP_RL:
748      printf("LB/RL asserted\n");
749      break;
750    default:
751      printf("unknown loop_back: %d\n", config.loop_back);
752      break;
753    }
754}
755
756static void
757print_tx_clk_src(void)
758{
759  printf("Tx Clk src:\t\t");
760  switch (config.tx_clk_src)
761    {
762    case CFG_CLKMUX_ST:
763      printf("Tx Clk from modem\n");
764      break;
765    case CFG_CLKMUX_INT:
766      printf("Internal source\n");
767      break;
768    case CFG_CLKMUX_RT:
769      printf("Rx Clk from modem (loop timed)\n");
770      break;
771    case CFG_CLKMUX_EXT:
772      printf("External connector\n");
773      break;
774    default:
775      printf("unknown tx_clk_src: %d\n", config.tx_clk_src);
776      break;
777    }
778}
779
780static void
781print_format(void)
782{
783  printf("Format-Frame/Code:\t");
784  switch (config.format)
785    {
786    case CFG_FORMAT_T1SF:
787      printf("T1-SF/AMI\n");
788      break;
789    case CFG_FORMAT_T1ESF:
790      printf("T1-ESF/B8ZS\n");
791      break;
792    case CFG_FORMAT_E1FAS:
793      printf("E1-FAS/HDB3\n");
794      break;
795    case CFG_FORMAT_E1FASCRC:
796      printf("E1-FAS+CRC/HDB3\n");
797      break;
798    case CFG_FORMAT_E1FASCAS:
799      printf("E1-FAS+CAS/HDB3\n");
800      break;
801    case CFG_FORMAT_E1FASCRCCAS:
802      printf("E1-FAS+CRC+CAS/HDB3\n");
803      break;
804    case CFG_FORMAT_E1NONE:
805      printf("E1-NOFRAMING/HDB3\n");
806      break;
807    case CFG_FORMAT_T3CPAR:
808      printf("T3-CParity/B3ZS\n");
809      break;
810    case CFG_FORMAT_T3M13:
811      printf("T3-M13/B3ZS\n");
812      break;
813    default:
814      printf("unknown format: %d\n", config.format);
815      break;
816    }
817}
818
819static void
820print_dte_dce(void)
821{
822  printf("DTE or DCE:\t\t");
823  switch(config.dte_dce)
824    {
825    case CFG_DTE:
826      printf("DTE (receiving TxClk)\n");
827      break;
828    case CFG_DCE:
829      printf("DCE (driving TxClk)\n");
830      break;
831    default:
832      printf("unknown dte_dce: %d\n", config.dte_dce);
833      break;
834    }
835}
836
837static void
838print_synth_freq(void)
839{
840  double Fref = 20e6;
841  double Fout, Fvco;
842
843  /* decode the synthesizer params */
844  Fvco = (Fref * (config.synth.n<<(3*config.synth.v)))/config.synth.m;
845  Fout =  Fvco / (1<<(config.synth.x+config.synth.r+config.synth.prescale));
846
847  printf("Synth freq:\t\t%.0f\n", Fout);
848}
849
850static void
851synth_freq(unsigned long target)
852{
853  unsigned int n, m, v, x, r;
854  double Fout, Fvco, Ftarg;
855  double newdiff, olddiff;
856  double bestF=0.0, bestV=0.0;
857  unsigned prescale = (target < 50000) ? 9:4;
858
859  Ftarg = target<<prescale;
860  for (n=3; n<=127; n++)
861    for (m=3; m<=127; m++)
862      for (v=0;  v<=1;  v++)
863        for (x=0;  x<=3;  x++)
864          for (r=0;  r<=3;  r++)
865            {
866            Fvco = (SYNTH_FREF * (n<<(3*v)))/m;
867            if (Fvco < SYNTH_FMIN || Fvco > SYNTH_FMAX) continue;
868            Fout =  Fvco / (1<<(x+r));
869            if (Fout >= Ftarg)
870              newdiff = Fout - Ftarg;
871            else
872              newdiff = Ftarg - Fout;
873            if (bestF >= Ftarg)
874              olddiff = bestF - Ftarg;
875            else
876              olddiff = Ftarg - bestF;
877            if ((newdiff < olddiff) ||
878               ((newdiff == olddiff) && (Fvco < bestV)))
879              {
880              config.synth.n = n;
881              config.synth.m = m;
882              config.synth.v = v;
883              config.synth.x = x;
884              config.synth.r = r;
885              config.synth.prescale = prescale;
886              bestF = Fout;
887              bestV = Fvco;
888	      }
889            }
890#if 0
891  printf("Fbest=%.0f, Ftarg=%u, Fout=%.0f\n", bestF>>prescale, target, bestF);
892  printf("N=%u, M=%u, V=%u, X=%u, R=%u\n", config.synth.n,
893   config.synth.m, config.synth.v, config.synth.x, config.synth.r);
894#endif
895}
896
897static void
898print_cable_len(void)
899{
900  printf("Cable length:\t\t%d meters\n", config.cable_len);
901}
902
903static void
904print_cable_type(void)
905{
906  printf("Cable type:\t\t");
907  if (status.cable_type > 7)
908    printf("unknown cable_type: %d\n", status.cable_type);
909  else
910    printf("%s\n", ssi_cables[status.cable_type]);
911}
912
913static void
914print_time_slots(void)
915{
916  printf("TimeSlot [31-0]:\t0x%08X\n", config.time_slots);
917}
918
919static void
920print_scrambler(void)
921{
922  printf("Scrambler:\t\t");
923  if (config.scrambler == CFG_SCRAM_OFF)
924    printf("off\n");
925  else if (config.scrambler == CFG_SCRAM_DL_KEN)
926    printf("DigLink/Kentrox: X^43+1\n");
927  else if (config.scrambler == CFG_SCRAM_LARS)
928    printf("Larse: X^20+X^17+1 w/28ZS\n");
929  else
930    printf("unknown scrambler: %d\n", config.scrambler);
931}
932
933static double
934vga_dbs(u_int8_t vga)
935{
936  if  (vga <  0x0F)                   return  0.0;
937  if ((vga >= 0x0F) && (vga <= 0x1B)) return  0.0 + 0.77 * (vga - 0x0F);
938  if ((vga >= 0x1C) && (vga <= 0x33)) return 10.0 + 1.25 * (vga - 0x1C);
939  if ((vga >= 0x34) && (vga <= 0x39)) return 40.0 + 1.67 * (vga - 0x34);
940  if ((vga >= 0x3A) && (vga <  0x3F)) return 50.0 + 2.80 * (vga - 0x3A);
941  return 64.0;
942}
943
944static void
945print_rx_gain(void)
946{
947  printf("Rx gain max:\t\t");
948
949  if (config.rx_gain == CFG_GAIN_AUTO)
950    printf("auto-set to %02.1f dB\n",
951     vga_dbs(read_framer(Bt8370_VGA_MAX) & 0x3F));
952  else
953    printf("up to %02.1f dB\n", vga_dbs(config.rx_gain));
954}
955
956static void
957print_tx_lbo(void)
958{
959  u_int8_t saved_lbo = config.tx_lbo;
960
961  printf("LBO = ");
962  if (config.tx_lbo == CFG_LBO_AUTO)
963    {
964    config.tx_lbo = read_framer(Bt8370_TLIU_CR) & 0x30;
965    printf("auto-set to ");
966    }
967
968  switch (config.tx_lbo)
969    {
970    case CFG_LBO_0DB:
971      printf("0 dB\n");
972      break;
973    case CFG_LBO_7DB:
974      printf("7.5 dB\n");
975      break;
976    case CFG_LBO_15DB:
977      printf("15 dB\n");
978      break;
979    case CFG_LBO_22DB:
980      printf("22.5 dB\n");
981      break;
982    default:
983      printf("unknown tx_lbo: %d\n", config.tx_lbo);
984      break;
985    }
986
987  if (saved_lbo == CFG_LBO_AUTO)
988    config.tx_lbo = saved_lbo;
989}
990
991static void
992print_tx_pulse(void)
993{
994  u_int8_t saved_pulse = config.tx_pulse;
995
996  printf("Tx pulse shape:\t\t");
997  if (config.tx_pulse == CFG_PULSE_AUTO)
998    {
999    config.tx_pulse = read_framer(Bt8370_TLIU_CR) & 0x0E;
1000    printf("auto-set to ");
1001    }
1002
1003  switch (config.tx_pulse)
1004    {
1005    case CFG_PULSE_T1DSX0:
1006      printf("T1-DSX: 0 to 40 meters\n");
1007      break;
1008    case CFG_PULSE_T1DSX1:
1009      printf("T1-DSX: 40 to 80 meters\n");
1010      break;
1011    case CFG_PULSE_T1DSX2:
1012      printf("T1-DSX: 80 to 120 meters\n");
1013      break;
1014    case CFG_PULSE_T1DSX3:
1015      printf("T1-DSX: 120 to 160 meters\n");
1016      break;
1017    case CFG_PULSE_T1DSX4:
1018      printf("T1-DSX: 160 to 200 meters\n");
1019      break;
1020    case CFG_PULSE_E1COAX:
1021      printf("E1: Twin Coax\n");
1022      break;
1023    case CFG_PULSE_E1TWIST:
1024      printf("E1: Twisted Pairs\n");
1025      break;
1026    case CFG_PULSE_T1CSU:
1027      printf("T1-CSU; ");
1028      print_tx_lbo();
1029      break;
1030    default:
1031      printf("unknown tx_pulse: %d\n", config.tx_pulse);
1032      break;
1033    }
1034
1035  if (saved_pulse == CFG_PULSE_AUTO)
1036    config.tx_pulse = saved_pulse;
1037}
1038
1039static void
1040print_ssi_sigs(void)
1041{
1042  u_int32_t mii16 = status.snmp.ssi.sigs;
1043  char *on = "On", *off = "Off";
1044
1045  printf("Modem signals:\t\tDTR=%s DSR=%s RTS=%s CTS=%s\n",
1046   (mii16 & MII16_SSI_DTR) ? on : off,
1047   (mii16 & MII16_SSI_DSR) ? on : off,
1048   (mii16 & MII16_SSI_RTS) ? on : off,
1049   (mii16 & MII16_SSI_CTS) ? on : off);
1050  printf("Modem signals:\t\tDCD=%s RI=%s LL=%s RL=%s TM=%s\n",
1051   (mii16 & MII16_SSI_DCD) ? on : off,
1052   (mii16 & MII16_SSI_RI)  ? on : off,
1053   (mii16 & MII16_SSI_LL)  ? on : off,
1054   (mii16 & MII16_SSI_RL)  ? on : off,
1055   (mii16 & MII16_SSI_TM)  ? on : off);
1056}
1057
1058static void
1059print_hssi_sigs(void)
1060{
1061  u_int32_t mii16 = status.snmp.hssi.sigs;
1062  char *on = "On", *off = "Off";
1063
1064  printf("Modem signals:\t\tTA=%s CA=%s\n",
1065   (mii16 & MII16_HSSI_TA) ? on : off,
1066   (mii16 & MII16_HSSI_CA) ? on : off);
1067  printf("Modem signals:\t\tLA=%s LB=%s LC=%s TM=%s\n",
1068   (mii16 & MII16_HSSI_LA) ? on : off,
1069   (mii16 & MII16_HSSI_LB) ? on : off,
1070   (mii16 & MII16_HSSI_LC) ? on : off,
1071   (mii16 & MII16_HSSI_TM) ? on : off);
1072}
1073
1074static void
1075print_events(void)
1076{
1077  const char *reset_time;
1078  time_t now;
1079
1080  now = time(NULL);
1081  printf("Current time:\t\t%s", ctime(&now));
1082  if (status.cntrs.reset_time.tv_sec < 1000)
1083    reset_time = "Never\n";
1084  else
1085    reset_time = ctime(&status.cntrs.reset_time.tv_sec);
1086  printf("Cntrs reset:\t\t%s", reset_time);
1087
1088  if (status.cntrs.ibytes)     printf("Rx bytes:\t\t%ju\n",    (uintmax_t)status.cntrs.ibytes);
1089  if (status.cntrs.obytes)     printf("Tx bytes:\t\t%ju\n",    (uintmax_t)status.cntrs.obytes);
1090  if (status.cntrs.ipackets)   printf("Rx packets:\t\t%ju\n",  (uintmax_t)status.cntrs.ipackets);
1091  if (status.cntrs.opackets)   printf("Tx packets:\t\t%ju\n",  (uintmax_t)status.cntrs.opackets);
1092  if (status.cntrs.ierrors)    printf("Rx errors:\t\t%u\n",    status.cntrs.ierrors);
1093  if (status.cntrs.oerrors)    printf("Tx errors:\t\t%u\n",    status.cntrs.oerrors);
1094  if (status.cntrs.idiscards)  printf("Rx discards:\t\t%u\n",  status.cntrs.idiscards);
1095  if (status.cntrs.odiscards)  printf("Tx discards:\t\t%u\n",  status.cntrs.odiscards);
1096  if (status.cntrs.fifo_over)  printf("Rx fifo overruns:\t%u\n", status.cntrs.fifo_over);
1097  if (status.cntrs.fifo_under) printf("Tx fifo underruns:\t%u\n", status.cntrs.fifo_under);
1098  if (status.cntrs.missed)     printf("Rx missed:\t\t%u\n",    status.cntrs.missed);
1099  if (status.cntrs.overruns)   printf("Rx overruns:\t\t%u\n",  status.cntrs.overruns);
1100  if (status.cntrs.fdl_pkts)   printf("Rx FDL pkts:\t\t%u\n",  status.cntrs.fdl_pkts);
1101  if (status.cntrs.crc_errs)   printf("Rx CRC:\t\t\t%u\n",     status.cntrs.crc_errs);
1102  if (status.cntrs.lcv_errs)   printf("Rx line code:\t\t%u\n", status.cntrs.lcv_errs);
1103  if (status.cntrs.frm_errs)   printf("Rx F-bits:\t\t%u\n",    status.cntrs.frm_errs);
1104  if (status.cntrs.febe_errs)  printf("Rx FEBE:\t\t%u\n",      status.cntrs.febe_errs);
1105  if (status.cntrs.par_errs)   printf("Rx P-parity:\t\t%u\n",  status.cntrs.par_errs);
1106  if (status.cntrs.cpar_errs)  printf("Rx C-parity:\t\t%u\n",  status.cntrs.cpar_errs);
1107  if (status.cntrs.mfrm_errs)  printf("Rx M-bits:\t\t%u\n",    status.cntrs.mfrm_errs);
1108  if (config.debug)
1109    { /* These events are hard to explain and may worry users, */
1110    if (status.cntrs.rxdma)     printf("Rx no buffs:\t\t%u\n", status.cntrs.rxdma);
1111    if (status.cntrs.txdma)     printf("Tx no descs:\t\t%u\n", status.cntrs.txdma);
1112    if (status.cntrs.lck_watch) printf("Lck watch:\t\t%u\n",   status.cntrs.lck_watch);
1113    if (status.cntrs.lck_ioctl) printf("Lck ioctl:\t\t%u\n",   status.cntrs.lck_ioctl);
1114    if (status.cntrs.lck_intr)  printf("Lck intr:\t\t%u\n",    status.cntrs.lck_intr);
1115    }
1116}
1117
1118static void
1119print_summary(void)
1120{
1121  switch(status.card_type)
1122    {
1123    case TLP_CSID_HSSI:
1124      {
1125      print_card_name();
1126      print_card_type();
1127      print_debug();
1128      print_status();
1129      print_tx_speed();
1130      print_line_prot();
1131      print_crc_len();
1132      print_loop_back();
1133      print_tx_clk_src();
1134      print_hssi_sigs();
1135      print_events();
1136      break;
1137      }
1138    case TLP_CSID_T3:
1139      {
1140      print_card_name();
1141      print_card_type();
1142      print_debug();
1143      print_status();
1144      print_tx_speed();
1145      print_line_prot();
1146      print_crc_len();
1147      print_loop_back();
1148      print_format();
1149      print_cable_len();
1150      print_scrambler();
1151      print_events();
1152      break;
1153      }
1154    case TLP_CSID_SSI:
1155      {
1156      print_card_name();
1157      print_card_type();
1158      print_debug();
1159      print_status();
1160      print_tx_speed();
1161      print_line_prot();
1162      print_crc_len();
1163      print_loop_back();
1164      print_dte_dce();
1165      print_synth_freq();
1166      print_cable_type();
1167      print_ssi_sigs();
1168      print_events();
1169      break;
1170      }
1171    case TLP_CSID_T1E1:
1172      {
1173      print_card_name();
1174      print_card_type();
1175      print_debug();
1176      print_status();
1177      print_tx_speed();
1178      print_line_prot();
1179      print_crc_len();
1180      print_loop_back();
1181      print_tx_clk_src();
1182      print_format();
1183      print_time_slots();
1184      print_cable_len();
1185      print_tx_pulse();
1186      print_rx_gain();
1187      print_events();
1188      break;
1189      }
1190    case TLP_CSID_HSSIc:
1191      {
1192      print_card_name();
1193      print_card_type();
1194      print_debug();
1195      print_status();
1196      print_line_prot();
1197      print_tx_speed();
1198      print_crc_len();
1199      print_loop_back();
1200      print_tx_clk_src();
1201      print_dte_dce();
1202      print_synth_freq();
1203      print_hssi_sigs();
1204      print_events();
1205      break;
1206      }
1207    default:
1208      {
1209      printf("%s: Unknown card type: %d\n", ifname, status.card_type);
1210      break;
1211      }
1212    }
1213}
1214
1215static char *
1216print_t3_bop(int bop_code)
1217{
1218  switch(bop_code)
1219    {
1220    case 0x00:
1221      return "far end LOF";
1222    case 0x0E:
1223      return "far end LOS";
1224    case 0x16:
1225      return "far end AIS";
1226    case 0x1A:
1227      return "far end IDL";
1228    case 0x07:
1229      return "Line Loopback activate";
1230    case 0x1C:
1231      return "Line Loopback deactivate";
1232    case 0x1B:
1233      return "Entire DS3 line";
1234    default:
1235      return "Unknown BOP code";
1236    }
1237}
1238
1239static void
1240print_t3_snmp(void)
1241{
1242  printf("SNMP performance data:\n");
1243  printf(" LCV=%d",  status.snmp.t3.lcv);
1244  printf(" LOS=%d", (status.snmp.t3.line & TLINE_LOS)    ? 1 : 0);
1245  printf(" PCV=%d",  status.snmp.t3.pcv);
1246  printf(" CCV=%d",  status.snmp.t3.ccv);
1247  printf(" AIS=%d", (status.snmp.t3.line & TLINE_RX_AIS) ? 1 : 0);
1248  printf(" SEF=%d", (status.snmp.t3.line & T1LINE_SEF)   ? 1 : 0);
1249  printf(" OOF=%d", (status.snmp.t3.line & TLINE_LOF)    ? 1 : 0);
1250  printf("  FEBE=%d", status.snmp.t3.febe);
1251  printf(" RAI=%d", (status.snmp.t3.line & TLINE_RX_RAI) ? 1 : 0);
1252  printf("\n");
1253}
1254
1255static void
1256print_t3_dsu(void)
1257{
1258  char *no = "No", *yes = "Yes";
1259  u_int16_t mii16 = read_mii(16);
1260  u_int8_t ctl1   = read_framer(T3CSR_CTL1);
1261  u_int8_t ctl8   = read_framer(T3CSR_CTL8);
1262  u_int8_t stat9  = read_framer(T3CSR_STAT9);
1263  u_int8_t ctl12  = read_framer(T3CSR_CTL12);
1264  u_int8_t stat16 = read_framer(T3CSR_STAT16);
1265
1266  printf("Framing:       \t\t%s\n", ctl1   & CTL1_M13MODE    ? "M13" : "CPAR");
1267  print_tx_speed();
1268  printf("Scrambler:     \t\t%s\n", mii16  & MII16_DS3_SCRAM ? yes : no);
1269  printf("Scram poly:    \t\t%s\n", mii16  & MII16_DS3_POLY  ? "X^20" : "X^43");
1270  printf("Cable length   \t\t%s\n", mii16  & MII16_DS3_ZERO  ? "Short" : "Long");
1271  printf("Line    loop:  \t\t%s\n", mii16  & MII16_DS3_LNLBK ? yes : no);
1272  printf("Payload loop:  \t\t%s\n", ctl12  & CTL12_RTPLOOP   ? yes : no);
1273  printf("Frame   loop:  \t\t%s\n", ctl1   & CTL1_3LOOP      ? yes : no);
1274  printf("Host    loop:  \t\t%s\n", mii16  & MII16_DS3_TRLBK ? yes : no);
1275  printf("Transmit RAI:  \t\t%s\n", ctl1   & CTL1_XTX        ? no  : yes);
1276  printf("Receive  RAI   \t\t%s\n", stat16 & STAT16_XERR     ? yes : no);
1277  printf("Transmit AIS:  \t\t%s\n", ctl1   & CTL1_TXAIS      ? yes : no);
1278  printf("Receive  AIS:  \t\t%s\n", stat16 & STAT16_RAIS     ? yes : no);
1279  printf("Transmit IDLE: \t\t%s\n", ctl1   & CTL1_TXIDL      ? yes : no);
1280  printf("Receive  IDLE: \t\t%s\n", stat16 & STAT16_RIDL     ? yes : no);
1281  printf("Transmit BLUE: \t\t%s\n", ctl8   & CTL8_TBLU       ? yes : no);
1282  printf("Receive  BLUE: \t\t%s\n", stat9  & STAT9_RBLU      ? yes : no);
1283  printf("Loss of Signal:\t\t%s\n", stat16 & STAT16_RLOS     ? yes : no);
1284  printf("Loss of Frame: \t\t%s\n", stat16 & STAT16_ROOF     ? yes : no);
1285  printf("Sev Err Frms:  \t\t%s\n", stat16 & STAT16_SEF      ? yes : no);
1286  printf("Code  errors:  \t\t%d\n", read_framer(T3CSR_CVLO) + (read_framer(T3CSR_CVHI)<<8));
1287  printf("C-Par errors:  \t\t%d\n", read_framer(T3CSR_CERR));
1288  printf("P-Par errors:  \t\t%d\n", read_framer(T3CSR_PERR));
1289  printf("F-Bit errors:  \t\t%d\n", read_framer(T3CSR_FERR));
1290  printf("M-Bit errors:  \t\t%d\n", read_framer(T3CSR_MERR));
1291  printf("FarEndBitErrs: \t\t%d\n", read_framer(T3CSR_FEBE));
1292  printf("Last Tx  FEAC msg:\t0x%02X (%s)\n",
1293   read_framer(T3CSR_TX_FEAC)  & 0x3F,
1294   print_t3_bop(read_framer(T3CSR_TX_FEAC) & 0x3F));
1295  printf("Last dbl FEAC msg;\t0x%02X (%s)\n",
1296   read_framer(T3CSR_DBL_FEAC) & 0x3F,
1297   print_t3_bop(read_framer(T3CSR_DBL_FEAC) & 0x3F));
1298  printf("Last Rx  FEAC msg:\t0x%02X (%s)\n",
1299   read_framer(T3CSR_RX_FEAC)  & 0x3F,
1300   print_t3_bop(read_framer(T3CSR_RX_FEAC) & 0x3F));
1301  print_t3_snmp();
1302}
1303
1304static void
1305t3_cmd(int argc, char **argv)
1306{
1307  int ch;
1308
1309  while ((ch = getopt(argc, argv, "a:A:B:c:de:fF:lLsS:vV:")) != -1)
1310    {
1311    switch (ch)
1312      {
1313      case 'a': /* stop alarms */
1314        {
1315        switch (optarg[0])
1316          {
1317          case 'a': /* Stop sending AIS Signal */
1318            {
1319            write_mii(16,
1320             read_mii(16) & ~MII16_DS3_FRAME);
1321            write_framer(T3CSR_CTL1,
1322             read_framer(T3CSR_CTL1) & ~CTL1_TXAIS);
1323            if (verbose) printf("Stop sending Alarm Indication Signal (AIS)\n");
1324            break;
1325            }
1326          case 'b': /* Stop sending Blue signal */
1327            {
1328            write_mii(16,
1329             read_mii(16) & ~MII16_DS3_FRAME);
1330            write_framer(T3CSR_CTL8,
1331             read_framer(T3CSR_CTL8) & ~CTL8_TBLU);
1332            if (verbose) printf("Stop sending Blue signal\n");
1333            break;
1334            }
1335          case 'i': /* Stop sending IDLE signal */
1336            {
1337            write_framer(T3CSR_CTL1,
1338             read_framer(T3CSR_CTL1) & ~CTL1_TXIDL);
1339            if (verbose) printf("Stop sending IDLE signal\n");
1340            break;
1341            }
1342          case 'y': /* Stop sending Yellow alarm */
1343            {
1344            write_framer(T3CSR_CTL1,
1345             read_framer(T3CSR_CTL1) | CTL1_XTX);
1346            if (verbose) printf("Stop sending Yellow alarm\n");
1347            break;
1348            }
1349          default:
1350            printf("Unknown alarm: %c\n", optarg[0]);
1351            break;
1352          }
1353        break;
1354        }
1355      case 'A': /* start alarms */
1356        {
1357        switch (optarg[0])
1358          {
1359          case 'a': /* Start sending AIS Signal */
1360            {
1361            write_mii(16,
1362             read_mii(16) | MII16_DS3_FRAME);
1363            write_framer(T3CSR_CTL1,
1364             read_framer(T3CSR_CTL1) | CTL1_TXAIS);
1365            if (verbose) printf("Sending AIS signal (framed 1010..)\n");
1366            break;
1367            }
1368          case 'b': /* Start sending Blue signal */
1369            {
1370            write_mii(16,
1371             read_mii(16) | MII16_DS3_FRAME);
1372            write_framer(T3CSR_CTL8,
1373             read_framer(T3CSR_CTL8) | CTL8_TBLU);
1374            if (verbose) printf("Sending Blue signal (unframed all 1s)\n");
1375            break;
1376            }
1377          case 'i': /* Start sending IDLE signal */
1378            {
1379            write_framer(T3CSR_CTL1,
1380             read_framer(T3CSR_CTL1) | CTL1_TXIDL);
1381            if (verbose) printf("Sending IDLE signal (framed 1100..)\n");
1382            break;
1383            }
1384          case 'y': /* Start sending Yellow alarm */
1385            {
1386            write_framer(T3CSR_CTL1,
1387             read_framer(T3CSR_CTL1) & ~CTL1_XTX);
1388            if (verbose) printf("Sending Yellow alarm (X-bits=0)\n");
1389            break;
1390            }
1391          default:
1392            printf("Unknown alarm: %c\n", optarg[0]);
1393            break;
1394          }
1395        break;
1396        }
1397      case 'B': /* send BOP msg */
1398        {
1399        u_int8_t bop = strtoul(optarg, NULL, 0);
1400        write_framer(T3CSR_TX_FEAC,  0xC0 + bop);
1401        if (verbose) printf("Sent '0x%02X' BOP msg 10 times\n", bop);
1402        break;
1403	}
1404      case 'c': /* set cable length */
1405        {
1406        config.cable_len = strtoul(optarg, NULL, 0);
1407        if (verbose) print_cable_len();
1408        update = 1;
1409        break;
1410        }
1411      case 'd': /* DSU status */
1412      case 's': /* deprecated */
1413        {
1414        print_t3_dsu();
1415        break;
1416        }
1417      case 'e': /* set framimg format */
1418        {
1419        config.format = strtoul(optarg, NULL, 0);
1420        if (verbose) print_format();
1421        update = 1;
1422        break;
1423        }
1424      case 'f': /* read and print framer regs */
1425        {
1426        int i;
1427        printf("TXC03401 regs:\n");
1428        printf("     0  1  2  3  4  5  6  7");
1429        for (i=0; i<21; i++)
1430          {
1431          if (i%8 == 0) printf("\n%02X: ", i);
1432          printf("%02X ", read_framer(i));
1433          }
1434        printf("\n\n");
1435        break;
1436        }
1437      case 'F': /* write framer reg */
1438        {
1439        u_int32_t addr = strtoul(optarg, NULL, 0);
1440        u_int32_t data = strtoul(argv[optind++], NULL, 0);
1441        write_framer(addr, data);
1442        if (verbose)
1443          {
1444          data = read_framer(addr);
1445          printf("Write framer register: addr = 0x%02X data = 0x%02X\n", addr, data);
1446	  }
1447        break;
1448        }
1449      case 'l': /* send DS3 line loopback deactivate BOP cmd */
1450        {
1451        ioctl_snmp_send(TSEND_RESET);
1452        if (verbose) printf("Sent 'DS3 Line Loopback deactivate' BOP cmd\n");
1453        break;
1454        }
1455      case 'L': /* send DS3 line loopback activate BOP cmd */
1456        {
1457        ioctl_snmp_send(TSEND_LINE);
1458        if (verbose) printf("Sent 'DS3 Line Loopback activate' BOP cmd\n");
1459        break;
1460        }
1461      case 'S': /* set scrambler */
1462        {
1463        config.scrambler = strtoul(optarg, NULL, 0);
1464        if (verbose) print_scrambler();
1465        update = 1;
1466        break;
1467        }
1468      case 'v': /* set verbose mode */
1469        {
1470        verbose = 1;
1471        break;
1472        }
1473      case 'V': /* set T3 freq control DAC */
1474        {
1475        u_int32_t dac = strtoul(optarg, NULL, 0);
1476        write_dac(dac);
1477        if (verbose) printf("VCXO DAC value is %d\n", dac);
1478        break;
1479        }
1480      default:
1481        {
1482        printf("Unknown command char: %c\n", ch);
1483        exit(1);
1484        } /* case */
1485      } /* switch */
1486    } /* while */
1487} /* proc */
1488
1489static void
1490print_test_pattern(int patt)
1491{
1492  printf("Test Pattern:\t\t");
1493  switch (patt)
1494    {
1495    case 0:
1496      printf("unframed X^11+X^9+1\n");
1497      break;
1498    case 1:
1499      printf("unframed X^15+X^14+1\n");
1500      break;
1501    case 2:
1502      printf("unframed X^20+X^17+1\n");
1503      break;
1504    case 3:
1505      printf("unframed X^23+X^18+1\n");
1506      break;
1507    case 4:
1508      printf("unframed X^11+X^9+1 w/7ZS\n");
1509      break;
1510    case 5:
1511      printf("unframed X^15+X^14+1 w/7ZS\n");
1512      break;
1513    case 6:
1514      printf("unframed X^20+X^17+1 w/14ZS (QRSS)\n");
1515      break;
1516    case 7:
1517      printf("unframed X^23+X^18+1 w/14ZS\n");
1518      break;
1519    case 8:
1520      printf("framed X^11+X^9+1\n");
1521      break;
1522    case 9:
1523      printf("framed X^15+X^14+1\n");
1524      break;
1525    case 10:
1526      printf("framed X^20+X^17+1\n");
1527      break;
1528    case 11:
1529      printf("framed X^23+X^18+1\n");
1530      break;
1531    case 12:
1532      printf("framed X^11+X^9+1 w/7ZS\n");
1533      break;
1534    case 13:
1535      printf("framed X^15+X^14+1 w/7ZS\n");
1536      break;
1537    case 14:
1538      printf("framed X^20+X^17+1 w/14ZS (QRSS)\n");
1539      break;
1540    case 15:
1541      printf("framed X^23+X^18+1 w/14ZS\n");
1542      break;
1543    }
1544}
1545
1546static char *
1547print_t1_bop(int bop_code)
1548{
1549  switch(bop_code)
1550    {
1551    case 0x00:
1552      return "Yellow Alarm (far end LOF)";
1553    case 0x07:
1554      return "Line Loop up";
1555    case 0x1C:
1556      return "Line Loop down";
1557    case 0x0A:
1558      return "Payload Loop up";
1559    case 0x19:
1560      return "Payload Loop down";
1561    case 0x09:
1562      return "Network Loop up";
1563    case 0x12:
1564      return "Network Loop down";
1565    default:
1566      return "Unknown BOP code";
1567    }
1568}
1569
1570static void
1571print_far_report(int index)
1572{
1573  u_int16_t far = status.snmp.t1.prm[index];
1574
1575  printf(" SEQ=%d ", (far & T1PRM_SEQ)>>8);
1576  if      (far & T1PRM_G1) printf("CRC=1");
1577  else if (far & T1PRM_G2) printf("CRC=1 to 5");
1578  else if (far & T1PRM_G3) printf("CRC=5 to 10");
1579  else if (far & T1PRM_G4) printf("CRC=10 to 100");
1580  else if (far & T1PRM_G5) printf("CRC=100 to 319");
1581  else if (far & T1PRM_G6) printf("CRC>=320");
1582  else                     printf("CRC=0");
1583  printf(" SE=%d", (far & T1PRM_SE) ? 1 : 0);
1584  printf(" FE=%d", (far & T1PRM_FE) ? 1 : 0);
1585  printf(" LV=%d", (far & T1PRM_LV) ? 1 : 0);
1586  printf(" SL=%d", (far & T1PRM_SL) ? 1 : 0);
1587  printf(" LB=%d", (far & T1PRM_LB) ? 1 : 0);
1588  printf("\n");
1589}
1590
1591static void
1592print_t1_snmp(void)
1593{
1594  printf("SNMP Near-end performance data:\n");
1595  printf(" LCV=%d",  status.snmp.t1.lcv);
1596  printf(" LOS=%d", (status.snmp.t1.line & TLINE_LOS)    ? 1 : 0);
1597  printf(" FE=%d",   status.snmp.t1.fe);
1598  printf(" CRC=%d",  status.snmp.t1.crc);
1599  printf(" AIS=%d", (status.snmp.t1.line & TLINE_RX_AIS) ? 1 : 0);
1600  printf(" SEF=%d", (status.snmp.t1.line & T1LINE_SEF)   ? 1 : 0);
1601  printf(" OOF=%d", (status.snmp.t1.line & TLINE_LOF)    ? 1 : 0);
1602  printf("  RAI=%d",(status.snmp.t1.line & TLINE_RX_RAI) ? 1 : 0);
1603  printf("\n");
1604  if (config.format == CFG_FORMAT_T1ESF)
1605    {
1606    printf("ANSI Far-end performance reports:\n");
1607    print_far_report(0);
1608    print_far_report(1);
1609    print_far_report(2);
1610    print_far_report(3);
1611    }
1612}
1613
1614static void
1615print_t1_dsu(void)
1616{
1617  char *no = "No", *yes = "Yes";
1618  u_int16_t mii16  = read_mii(16);
1619  u_int8_t isr0    = read_framer(Bt8370_ISR0);
1620  u_int8_t loop    = read_framer(Bt8370_LOOP);
1621  u_int8_t vga_max = read_framer(Bt8370_VGA_MAX) & 0x3F;
1622  u_int8_t alm1    = read_framer(Bt8370_ALM1);
1623  u_int8_t alm3    = read_framer(Bt8370_ALM3);
1624  u_int8_t talm    = read_framer(Bt8370_TALM);
1625  u_int8_t tpatt   = read_framer(Bt8370_TPATT);
1626  u_int8_t tpulse  = read_framer(Bt8370_TLIU_CR);
1627  u_int8_t vga;
1628  u_int8_t saved_pulse, saved_lbo;
1629
1630  /* d/c write required before read */
1631  write_framer(Bt8370_VGA, 0);
1632  vga = read_framer(Bt8370_VGA) & 0x3F;
1633
1634  print_format();
1635  print_time_slots();
1636  print_tx_clk_src();
1637  print_tx_speed();
1638
1639  saved_pulse     = config.tx_pulse;
1640  config.tx_pulse = tpulse & 0x0E;
1641  saved_lbo       = config.tx_lbo;
1642  config.tx_lbo   = tpulse & 0x30;
1643  print_tx_pulse();
1644  config.tx_pulse = saved_pulse;
1645  config.tx_lbo   = saved_lbo;
1646
1647  printf("Tx outputs:    \t\t%sabled\n", (mii16 & MII16_T1_XOE) ? "En" : "Dis");
1648  printf("Line impedance:\t\t%s ohms\n", (mii16 & MII16_T1_Z) ? "120" : "100");
1649  printf("Max line loss: \t\t%4.1f dB\n", vga_dbs(vga_max));
1650  printf("Cur line loss: \t\t%4.1f dB\n", vga_dbs(vga));
1651  printf("Invert data:   \t\t%s\n", (mii16 & MII16_T1_INVERT) ? yes : no);
1652  printf("Line    loop:  \t\t%s\n", (loop & LOOP_LINE)    ? yes : no);
1653  printf("Payload loop:  \t\t%s\n", (loop & LOOP_PAYLOAD) ? yes : no);
1654  printf("Framer  loop:  \t\t%s\n", (loop & LOOP_FRAMER)  ? yes : no);
1655  printf("Analog  loop:  \t\t%s\n", (loop & LOOP_ANALOG)  ? yes : no);
1656  printf("Tx AIS:        \t\t%s\n", ((talm & TALM_TAIS) ||
1657   ((talm & TALM_AUTO_AIS) && (alm1 & ALM1_RLOS))) ? yes : no);
1658  printf("Rx AIS:        \t\t%s\n", (alm1 & ALM1_RAIS)  ? yes : no);
1659  if (((config.format & 1)==0) && (config.format != CFG_FORMAT_E1NONE))
1660    {
1661    printf("Tx RAI:        \t\t%s\n", ((talm & TALM_TYEL) ||
1662     ((talm & TALM_AUTO_YEL) && (alm3 & ALM3_FRED))) ? yes : no);
1663    printf("Rx RAI:        \t\t%s\n", (alm1 & ALM1_RYEL)  ? yes : no);
1664    }
1665  if (config.format == CFG_FORMAT_T1ESF)
1666    {
1667    printf("Tx BOP RAI:    \t\t%s\n", (alm1 & ALM1_RLOF)  ? yes : no);
1668    printf("Rx BOP RAI:    \t\t%s\n", (alm1 & ALM1_RMYEL) ? yes : no);
1669    }
1670  if ((config.format & 0x11) == 0x10) /* E1CAS */
1671    {
1672    printf("Rx TS16 AIS:   \t\t%s\n", (alm3 & ALM3_RMAIS) ? yes : no);
1673    printf("Tx TS16 RAI;   \t\t%s\n",
1674     ((talm & TALM_AUTO_MYEL) && (alm3 & ALM3_SRED)) ? yes : no);
1675    }
1676  printf("Rx LOS analog: \t\t%s\n", (alm1 & ALM1_RALOS) ? yes : no);
1677  printf("Rx LOS digital:\t\t%s\n", (alm1 & ALM1_RLOS)  ? yes : no);
1678  printf("Rx LOF:        \t\t%s\n", (alm1 & ALM1_RLOF)  ? yes : no);
1679  printf("Tx QRS:        \t\t%s\n", (tpatt & 0x10)      ? yes : no);
1680  printf("Rx QRS:        \t\t%s\n", (isr0 & 0x10)       ? yes : no);
1681  printf("LCV errors:    \t\t%d\n",
1682   read_framer(Bt8370_LCV_LO)  + (read_framer(Bt8370_LCV_HI)<<8));
1683  if (config.format != CFG_FORMAT_E1NONE)
1684    {
1685    if ((config.format & 1)==0) printf("Far End Block Errors:\t%d\n",
1686     read_framer(Bt8370_FEBE_LO) + (read_framer(Bt8370_FEBE_HI)<<8));
1687    printf("CRC errors:    \t\t%d\n",
1688     read_framer(Bt8370_CRC_LO)  + (read_framer(Bt8370_CRC_HI)<<8));
1689    printf("Frame errors:  \t\t%d\n",
1690     read_framer(Bt8370_FERR_LO) + (read_framer(Bt8370_FERR_HI)<<8));
1691    printf("Sev Err Frms:  \t\t%d\n", read_framer(Bt8370_AERR) & 0x03);
1692    printf("Change of Frm align:\t%d\n",  (read_framer(Bt8370_AERR) & 0x0C)>>2);
1693    printf("Loss of Frame events:\t%d\n", (read_framer(Bt8370_AERR) & 0xF0)>>4);
1694    }
1695  if (config.format == CFG_FORMAT_T1ESF)
1696    {
1697    printf("Last Tx BOP msg:\t0x%02X (%s)\n",
1698     read_framer(Bt8370_TBOP), print_t1_bop(read_framer(Bt8370_TBOP)));
1699    printf("Last Rx BOP msg:\t0x%02X (%s)\n",
1700     read_framer(Bt8370_RBOP), print_t1_bop(read_framer(Bt8370_RBOP)&0x3F));
1701    }
1702  print_t1_snmp();
1703}
1704
1705static void
1706t1_cmd(int argc, char **argv)
1707{
1708  int ch;
1709
1710  while ((ch = getopt(argc, argv, "a:A:B:c:de:E:fF:g:iIlLpPstT:u:U:vxX")) != -1)
1711    {
1712    switch (ch)
1713      {
1714      case 'a': /* stop alarms */
1715        {
1716        switch (optarg[0])
1717          {
1718          case 'y': /* Stop sending Yellow Alarm */
1719            {
1720            if ((config.format == CFG_FORMAT_T1SF) ||
1721                (config.format == CFG_FORMAT_E1NONE))
1722              printf("No Yellow alarm for this frame format\n");
1723            else if (config.format == CFG_FORMAT_T1ESF)
1724              write_framer(Bt8370_BOP,  0xE0); /* rbop 25, tbop off */
1725            else
1726              {
1727              u_int8_t talm = read_framer(Bt8370_TALM);
1728              write_framer(Bt8370_TALM, talm & ~TALM_TYEL);
1729	      }
1730            if (verbose) printf("Stop sending Yellow alarm\n");
1731            break;
1732            }
1733          case 'a': /* Stop sending AIS */
1734          case 'b': /* Stop sending Blue Alarm */
1735            {
1736            u_int8_t talm = read_framer(Bt8370_TALM);
1737            write_framer(Bt8370_TALM, talm & ~TALM_TAIS);
1738            if (verbose) printf("Stop sending AIS/Blue signal\n");
1739            break;
1740            }
1741          default:
1742            printf("Unknown alarm: %c\n", optarg[0]);
1743          }
1744        break;
1745        }
1746      case 'A': /* start alarms */
1747        {
1748        switch (optarg[0])
1749          {
1750          case 'y': /* Start sending Yellow Alarm */
1751            {
1752            if ((config.format == CFG_FORMAT_T1SF) ||
1753                (config.format == CFG_FORMAT_E1NONE))
1754              printf("No Yellow alarm for this frame format\n");
1755            else if (config.format == CFG_FORMAT_T1ESF)
1756              {
1757              write_framer(Bt8370_BOP,  0x0F); /* rbop off, tbop cont */
1758              write_framer(Bt8370_TBOP, T1BOP_OOF);
1759	      }
1760            else
1761              {
1762              u_int8_t talm = read_framer(Bt8370_TALM);
1763              write_framer(Bt8370_TALM, talm | TALM_TYEL);
1764	      }
1765            if (verbose) printf("Sending Yellow alarm\n");
1766            break;
1767            }
1768          case 'a': /* Start sending AIS */
1769          case 'b': /* Start sending Blue Alarm */
1770            {
1771            u_int8_t talm = read_framer(Bt8370_TALM);
1772            write_framer(Bt8370_TALM, talm | TALM_TAIS);
1773            if (verbose) printf("Sending AIS/Blue signal\n");
1774            break;
1775            }
1776          default:
1777            printf("Unknown alarm: %c\n", optarg[0]);
1778          }
1779        break;
1780        }
1781      case 'B': /* send BOP msg */
1782        {
1783        u_int8_t bop = strtoul(optarg, NULL, 0);
1784        if (config.format == CFG_FORMAT_T1ESF)
1785          {
1786          write_framer(Bt8370_BOP, 0x0B); /* rbop off, tbop 25 */
1787          write_framer(Bt8370_TBOP, bop); /* start sending BOP msg */
1788          sleep(1);  /* sending 25 BOP msgs takes about 100 ms. */
1789          write_framer(Bt8370_BOP, 0xE0); /* rbop 25, tbop off */
1790          if (verbose) printf("Sent '0x%02X' BOP msg 25 times\n", bop);
1791	  }
1792        else
1793          printf("BOP msgs only work in T1-ESF format\n");
1794        break;
1795	}
1796      case 'c': /* set cable length */
1797        {
1798        config.cable_len = strtoul(optarg, NULL, 0);
1799        if (verbose) print_cable_len();
1800        update = 1;
1801        break;
1802        }
1803      case 'd': /* DSU status */
1804      case 's': /* deprecated */
1805        {
1806        print_t1_dsu();
1807        break;
1808        }
1809      case 'e': /* set framimg format */
1810        {
1811        config.format = strtoul(optarg, NULL, 0);
1812        if (verbose) print_format();
1813        update = 1;
1814        break;
1815        }
1816      case 'E': /* set time slots */
1817        {
1818        config.time_slots = strtoul(optarg, NULL, 16);
1819        if (verbose) print_time_slots();
1820        update = 1;
1821        break;
1822        }
1823      case 'f': /* read and print framer regs */
1824        {
1825        int i;
1826        printf("Bt8370 regs:\n");
1827        printf("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
1828        for (i=0; i<512; i++)
1829          {
1830          if (i%16 == 0) printf("\n%03X: ", i);
1831          printf("%02X ", read_framer(i));
1832	  }
1833        printf("\n\n");
1834        break;
1835	}
1836      case 'F': /* write framer reg */
1837        {
1838        u_int32_t addr = strtoul(optarg, NULL, 0);
1839        u_int32_t data = strtoul(argv[optind++], NULL, 0);
1840        write_framer(addr, data);
1841        if (verbose)
1842          {
1843          data = read_framer(addr);
1844          printf("Write framer register: addr = 0x%02X data = 0x%02X\n", addr, data);
1845	  }
1846        break;
1847	}
1848      case 'g': /* set receiver gain */
1849        {
1850        config.rx_gain = strtoul(optarg, NULL, 0);
1851        if (verbose) print_rx_gain();
1852        update = 1;
1853        break;
1854        }
1855      case 'i': /* send CSU loopback deactivate inband cmd */
1856        {
1857        if (config.format == CFG_FORMAT_T1SF)
1858          {
1859          if (verbose) printf("Sending 'CSU loop down' inband cmd for 10 secs...");
1860          ioctl_snmp_send(TSEND_RESET);
1861          sleep(10);
1862          ioctl_snmp_send(TSEND_NORMAL);
1863          if (verbose) printf("done\n");
1864	  }
1865        else
1866          printf("Inband loopback cmds only work in T1-SF format");
1867        break;
1868        }
1869      case 'I': /* send CSU loopback activate inband cmd */
1870        {
1871        if (config.format == CFG_FORMAT_T1SF)
1872          {
1873          if (verbose) printf("Sending 'CSU loop up' inband cmd for 10 secs...");
1874          ioctl_snmp_send(TSEND_LINE);
1875          sleep(10);
1876          ioctl_snmp_send(TSEND_NORMAL);
1877          if (verbose) printf("done\n");
1878	  }
1879        else
1880          printf("Inband loopback cmds only work in T1-SF format");
1881        break;
1882        }
1883      case 'l': /* send line loopback deactivate BOP msg */
1884        {
1885        if (config.format == CFG_FORMAT_T1ESF)
1886          {
1887          ioctl_snmp_send(TSEND_RESET);
1888          if (verbose) printf("Sent 'Line Loop Down' BOP cmd\n");
1889	  }
1890        else
1891          printf("BOP msgs only work in T1-ESF format\n");
1892        break;
1893        }
1894      case 'L': /* send line loopback activate BOP msg */
1895        {
1896        if (config.format == CFG_FORMAT_T1ESF)
1897          {
1898          ioctl_snmp_send(TSEND_LINE);
1899          if (verbose) printf("Sent 'Line Loop Up' BOP cmd\n");
1900	  }
1901        else
1902          printf("BOP msgs only work in T1-ESF format\n");
1903        break;
1904        }
1905      case 'p': /* send payload loopback deactivate BOP msg */
1906        {
1907        if (config.format == CFG_FORMAT_T1ESF)
1908          {
1909          ioctl_snmp_send(TSEND_RESET);
1910          if (verbose) printf("Sent 'Payload Loop Down' BOP cmd\n");
1911	  }
1912        else
1913          printf("BOP msgs only work in T1-ESF format\n");
1914        break;
1915        }
1916      case 'P': /* send payload loopback activate BOP msg */
1917        {
1918        if (config.format == CFG_FORMAT_T1ESF)
1919          {
1920          ioctl_snmp_send(TSEND_PAYLOAD);
1921          if (verbose) printf("Sent 'Payload Loop Up' BOP cmd\n");
1922	  }
1923        else
1924          printf("BOP msgs only work in T1-ESF format\n");
1925        break;
1926        }
1927      case 't': /* stop sending test pattern */
1928        {
1929        ioctl_snmp_send(TSEND_NORMAL);
1930        if (verbose) printf("Stop sending test pattern\n");
1931        break;
1932        }
1933      case 'T': /* start sending test pattern */
1934        {
1935        u_int8_t patt = strtoul(optarg, NULL, 0);
1936        write_framer(Bt8370_TPATT, 0x10 + patt);
1937        write_framer(Bt8370_RPATT, 0x30 + patt);
1938        if (verbose) print_test_pattern(patt);
1939        break;
1940        }
1941      case 'u': /* set transmit pulse shape */
1942        {
1943        config.tx_pulse = strtoul(optarg, NULL, 0);
1944        if (verbose) print_tx_pulse();
1945        update = 1;
1946        break;
1947        }
1948      case 'U': /* set tx line build-out */
1949        {
1950        if (config.tx_pulse == CFG_PULSE_T1CSU)
1951          {
1952          config.tx_lbo = strtoul(optarg, NULL, 0);
1953          if (verbose) print_tx_pulse();
1954          update = 1;
1955	  }
1956        else
1957          printf("LBO only meaningful if Tx Pulse is T1CSU\n");
1958        break;
1959        }
1960      case 'v': /* set verbose mode */
1961        {
1962        verbose = 1;
1963        break;
1964        }
1965      case 'x': /* disable transmitter outputs */
1966        {
1967        write_mii(16, read_mii(16) & ~MII16_T1_XOE);
1968        if (verbose) printf("Transmitter outputs disabled\n");
1969        break;
1970	}
1971      case 'X': /* enable transmitter outputs */
1972        {
1973        write_mii(16, read_mii(16) |  MII16_T1_XOE);
1974        if (verbose) printf("Transmitter outputs enabled\n");
1975        break;
1976        }
1977      default:
1978        {
1979        printf("Unknown command char: %c\n", ch);
1980        exit(1);
1981        } /* case */
1982      } /* switch */
1983    } /* while */
1984} /* proc */
1985
1986/* used when reading Motorola S-Record format ROM files */
1987static unsigned char
1988read_hex(FILE *f)
1989{
1990  unsigned char a, b, c;
1991  for (a=0, b=0; a<2; a++)
1992    {
1993    c = fgetc(f);
1994    c -= 48;
1995    if (c > 9) c -= 7;
1996    b = (b<<4) | (c & 0xF);
1997    }
1998  checksum += b;
1999  return b;
2000}
2001
2002static void
2003load_xilinx(char *name)
2004{
2005  FILE *f;
2006  char *ucode;
2007  int i, length;
2008  int c;
2009
2010  if (verbose) printf("Load firmware from file %s...\n", name);
2011  if ((f = fopen(name, "r")) == NULL)
2012    {
2013    perror("Failed to open file");
2014    exit(1);
2015    }
2016
2017  ucode = (char *)malloc(8192); bzero(ucode, 8192);
2018
2019  c = fgetc(f);
2020  if (c == 'X')
2021    { /* Xilinx raw bits file (foo.rbt) */
2022    /* skip seven lines of boiler plate */
2023    for (i=0; i<7;) if ((c=fgetc(f))=='\n') i++;
2024    /* build a dense bit array */
2025    i = length = 0;
2026    while ((c=fgetc(f))!=EOF)
2027      {  /* LSB first */
2028      if (c=='1') ucode[length] |= 1<<i++;
2029      if (c=='0') i++;
2030      if (i==8) { i=0; length++; }
2031      }
2032    }
2033  else if (c == 'S')
2034    { /* Motarola S records (foo.exo) */
2035    int blklen;
2036    length = 0;
2037    ungetc(c, f);
2038    while ((c = fgetc(f)) != EOF)
2039      {
2040      if (c != 'S')
2041        {
2042        printf("I'm confused; I expected an 'S'\n");
2043        exit(1);
2044        }
2045      c = fgetc(f);
2046      if (c == '9') break;
2047      else if (c == '1')
2048        {
2049        checksum = 0;
2050        blklen = read_hex(f) -3;
2051        read_hex(f); /* hi blkaddr */
2052        read_hex(f); /* lo blkaddr */
2053        for (i=0; i<blklen; i++)
2054          ucode[length++] = read_hex(f);
2055        read_hex(f); /* process but ignore checksum */
2056        if (checksum != 0xFF)
2057          {
2058          printf("File checksum error\n");
2059          exit(1);
2060          }
2061        c = fgetc(f); /* throw away eol */
2062        c = fgetc(f); /* throw away eol */
2063        }
2064      else
2065        {
2066        printf("I'm confused; I expected a '1' or a '9'\n");
2067        exit(1);
2068        }
2069      } /* while */
2070    } /* Motorola S-Record */
2071  else
2072    {
2073    printf("Unknown file type giving up\n");
2074    exit(1);
2075    }
2076
2077  load_xilinx_from_file(ucode, length);
2078}
2079
2080/* 32-bit CRC calculated right-to-left over 8-bit bytes */
2081static u_int32_t
2082crc32(char *bufp, int len)
2083{
2084  int bit, i;
2085  u_int32_t data;
2086  u_int32_t crc  = 0xFFFFFFFFL;
2087  u_int32_t poly = 0xEDB88320L;
2088
2089  for (i = 0; i < len; i++)
2090    for (data = *bufp++, bit = 0; bit < 8; bit++, data >>= 1)
2091      crc = (crc >> 1) ^ (((crc ^ data) & 1) ? poly : 0);
2092
2093  return crc;
2094}
2095
2096/* 8-bit CRC calculated left-to-right over 16-bit words */
2097static u_int8_t
2098crc8(u_int16_t *bufp, int len)
2099{
2100  int bit, i;
2101  u_int16_t data;
2102  u_int8_t crc  = 0xFF;
2103  u_int8_t poly = 0x07;
2104
2105  for (i = 0; i < len; i++)
2106    for (data = *bufp++, bit = 15; bit >= 0; bit--)
2107      {
2108      if ((i==8) && (bit==7)) break;
2109      crc = (crc << 1) ^ ((((crc >> 7) ^ (data >> bit)) & 1) ? poly : 0);
2110      }
2111  return crc;
2112}
2113
2114/* HSSI=3, DS3=4, SSI=5, T1E1=6, HSSIc=7, SDSL=8 */
2115void
2116init_srom(int board)
2117{
2118  int i;
2119  u_int16_t srom[64];
2120
2121  /* zero the entire rom */
2122  for (i=0; i<64; i++) srom[i] = 0;
2123
2124  srom[0]  = 0x1376; /* subsys vendor id */
2125  srom[1]  = board ? board : (read_mii(3)>>4 & 0xF) +1;
2126  srom[8]  = crc8(srom, 9);
2127  /* Tulip hardware checks this checksum */
2128  srom[10] = 0x6000; /* ethernet address */
2129  srom[11] = 0x0099; /* ethernet address */
2130  srom[12] = 0x0000; /* ethernet address */
2131  /* srom checksum is low 16 bits of Ethernet CRC-32 */
2132  srom[63] = crc32((char *)srom, 126) ^ 0xFFFFFFFFL;
2133
2134  /* write the SROM */
2135#if 1 /* really write it */
2136  for (i=0; i<64; i++) write_srom(i, srom[i]);
2137#else /* print what would be written */
2138  printf("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
2139  for (i=0; i<64; i++)
2140    {
2141    if (i%8 == 0) printf("\n%02X: ", i<<1);
2142    printf("%02X %02X ", srom[i] & 0xFF, srom[i]>>8);
2143    }
2144  printf("\n\n");
2145#endif
2146}
2147
2148int
2149main(int argc, char **argv)
2150{
2151  int i, error, ch;
2152  char *optstring = "13a:bBcCdDeEf:Fhi:L:mM:pP:sS:tT:uUvVwW:xXyYzZ?";
2153
2154  progname = (char *)argv[0];
2155
2156  /* Here is the overall plan:
2157   *  1) Read the interface name from the command line.
2158   *  2) Open the device; decide if netgraph is being used.
2159   *  3) Read the current interface configuration from the driver.
2160   *  4) Read the command line args and carry out their actions.
2161   *  5) Write the modified interface configuration to the driver.
2162   */
2163
2164  /* 1) Read the interface name from the command line. */
2165#if __linux__
2166  ifname = (argc==1) ? "hdlc0" : (char *) argv[1];
2167#else
2168  ifname = (argc==1) ? DEVICE_NAME"0" : (char *) argv[1];
2169#endif
2170
2171  /* 2) Open the device; decide if netgraph is being used, */
2172  /* use netgraph if ifname ends with ":" */
2173  for (i=0; i<16; i++) if (ifname[i] == 0) break;
2174
2175  /* Get a socket type file descriptor. */
2176#if defined(NETGRAPH)
2177  if ((netgraph = (ifname[i-1] == ':')))
2178    error = NgMkSockNode(NULL, &fdcs, NULL);
2179  else
2180#endif
2181    error = fdcs = socket(AF_INET, SOCK_DGRAM, 0);
2182  if (error < 0)
2183    {
2184    fprintf(stderr, "%s: %s() failed: %s\n", progname,
2185     netgraph? "NgMkSockNode" : "socket", strerror(errno));
2186    exit(1);
2187    }
2188
2189  /* 3) Read the current interface configuration from the driver. */
2190  ioctl_read_config();
2191  ioctl_read_status();
2192
2193  summary = (argc <= 2);  /* print summary at end */
2194  update  = 0;	/* write to card at end */
2195
2196  /* 4) Read the command line args and carry out their actions. */
2197  optind = 2;
2198  while (((ch = getopt(argc, argv, optstring)) != -1) && (argc > 2))
2199    {
2200    switch (ch)
2201      {
2202      case '1': /* T1 commands */
2203        {
2204        if (verbose) printf("Doing T1 settings\n");
2205        if (status.card_type != TLP_CSID_T1E1)
2206          {
2207          printf("T1 settings only apply to T1E1 cards\n");
2208          exit(1);
2209          }
2210        t1_cmd(argc, argv);
2211        break;
2212        }
2213      case '3': /* T3 commands */
2214        {
2215        if (verbose) printf("Doing T3 settings\n");
2216        if (status.card_type != TLP_CSID_T3)
2217          {
2218          printf("T3 settings only apply to T3 cards\n");
2219          exit(1);
2220          }
2221        t3_cmd(argc, argv);
2222        break;
2223        }
2224      case 'a': /* clock source */
2225        {
2226        if ((status.card_type != TLP_CSID_T1E1) ||
2227            (status.card_type != TLP_CSID_HSSI) ||
2228            (status.card_type != TLP_CSID_HSSIc))
2229          {
2230          if (verbose) print_tx_clk_src();
2231          config.tx_clk_src = strtoul(optarg, NULL, 0);
2232          update = 1;
2233	  }
2234        else
2235          printf("txclksrc only applies to T1E1 and HSSI card types\n");
2236        break;
2237        }
2238      case 'b': /* read bios rom */
2239        {
2240        int i;
2241        printf("Bios ROM:\n");
2242        printf("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
2243        for (i=0; i<256; i++)
2244          {
2245          if (i%16 == 0) printf("\n%02X: ", i);
2246          printf("%02X ", read_bios_rom(i));
2247	  }
2248        printf("\n\n");
2249        break;
2250	}
2251      case 'B': /* write bios rom */
2252        {
2253        int i;
2254        for (i=0; i<256; i++) write_bios_rom(i, 255-i);
2255        if (verbose) printf("wrote (0..255) to bios rom addrs (0..255)\n");
2256        break;
2257	}
2258      case 'c': /* set crc_len = 16 */
2259        {
2260        config.crc_len = CFG_CRC_16;
2261        if (verbose) print_crc_len();
2262        update = 1;
2263        break;
2264        }
2265      case 'C': /* set crc_len = 32 */
2266        {
2267        config.crc_len = CFG_CRC_32;
2268        if (verbose) print_crc_len();
2269        update = 1;
2270        break;
2271        }
2272      case 'd': /* clear DEBUG flag */
2273        {
2274        config.debug = 0;
2275        if (verbose) printf("DEBUG flag cleared\n");
2276        update = 1;
2277        break;
2278	}
2279      case 'D': /* set DEBUG flag */
2280        {
2281        config.debug = 1;
2282        if (verbose) printf("DEBUG flag set\n");
2283        update = 1;
2284        break;
2285	}
2286      case 'e': /* set DTE (default) */
2287        {
2288        if ((status.card_type == TLP_CSID_SSI) ||
2289            (status.card_type == TLP_CSID_HSSIc))
2290          {
2291          config.dte_dce = CFG_DTE;
2292          if (verbose) print_dte_dce();
2293          update = 1;
2294	  }
2295        else
2296          printf("DTE cmd only applies to SSI & HSSIc cards\n");
2297        break;
2298	}
2299      case 'E': /* set DCE */
2300        {
2301        if ((status.card_type == TLP_CSID_SSI) ||
2302            (status.card_type == TLP_CSID_HSSIc))
2303          {
2304          config.dte_dce = CFG_DCE;
2305          if (verbose) print_dte_dce();
2306          update = 1;
2307	  }
2308        else
2309          printf("DCE cmd only applies to SSI & HSSIc cards\n");
2310        break;
2311	}
2312      case 'f': /* set synth osc freq */
2313        {
2314        if ((status.card_type == TLP_CSID_SSI) ||
2315            (status.card_type == TLP_CSID_HSSIc))
2316          {
2317          synth_freq(strtoul(optarg, NULL, 0));
2318          write_synth(config.synth);
2319          if (verbose) print_synth_freq();
2320	  }
2321        else
2322          printf("synth osc freq only applies to SSI & HSSIc cards\n");
2323        break;
2324        }
2325      case 'F': /* set SPPP line protocol to Frame-Relay */
2326        {
2327        config.line_prot = PROT_FRM_RLY;
2328        config.keep_alive = 1; /* required for LMI operation */
2329        if (verbose) printf("SPPP line protocol set to Frame-Relay\n");
2330        update = 1;
2331        break;
2332	}
2333      case 'h': /* help */
2334      case '?':
2335        {
2336        usage();
2337        exit(0);
2338        }
2339      case 'i': /* interface name */
2340        {
2341        /* already scanned this */
2342        break;
2343        }
2344      case 'L': /* set loopback modes */
2345        {
2346        config.loop_back = strtoul(optarg, NULL, 0);
2347        if (verbose) print_loop_back();
2348        update = 1;
2349        break;
2350	}
2351      case 'm': /* read and print MII regs */
2352        {
2353        printf("MII regs:\n");
2354        printf("      0    1    2    3    4    5    6    7");
2355        for (i=0; i<32; i++)
2356          {
2357          u_int16_t mii = read_mii(i);
2358          if (i%8 == 0) printf("\n%02X: ", i);
2359          printf("%04X ", mii);
2360	  }
2361        printf("\n\n");
2362        break;
2363        }
2364      case 'M': /* write MII reg */
2365        {
2366        u_int32_t addr = strtoul(optarg, NULL, 0);
2367        u_int32_t data = strtoul(argv[optind++], NULL, 0);
2368        write_mii(addr, data);
2369        if (verbose)
2370          {
2371          data = read_mii(addr);
2372          printf("Write mii register: addr = 0x%02X data = 0x%04X\n", addr, data);
2373	  }
2374        break;
2375        }
2376      case 'p': /* read and print PCI config regs */
2377        {
2378        int i;
2379        printf("21140A PCI Config regs:\n");
2380        printf("       0        1        2        3");
2381        for (i=0; i<16; i++)
2382          {
2383          if (i%4 == 0) printf("\n%X: ", i);
2384          printf("%08X ", read_pci_config(i<<2));
2385	  }
2386        printf("\n\n");
2387        break;
2388	}
2389      case 'P': /* write PCI config reg */
2390        {
2391        u_int32_t addr = strtoul(optarg, NULL, 0);
2392        u_int32_t data = strtoul(argv[optind++], NULL, 0);
2393        write_pci_config(addr, data);
2394        if (verbose)
2395          {
2396          data = read_pci_config(addr);
2397          printf("Write PCI config reg: addr = 0x%02X data = 0x%08X\n", addr, data);
2398	  }
2399        break;
2400	}
2401      case 's': /* read and print Tulip SROM */
2402        {
2403        int i;
2404        printf("21140A SROM:\n");
2405        printf("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
2406        for (i=0; i<64; i++)
2407          {
2408          u_int16_t srom = read_srom(i);
2409          if (i%8 == 0) printf("\n%02X: ", i<<1);
2410          printf("%02X %02X ", srom & 0xFF, srom>>8);
2411	  }
2412        printf("\n\n");
2413        break;
2414	}
2415      case 'S': /* write Tulip SROM loc */
2416        {
2417#if 0  /* write a single location -- not too useful */
2418        u_int32_t addr = strtoul(optarg, NULL, 0);
2419        u_int32_t data = strtoul(argv[optind++], NULL, 0);
2420        write_mii(addr, data);
2421        data = read_mii(addr);
2422        printf("Write SROM: addr = 0x%02X data = 0x%04X\n", addr, data);
2423#endif
2424#if 0  /* write the whole SROM -- very dangerous */
2425        init_srom(strtoul(optarg, NULL, 0));
2426#endif
2427        printf("Caution! Recompile %s to enable this.\n", progname);
2428        break;
2429	}
2430      case 't': /* read and print Tulip CSRs */
2431        {
2432        int i;
2433        printf("21140A CSRs:\n");
2434        printf("       0        1        2        3");
2435        for (i=0; i<16; i++)
2436          {
2437          if (i%4 == 0) printf("\n%X: ", i);
2438          printf("%08X ", read_csr(i));
2439	  }
2440        printf("\n\n");
2441        break;
2442	}
2443      case 'T': /* write Tulip CSR */
2444        {
2445        u_int32_t addr = strtoul(optarg, NULL, 0);
2446        u_int32_t data = strtoul(argv[optind++], NULL, 0);
2447        write_csr(addr, data);
2448        if (verbose)
2449          {
2450          data = read_csr(addr);
2451          printf("Write 21140A CSR: addr = 0x%02X data = 0x%08X\n", addr, data);
2452	  }
2453        break;
2454	}
2455      case 'u': /* reset event counters */
2456        {
2457        ioctl_reset_cntrs();
2458        if (verbose) printf("Event counters reset\n");
2459        break;
2460	}
2461      case 'U': /* reset gate array */
2462        {
2463        reset_xilinx();
2464        if (verbose) printf("gate array reset\n");
2465        break;
2466        }
2467      case 'v': /* set verbose mode */
2468        {
2469        verbose = 1;
2470        break;
2471        }
2472      case 'V': /* print card configuration */
2473        {
2474        summary = 1;
2475        break;
2476	}
2477      case 'w': /* load gate array microcode from ROM */
2478        {
2479        load_xilinx_from_rom();
2480        if (verbose) printf("gate array configured from on-board ROM\n");
2481        break;
2482        }
2483      case 'W': /* load gate array microcode from file */
2484        {
2485        load_xilinx(optarg);
2486        if (verbose) printf("gate array configured from file %s\n", optarg);
2487        break;
2488        }
2489      case 'x': /* select RAWIP protocol */
2490        {
2491        config.line_pkg = PKG_RAWIP;
2492        if (verbose) printf("RAWIP mode selected\n");
2493        update = 1;
2494        break;
2495	}
2496      case 'X': /* Select in-kernel line protocol packages */
2497        {
2498        config.line_pkg = 0;
2499        if (verbose) printf("line protocol mode selected\n");
2500        update = 1;
2501        break;
2502	}
2503      case 'y': /* disable SPPP keep-alive packets */
2504        {
2505        if ((config.line_pkg  == PKG_SPPP) &&
2506            (config.line_prot == PROT_FRM_RLY))
2507          printf("keep-alives must be ON for Frame-Relay/SPPP\n");
2508        else
2509          {
2510          config.keep_alive = 0;
2511          if (verbose) printf("SPPP keep-alive packets disabled\n");
2512          update = 1;
2513	  }
2514        break;
2515	}
2516      case 'Y': /* enable SPPP keep-alive packets */
2517        {
2518        config.keep_alive = 1;
2519        if (verbose) printf("SPPP keep-alive packets enabled\n");
2520        update = 1;
2521        break;
2522	}
2523      case 'z': /* set SPPP line protocol to Cisco HDLC */
2524        {
2525        config.line_prot = PROT_C_HDLC;
2526        config.keep_alive = 1;
2527        if (verbose) printf("SPPP line protocol set to Cisco-HDLC\n");
2528        update = 1;
2529        break;
2530	}
2531      case 'Z': /* set SPPP line protocol to PPP */
2532        {
2533        config.line_prot = PROT_PPP;
2534        config.keep_alive = 0;
2535        if (verbose) printf("SPPP line protocol set to PPP\n");
2536        update = 1;
2537        break;
2538	}
2539      default:
2540        {
2541        printf("Unknown command char: %c\n", ch);
2542        exit(1);
2543	}
2544      } /* switch */
2545    } /* while */
2546
2547  if (summary) print_summary();
2548
2549  /*  5) Write the modified interface configuration to the driver. */
2550  if (update) ioctl_write_config();
2551
2552  exit(0);
2553}
2554