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$
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  strncpy(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  char *time;
1078  struct timeval tv;
1079  struct timezone tz;
1080
1081  gettimeofday(&tv, &tz);
1082  time = (char *)ctime((time_t *)&tv);
1083  printf("Current time:\t\t%s", time);
1084  if (status.cntrs.reset_time.tv_sec < 1000)
1085    time = "Never\n";
1086  else
1087    time = (char *)ctime((time_t *)&status.cntrs.reset_time.tv_sec);
1088  printf("Cntrs reset:\t\t%s", time);
1089
1090  if (status.cntrs.ibytes)     printf("Rx bytes:\t\t%ju\n",    (uintmax_t)status.cntrs.ibytes);
1091  if (status.cntrs.obytes)     printf("Tx bytes:\t\t%ju\n",    (uintmax_t)status.cntrs.obytes);
1092  if (status.cntrs.ipackets)   printf("Rx packets:\t\t%ju\n",  (uintmax_t)status.cntrs.ipackets);
1093  if (status.cntrs.opackets)   printf("Tx packets:\t\t%ju\n",  (uintmax_t)status.cntrs.opackets);
1094  if (status.cntrs.ierrors)    printf("Rx errors:\t\t%u\n",    status.cntrs.ierrors);
1095  if (status.cntrs.oerrors)    printf("Tx errors:\t\t%u\n",    status.cntrs.oerrors);
1096  if (status.cntrs.idiscards)  printf("Rx discards:\t\t%u\n",  status.cntrs.idiscards);
1097  if (status.cntrs.odiscards)  printf("Tx discards:\t\t%u\n",  status.cntrs.odiscards);
1098  if (status.cntrs.fifo_over)  printf("Rx fifo overruns:\t%u\n", status.cntrs.fifo_over);
1099  if (status.cntrs.fifo_under) printf("Tx fifo underruns:\t%u\n", status.cntrs.fifo_under);
1100  if (status.cntrs.missed)     printf("Rx missed:\t\t%u\n",    status.cntrs.missed);
1101  if (status.cntrs.overruns)   printf("Rx overruns:\t\t%u\n",  status.cntrs.overruns);
1102  if (status.cntrs.fdl_pkts)   printf("Rx FDL pkts:\t\t%u\n",  status.cntrs.fdl_pkts);
1103  if (status.cntrs.crc_errs)   printf("Rx CRC:\t\t\t%u\n",     status.cntrs.crc_errs);
1104  if (status.cntrs.lcv_errs)   printf("Rx line code:\t\t%u\n", status.cntrs.lcv_errs);
1105  if (status.cntrs.frm_errs)   printf("Rx F-bits:\t\t%u\n",    status.cntrs.frm_errs);
1106  if (status.cntrs.febe_errs)  printf("Rx FEBE:\t\t%u\n",      status.cntrs.febe_errs);
1107  if (status.cntrs.par_errs)   printf("Rx P-parity:\t\t%u\n",  status.cntrs.par_errs);
1108  if (status.cntrs.cpar_errs)  printf("Rx C-parity:\t\t%u\n",  status.cntrs.cpar_errs);
1109  if (status.cntrs.mfrm_errs)  printf("Rx M-bits:\t\t%u\n",    status.cntrs.mfrm_errs);
1110  if (config.debug)
1111    { /* These events are hard to explain and may worry users, */
1112    if (status.cntrs.rxdma)     printf("Rx no buffs:\t\t%u\n", status.cntrs.rxdma);
1113    if (status.cntrs.txdma)     printf("Tx no descs:\t\t%u\n", status.cntrs.txdma);
1114    if (status.cntrs.lck_watch) printf("Lck watch:\t\t%u\n",   status.cntrs.lck_watch);
1115    if (status.cntrs.lck_ioctl) printf("Lck ioctl:\t\t%u\n",   status.cntrs.lck_ioctl);
1116    if (status.cntrs.lck_intr)  printf("Lck intr:\t\t%u\n",    status.cntrs.lck_intr);
1117    }
1118}
1119
1120static void
1121print_summary(void)
1122{
1123  switch(status.card_type)
1124    {
1125    case TLP_CSID_HSSI:
1126      {
1127      print_card_name();
1128      print_card_type();
1129      print_debug();
1130      print_status();
1131      print_tx_speed();
1132      print_line_prot();
1133      print_crc_len();
1134      print_loop_back();
1135      print_tx_clk_src();
1136      print_hssi_sigs();
1137      print_events();
1138      break;
1139      }
1140    case TLP_CSID_T3:
1141      {
1142      print_card_name();
1143      print_card_type();
1144      print_debug();
1145      print_status();
1146      print_tx_speed();
1147      print_line_prot();
1148      print_crc_len();
1149      print_loop_back();
1150      print_format();
1151      print_cable_len();
1152      print_scrambler();
1153      print_events();
1154      break;
1155      }
1156    case TLP_CSID_SSI:
1157      {
1158      print_card_name();
1159      print_card_type();
1160      print_debug();
1161      print_status();
1162      print_tx_speed();
1163      print_line_prot();
1164      print_crc_len();
1165      print_loop_back();
1166      print_dte_dce();
1167      print_synth_freq();
1168      print_cable_type();
1169      print_ssi_sigs();
1170      print_events();
1171      break;
1172      }
1173    case TLP_CSID_T1E1:
1174      {
1175      print_card_name();
1176      print_card_type();
1177      print_debug();
1178      print_status();
1179      print_tx_speed();
1180      print_line_prot();
1181      print_crc_len();
1182      print_loop_back();
1183      print_tx_clk_src();
1184      print_format();
1185      print_time_slots();
1186      print_cable_len();
1187      print_tx_pulse();
1188      print_rx_gain();
1189      print_events();
1190      break;
1191      }
1192    case TLP_CSID_HSSIc:
1193      {
1194      print_card_name();
1195      print_card_type();
1196      print_debug();
1197      print_status();
1198      print_line_prot();
1199      print_tx_speed();
1200      print_crc_len();
1201      print_loop_back();
1202      print_tx_clk_src();
1203      print_dte_dce();
1204      print_synth_freq();
1205      print_hssi_sigs();
1206      print_events();
1207      break;
1208      }
1209    default:
1210      {
1211      printf("%s: Unknown card type: %d\n", ifname, status.card_type);
1212      break;
1213      }
1214    }
1215}
1216
1217static char *
1218print_t3_bop(int bop_code)
1219{
1220  switch(bop_code)
1221    {
1222    case 0x00:
1223      return "far end LOF";
1224    case 0x0E:
1225      return "far end LOS";
1226    case 0x16:
1227      return "far end AIS";
1228    case 0x1A:
1229      return "far end IDL";
1230    case 0x07:
1231      return "Line Loopback activate";
1232    case 0x1C:
1233      return "Line Loopback deactivate";
1234    case 0x1B:
1235      return "Entire DS3 line";
1236    default:
1237      return "Unknown BOP code";
1238    }
1239}
1240
1241static void
1242print_t3_snmp(void)
1243{
1244  printf("SNMP performance data:\n");
1245  printf(" LCV=%d",  status.snmp.t3.lcv);
1246  printf(" LOS=%d", (status.snmp.t3.line & TLINE_LOS)    ? 1 : 0);
1247  printf(" PCV=%d",  status.snmp.t3.pcv);
1248  printf(" CCV=%d",  status.snmp.t3.ccv);
1249  printf(" AIS=%d", (status.snmp.t3.line & TLINE_RX_AIS) ? 1 : 0);
1250  printf(" SEF=%d", (status.snmp.t3.line & T1LINE_SEF)   ? 1 : 0);
1251  printf(" OOF=%d", (status.snmp.t3.line & TLINE_LOF)    ? 1 : 0);
1252  printf("  FEBE=%d", status.snmp.t3.febe);
1253  printf(" RAI=%d", (status.snmp.t3.line & TLINE_RX_RAI) ? 1 : 0);
1254  printf("\n");
1255}
1256
1257static void
1258print_t3_dsu(void)
1259{
1260  char *no = "No", *yes = "Yes";
1261  u_int16_t mii16 = read_mii(16);
1262  u_int8_t ctl1   = read_framer(T3CSR_CTL1);
1263  u_int8_t ctl8   = read_framer(T3CSR_CTL8);
1264  u_int8_t stat9  = read_framer(T3CSR_STAT9);
1265  u_int8_t ctl12  = read_framer(T3CSR_CTL12);
1266  u_int8_t stat16 = read_framer(T3CSR_STAT16);
1267
1268  printf("Framing:       \t\t%s\n", ctl1   & CTL1_M13MODE    ? "M13" : "CPAR");
1269  print_tx_speed();
1270  printf("Scrambler:     \t\t%s\n", mii16  & MII16_DS3_SCRAM ? yes : no);
1271  printf("Scram poly:    \t\t%s\n", mii16  & MII16_DS3_POLY  ? "X^20" : "X^43");
1272  printf("Cable length   \t\t%s\n", mii16  & MII16_DS3_ZERO  ? "Short" : "Long");
1273  printf("Line    loop:  \t\t%s\n", mii16  & MII16_DS3_LNLBK ? yes : no);
1274  printf("Payload loop:  \t\t%s\n", ctl12  & CTL12_RTPLOOP   ? yes : no);
1275  printf("Frame   loop:  \t\t%s\n", ctl1   & CTL1_3LOOP      ? yes : no);
1276  printf("Host    loop:  \t\t%s\n", mii16  & MII16_DS3_TRLBK ? yes : no);
1277  printf("Transmit RAI:  \t\t%s\n", ctl1   & CTL1_XTX        ? no  : yes);
1278  printf("Receive  RAI   \t\t%s\n", stat16 & STAT16_XERR     ? yes : no);
1279  printf("Transmit AIS:  \t\t%s\n", ctl1   & CTL1_TXAIS      ? yes : no);
1280  printf("Receive  AIS:  \t\t%s\n", stat16 & STAT16_RAIS     ? yes : no);
1281  printf("Transmit IDLE: \t\t%s\n", ctl1   & CTL1_TXIDL      ? yes : no);
1282  printf("Receive  IDLE: \t\t%s\n", stat16 & STAT16_RIDL     ? yes : no);
1283  printf("Transmit BLUE: \t\t%s\n", ctl8   & CTL8_TBLU       ? yes : no);
1284  printf("Receive  BLUE: \t\t%s\n", stat9  & STAT9_RBLU      ? yes : no);
1285  printf("Loss of Signal:\t\t%s\n", stat16 & STAT16_RLOS     ? yes : no);
1286  printf("Loss of Frame: \t\t%s\n", stat16 & STAT16_ROOF     ? yes : no);
1287  printf("Sev Err Frms:  \t\t%s\n", stat16 & STAT16_SEF      ? yes : no);
1288  printf("Code  errors:  \t\t%d\n", read_framer(T3CSR_CVLO) + (read_framer(T3CSR_CVHI)<<8));
1289  printf("C-Par errors:  \t\t%d\n", read_framer(T3CSR_CERR));
1290  printf("P-Par errors:  \t\t%d\n", read_framer(T3CSR_PERR));
1291  printf("F-Bit errors:  \t\t%d\n", read_framer(T3CSR_FERR));
1292  printf("M-Bit errors:  \t\t%d\n", read_framer(T3CSR_MERR));
1293  printf("FarEndBitErrs: \t\t%d\n", read_framer(T3CSR_FEBE));
1294  printf("Last Tx  FEAC msg:\t0x%02X (%s)\n",
1295   read_framer(T3CSR_TX_FEAC)  & 0x3F,
1296   print_t3_bop(read_framer(T3CSR_TX_FEAC) & 0x3F));
1297  printf("Last dbl FEAC msg;\t0x%02X (%s)\n",
1298   read_framer(T3CSR_DBL_FEAC) & 0x3F,
1299   print_t3_bop(read_framer(T3CSR_DBL_FEAC) & 0x3F));
1300  printf("Last Rx  FEAC msg:\t0x%02X (%s)\n",
1301   read_framer(T3CSR_RX_FEAC)  & 0x3F,
1302   print_t3_bop(read_framer(T3CSR_RX_FEAC) & 0x3F));
1303  print_t3_snmp();
1304}
1305
1306static void
1307t3_cmd(int argc, char **argv)
1308{
1309  int ch;
1310
1311  while ((ch = getopt(argc, argv, "a:A:B:c:de:fF:lLsS:vV:")) != -1)
1312    {
1313    switch (ch)
1314      {
1315      case 'a': /* stop alarms */
1316        {
1317        switch (optarg[0])
1318          {
1319          case 'a': /* Stop sending AIS Signal */
1320            {
1321            write_mii(16,
1322             read_mii(16) & ~MII16_DS3_FRAME);
1323            write_framer(T3CSR_CTL1,
1324             read_framer(T3CSR_CTL1) & ~CTL1_TXAIS);
1325            if (verbose) printf("Stop sending Alarm Indication Signal (AIS)\n");
1326            break;
1327            }
1328          case 'b': /* Stop sending Blue signal */
1329            {
1330            write_mii(16,
1331             read_mii(16) & ~MII16_DS3_FRAME);
1332            write_framer(T3CSR_CTL8,
1333             read_framer(T3CSR_CTL8) & ~CTL8_TBLU);
1334            if (verbose) printf("Stop sending Blue signal\n");
1335            break;
1336            }
1337          case 'i': /* Stop sending IDLE signal */
1338            {
1339            write_framer(T3CSR_CTL1,
1340             read_framer(T3CSR_CTL1) & ~CTL1_TXIDL);
1341            if (verbose) printf("Stop sending IDLE signal\n");
1342            break;
1343            }
1344          case 'y': /* Stop sending Yellow alarm */
1345            {
1346            write_framer(T3CSR_CTL1,
1347             read_framer(T3CSR_CTL1) | CTL1_XTX);
1348            if (verbose) printf("Stop sending Yellow alarm\n");
1349            break;
1350            }
1351          default:
1352            printf("Unknown alarm: %c\n", optarg[0]);
1353            break;
1354          }
1355        break;
1356        }
1357      case 'A': /* start alarms */
1358        {
1359        switch (optarg[0])
1360          {
1361          case 'a': /* Start sending AIS Signal */
1362            {
1363            write_mii(16,
1364             read_mii(16) | MII16_DS3_FRAME);
1365            write_framer(T3CSR_CTL1,
1366             read_framer(T3CSR_CTL1) | CTL1_TXAIS);
1367            if (verbose) printf("Sending AIS signal (framed 1010..)\n");
1368            break;
1369            }
1370          case 'b': /* Start sending Blue signal */
1371            {
1372            write_mii(16,
1373             read_mii(16) | MII16_DS3_FRAME);
1374            write_framer(T3CSR_CTL8,
1375             read_framer(T3CSR_CTL8) | CTL8_TBLU);
1376            if (verbose) printf("Sending Blue signal (unframed all 1s)\n");
1377            break;
1378            }
1379          case 'i': /* Start sending IDLE signal */
1380            {
1381            write_framer(T3CSR_CTL1,
1382             read_framer(T3CSR_CTL1) | CTL1_TXIDL);
1383            if (verbose) printf("Sending IDLE signal (framed 1100..)\n");
1384            break;
1385            }
1386          case 'y': /* Start sending Yellow alarm */
1387            {
1388            write_framer(T3CSR_CTL1,
1389             read_framer(T3CSR_CTL1) & ~CTL1_XTX);
1390            if (verbose) printf("Sending Yellow alarm (X-bits=0)\n");
1391            break;
1392            }
1393          default:
1394            printf("Unknown alarm: %c\n", optarg[0]);
1395            break;
1396          }
1397        break;
1398        }
1399      case 'B': /* send BOP msg */
1400        {
1401        u_int8_t bop = strtoul(optarg, NULL, 0);
1402        write_framer(T3CSR_TX_FEAC,  0xC0 + bop);
1403        if (verbose) printf("Sent '0x%02X' BOP msg 10 times\n", bop);
1404        break;
1405	}
1406      case 'c': /* set cable length */
1407        {
1408        config.cable_len = strtoul(optarg, NULL, 0);
1409        if (verbose) print_cable_len();
1410        update = 1;
1411        break;
1412        }
1413      case 'd': /* DSU status */
1414      case 's': /* deprecated */
1415        {
1416        print_t3_dsu();
1417        break;
1418        }
1419      case 'e': /* set framimg format */
1420        {
1421        config.format = strtoul(optarg, NULL, 0);
1422        if (verbose) print_format();
1423        update = 1;
1424        break;
1425        }
1426      case 'f': /* read and print framer regs */
1427        {
1428        int i;
1429        printf("TXC03401 regs:\n");
1430        printf("     0  1  2  3  4  5  6  7");
1431        for (i=0; i<21; i++)
1432          {
1433          if (i%8 == 0) printf("\n%02X: ", i);
1434          printf("%02X ", read_framer(i));
1435          }
1436        printf("\n\n");
1437        break;
1438        }
1439      case 'F': /* write framer reg */
1440        {
1441        u_int32_t addr = strtoul(optarg, NULL, 0);
1442        u_int32_t data = strtoul(argv[optind++], NULL, 0);
1443        write_framer(addr, data);
1444        if (verbose)
1445          {
1446          data = read_framer(addr);
1447          printf("Write framer register: addr = 0x%02X data = 0x%02X\n", addr, data);
1448	  }
1449        break;
1450        }
1451      case 'l': /* send DS3 line loopback deactivate BOP cmd */
1452        {
1453        ioctl_snmp_send(TSEND_RESET);
1454        if (verbose) printf("Sent 'DS3 Line Loopback deactivate' BOP cmd\n");
1455        break;
1456        }
1457      case 'L': /* send DS3 line loopback activate BOP cmd */
1458        {
1459        ioctl_snmp_send(TSEND_LINE);
1460        if (verbose) printf("Sent 'DS3 Line Loopback activate' BOP cmd\n");
1461        break;
1462        }
1463      case 'S': /* set scrambler */
1464        {
1465        config.scrambler = strtoul(optarg, NULL, 0);
1466        if (verbose) print_scrambler();
1467        update = 1;
1468        break;
1469        }
1470      case 'v': /* set verbose mode */
1471        {
1472        verbose = 1;
1473        break;
1474        }
1475      case 'V': /* set T3 freq control DAC */
1476        {
1477        u_int32_t dac = strtoul(optarg, NULL, 0);
1478        write_dac(dac);
1479        if (verbose) printf("VCXO DAC value is %d\n", dac);
1480        break;
1481        }
1482      default:
1483        {
1484        printf("Unknown command char: %c\n", ch);
1485        exit(1);
1486        } /* case */
1487      } /* switch */
1488    } /* while */
1489} /* proc */
1490
1491static void
1492print_test_pattern(int patt)
1493{
1494  printf("Test Pattern:\t\t");
1495  switch (patt)
1496    {
1497    case 0:
1498      printf("unframed X^11+X^9+1\n");
1499      break;
1500    case 1:
1501      printf("unframed X^15+X^14+1\n");
1502      break;
1503    case 2:
1504      printf("unframed X^20+X^17+1\n");
1505      break;
1506    case 3:
1507      printf("unframed X^23+X^18+1\n");
1508      break;
1509    case 4:
1510      printf("unframed X^11+X^9+1 w/7ZS\n");
1511      break;
1512    case 5:
1513      printf("unframed X^15+X^14+1 w/7ZS\n");
1514      break;
1515    case 6:
1516      printf("unframed X^20+X^17+1 w/14ZS (QRSS)\n");
1517      break;
1518    case 7:
1519      printf("unframed X^23+X^18+1 w/14ZS\n");
1520      break;
1521    case 8:
1522      printf("framed X^11+X^9+1\n");
1523      break;
1524    case 9:
1525      printf("framed X^15+X^14+1\n");
1526      break;
1527    case 10:
1528      printf("framed X^20+X^17+1\n");
1529      break;
1530    case 11:
1531      printf("framed X^23+X^18+1\n");
1532      break;
1533    case 12:;
1534      printf("framed X^11+X^9+1 w/7ZS\n");
1535      break;
1536    case 13:
1537      printf("framed X^15+X^14+1 w/7ZS\n");
1538      break;
1539    case 14:
1540      printf("framed X^20+X^17+1 w/14ZS (QRSS)\n");
1541      break;
1542    case 15:
1543      printf("framed X^23+X^18+1 w/14ZS\n");
1544      break;
1545    }
1546}
1547
1548static char *
1549print_t1_bop(int bop_code)
1550{
1551  switch(bop_code)
1552    {
1553    case 0x00:
1554      return "Yellow Alarm (far end LOF)";
1555    case 0x07:
1556      return "Line Loop up";
1557    case 0x1C:
1558      return "Line Loop down";
1559    case 0x0A:
1560      return "Payload Loop up";
1561    case 0x19:
1562      return "Payload Loop down";
1563    case 0x09:
1564      return "Network Loop up";
1565    case 0x12:
1566      return "Network Loop down";
1567    default:
1568      return "Unknown BOP code";
1569    }
1570}
1571
1572static void
1573print_far_report(int index)
1574{
1575  u_int16_t far = status.snmp.t1.prm[index];
1576
1577  printf(" SEQ=%d ", (far & T1PRM_SEQ)>>8);
1578  if      (far & T1PRM_G1) printf("CRC=1");
1579  else if (far & T1PRM_G2) printf("CRC=1 to 5");
1580  else if (far & T1PRM_G3) printf("CRC=5 to 10");
1581  else if (far & T1PRM_G4) printf("CRC=10 to 100");
1582  else if (far & T1PRM_G5) printf("CRC=100 to 319");
1583  else if (far & T1PRM_G6) printf("CRC>=320");
1584  else                     printf("CRC=0");
1585  printf(" SE=%d", (far & T1PRM_SE) ? 1 : 0);
1586  printf(" FE=%d", (far & T1PRM_FE) ? 1 : 0);
1587  printf(" LV=%d", (far & T1PRM_LV) ? 1 : 0);
1588  printf(" SL=%d", (far & T1PRM_SL) ? 1 : 0);
1589  printf(" LB=%d", (far & T1PRM_LB) ? 1 : 0);
1590  printf("\n");
1591}
1592
1593static void
1594print_t1_snmp(void)
1595{
1596  printf("SNMP Near-end performance data:\n");
1597  printf(" LCV=%d",  status.snmp.t1.lcv);
1598  printf(" LOS=%d", (status.snmp.t1.line & TLINE_LOS)    ? 1 : 0);
1599  printf(" FE=%d",   status.snmp.t1.fe);
1600  printf(" CRC=%d",  status.snmp.t1.crc);
1601  printf(" AIS=%d", (status.snmp.t1.line & TLINE_RX_AIS) ? 1 : 0);
1602  printf(" SEF=%d", (status.snmp.t1.line & T1LINE_SEF)   ? 1 : 0);
1603  printf(" OOF=%d", (status.snmp.t1.line & TLINE_LOF)    ? 1 : 0);
1604  printf("  RAI=%d",(status.snmp.t1.line & TLINE_RX_RAI) ? 1 : 0);
1605  printf("\n");
1606  if (config.format == CFG_FORMAT_T1ESF)
1607    {
1608    printf("ANSI Far-end performance reports:\n");
1609    print_far_report(0);
1610    print_far_report(1);
1611    print_far_report(2);
1612    print_far_report(3);
1613    }
1614}
1615
1616static void
1617print_t1_dsu(void)
1618{
1619  char *no = "No", *yes = "Yes";
1620  u_int16_t mii16  = read_mii(16);
1621  u_int8_t isr0    = read_framer(Bt8370_ISR0);
1622  u_int8_t loop    = read_framer(Bt8370_LOOP);
1623  u_int8_t vga_max = read_framer(Bt8370_VGA_MAX) & 0x3F;
1624  u_int8_t alm1    = read_framer(Bt8370_ALM1);
1625  u_int8_t alm3    = read_framer(Bt8370_ALM3);
1626  u_int8_t talm    = read_framer(Bt8370_TALM);
1627  u_int8_t tpatt   = read_framer(Bt8370_TPATT);
1628  u_int8_t tpulse  = read_framer(Bt8370_TLIU_CR);
1629  u_int8_t vga;
1630  u_int8_t saved_pulse, saved_lbo;
1631
1632  /* d/c write required before read */
1633  write_framer(Bt8370_VGA, 0);
1634  vga = read_framer(Bt8370_VGA) & 0x3F;
1635
1636  print_format();
1637  print_time_slots();
1638  print_tx_clk_src();
1639  print_tx_speed();
1640
1641  saved_pulse     = config.tx_pulse;
1642  config.tx_pulse = tpulse & 0x0E;
1643  saved_lbo       = config.tx_lbo;
1644  config.tx_lbo   = tpulse & 0x30;
1645  print_tx_pulse();
1646  config.tx_pulse = saved_pulse;
1647  config.tx_lbo   = saved_lbo;
1648
1649  printf("Tx outputs:    \t\t%sabled\n", (mii16 & MII16_T1_XOE) ? "En" : "Dis");
1650  printf("Line impedance:\t\t%s ohms\n", (mii16 & MII16_T1_Z) ? "120" : "100");
1651  printf("Max line loss: \t\t%4.1f dB\n", vga_dbs(vga_max));
1652  printf("Cur line loss: \t\t%4.1f dB\n", vga_dbs(vga));
1653  printf("Invert data:   \t\t%s\n", (mii16 & MII16_T1_INVERT) ? yes : no);
1654  printf("Line    loop:  \t\t%s\n", (loop & LOOP_LINE)    ? yes : no);
1655  printf("Payload loop:  \t\t%s\n", (loop & LOOP_PAYLOAD) ? yes : no);
1656  printf("Framer  loop:  \t\t%s\n", (loop & LOOP_FRAMER)  ? yes : no);
1657  printf("Analog  loop:  \t\t%s\n", (loop & LOOP_ANALOG)  ? yes : no);
1658  printf("Tx AIS:        \t\t%s\n", ((talm & TALM_TAIS) ||
1659   ((talm & TALM_AUTO_AIS) && (alm1 & ALM1_RLOS))) ? yes : no);
1660  printf("Rx AIS:        \t\t%s\n", (alm1 & ALM1_RAIS)  ? yes : no);
1661  if (((config.format & 1)==0) && (config.format != CFG_FORMAT_E1NONE))
1662    {
1663    printf("Tx RAI:        \t\t%s\n", ((talm & TALM_TYEL) ||
1664     ((talm & TALM_AUTO_YEL) && (alm3 & ALM3_FRED))) ? yes : no);
1665    printf("Rx RAI:        \t\t%s\n", (alm1 & ALM1_RYEL)  ? yes : no);
1666    }
1667  if (config.format == CFG_FORMAT_T1ESF)
1668    {
1669    printf("Tx BOP RAI:    \t\t%s\n", (alm1 & ALM1_RLOF)  ? yes : no);
1670    printf("Rx BOP RAI:    \t\t%s\n", (alm1 & ALM1_RMYEL) ? yes : no);
1671    }
1672  if ((config.format & 0x11) == 0x10) /* E1CAS */
1673    {
1674    printf("Rx TS16 AIS:   \t\t%s\n", (alm3 & ALM3_RMAIS) ? yes : no);
1675    printf("Tx TS16 RAI;   \t\t%s\n",
1676     ((talm & TALM_AUTO_MYEL) && (alm3 & ALM3_SRED)) ? yes : no);
1677    }
1678  printf("Rx LOS analog: \t\t%s\n", (alm1 & ALM1_RALOS) ? yes : no);
1679  printf("Rx LOS digital:\t\t%s\n", (alm1 & ALM1_RLOS)  ? yes : no);
1680  printf("Rx LOF:        \t\t%s\n", (alm1 & ALM1_RLOF)  ? yes : no);
1681  printf("Tx QRS:        \t\t%s\n", (tpatt & 0x10)      ? yes : no);
1682  printf("Rx QRS:        \t\t%s\n", (isr0 & 0x10)       ? yes : no);
1683  printf("LCV errors:    \t\t%d\n",
1684   read_framer(Bt8370_LCV_LO)  + (read_framer(Bt8370_LCV_HI)<<8));
1685  if (config.format != CFG_FORMAT_E1NONE)
1686    {
1687    if ((config.format & 1)==0) printf("Far End Block Errors:\t%d\n",
1688     read_framer(Bt8370_FEBE_LO) + (read_framer(Bt8370_FEBE_HI)<<8));
1689    printf("CRC errors:    \t\t%d\n",
1690     read_framer(Bt8370_CRC_LO)  + (read_framer(Bt8370_CRC_HI)<<8));
1691    printf("Frame errors:  \t\t%d\n",
1692     read_framer(Bt8370_FERR_LO) + (read_framer(Bt8370_FERR_HI)<<8));
1693    printf("Sev Err Frms:  \t\t%d\n", read_framer(Bt8370_AERR) & 0x03);
1694    printf("Change of Frm align:\t%d\n",  (read_framer(Bt8370_AERR) & 0x0C)>>2);
1695    printf("Loss of Frame events:\t%d\n", (read_framer(Bt8370_AERR) & 0xF0)>>4);
1696    }
1697  if (config.format == CFG_FORMAT_T1ESF)
1698    {
1699    printf("Last Tx BOP msg:\t0x%02X (%s)\n",
1700     read_framer(Bt8370_TBOP), print_t1_bop(read_framer(Bt8370_TBOP)));
1701    printf("Last Rx BOP msg:\t0x%02X (%s)\n",
1702     read_framer(Bt8370_RBOP), print_t1_bop(read_framer(Bt8370_RBOP)&0x3F));
1703    }
1704  print_t1_snmp();
1705}
1706
1707static void
1708t1_cmd(int argc, char **argv)
1709{
1710  int ch;
1711
1712  while ((ch = getopt(argc, argv, "a:A:B:c:de:E:fF:g:iIlLpPstT:u:U:vxX")) != -1)
1713    {
1714    switch (ch)
1715      {
1716      case 'a': /* stop alarms */
1717        {
1718        switch (optarg[0])
1719          {
1720          case 'y': /* Stop sending Yellow Alarm */
1721            {
1722            if ((config.format == CFG_FORMAT_T1SF) ||
1723                (config.format == CFG_FORMAT_E1NONE))
1724              printf("No Yellow alarm for this frame format\n");
1725            else if (config.format == CFG_FORMAT_T1ESF)
1726              write_framer(Bt8370_BOP,  0xE0); /* rbop 25, tbop off */
1727            else
1728              {
1729              u_int8_t talm = read_framer(Bt8370_TALM);
1730              write_framer(Bt8370_TALM, talm & ~TALM_TYEL);
1731	      }
1732            if (verbose) printf("Stop sending Yellow alarm\n");
1733            break;
1734            }
1735          case 'a': /* Stop sending AIS */
1736          case 'b': /* Stop sending Blue Alarm */
1737            {
1738            u_int8_t talm = read_framer(Bt8370_TALM);
1739            write_framer(Bt8370_TALM, talm & ~TALM_TAIS);
1740            if (verbose) printf("Stop sending AIS/Blue signal\n");
1741            break;
1742            }
1743          default:
1744            printf("Unknown alarm: %c\n", optarg[0]);
1745          }
1746        break;
1747        }
1748      case 'A': /* start alarms */
1749        {
1750        switch (optarg[0])
1751          {
1752          case 'y': /* Start sending Yellow Alarm */
1753            {
1754            if ((config.format == CFG_FORMAT_T1SF) ||
1755                (config.format == CFG_FORMAT_E1NONE))
1756              printf("No Yellow alarm for this frame format\n");
1757            else if (config.format == CFG_FORMAT_T1ESF)
1758              {
1759              write_framer(Bt8370_BOP,  0x0F); /* rbop off, tbop cont */
1760              write_framer(Bt8370_TBOP, T1BOP_OOF);
1761	      }
1762            else
1763              {
1764              u_int8_t talm = read_framer(Bt8370_TALM);
1765              write_framer(Bt8370_TALM, talm | TALM_TYEL);
1766	      }
1767            if (verbose) printf("Sending Yellow alarm\n");
1768            break;
1769            }
1770          case 'a': /* Start sending AIS */
1771          case 'b': /* Start sending Blue Alarm */
1772            {
1773            u_int8_t talm = read_framer(Bt8370_TALM);
1774            write_framer(Bt8370_TALM, talm | TALM_TAIS);
1775            if (verbose) printf("Sending AIS/Blue signal\n");
1776            break;
1777            }
1778          default:
1779            printf("Unknown alarm: %c\n", optarg[0]);
1780          }
1781        break;
1782        }
1783      case 'B': /* send BOP msg */
1784        {
1785        u_int8_t bop = strtoul(optarg, NULL, 0);
1786        if (config.format == CFG_FORMAT_T1ESF)
1787          {
1788          write_framer(Bt8370_BOP, 0x0B); /* rbop off, tbop 25 */
1789          write_framer(Bt8370_TBOP, bop); /* start sending BOP msg */
1790          sleep(1);  /* sending 25 BOP msgs takes about 100 ms. */
1791          write_framer(Bt8370_BOP, 0xE0); /* rbop 25, tbop off */
1792          if (verbose) printf("Sent '0x%02X' BOP msg 25 times\n", bop);
1793	  }
1794        else
1795          printf("BOP msgs only work in T1-ESF format\n");
1796        break;
1797	}
1798      case 'c': /* set cable length */
1799        {
1800        config.cable_len = strtoul(optarg, NULL, 0);
1801        if (verbose) print_cable_len();
1802        update = 1;
1803        break;
1804        }
1805      case 'd': /* DSU status */
1806      case 's': /* deprecated */
1807        {
1808        print_t1_dsu();
1809        break;
1810        }
1811      case 'e': /* set framimg format */
1812        {
1813        config.format = strtoul(optarg, NULL, 0);
1814        if (verbose) print_format();
1815        update = 1;
1816        break;
1817        }
1818      case 'E': /* set time slots */
1819        {
1820        config.time_slots = strtoul(optarg, NULL, 16);
1821        if (verbose) print_time_slots();
1822        update = 1;
1823        break;
1824        }
1825      case 'f': /* read and print framer regs */
1826        {
1827        int i;
1828        printf("Bt8370 regs:\n");
1829        printf("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
1830        for (i=0; i<512; i++)
1831          {
1832          if (i%16 == 0) printf("\n%03X: ", i);
1833          printf("%02X ", read_framer(i));
1834	  }
1835        printf("\n\n");
1836        break;
1837	}
1838      case 'F': /* write framer reg */
1839        {
1840        u_int32_t addr = strtoul(optarg, NULL, 0);
1841        u_int32_t data = strtoul(argv[optind++], NULL, 0);
1842        write_framer(addr, data);
1843        if (verbose)
1844          {
1845          data = read_framer(addr);
1846          printf("Write framer register: addr = 0x%02X data = 0x%02X\n", addr, data);
1847	  }
1848        break;
1849	}
1850      case 'g': /* set receiver gain */
1851        {
1852        config.rx_gain = strtoul(optarg, NULL, 0);
1853        if (verbose) print_rx_gain();
1854        update = 1;
1855        break;
1856        }
1857      case 'i': /* send CSU loopback deactivate inband cmd */
1858        {
1859        if (config.format == CFG_FORMAT_T1SF)
1860          {
1861          if (verbose) printf("Sending 'CSU loop down' inband cmd for 10 secs...");
1862          ioctl_snmp_send(TSEND_RESET);
1863          sleep(10);
1864          ioctl_snmp_send(TSEND_NORMAL);
1865          if (verbose) printf("done\n");
1866	  }
1867        else
1868          printf("Inband loopback cmds only work in T1-SF format");
1869        break;
1870        }
1871      case 'I': /* send CSU loopback activate inband cmd */
1872        {
1873        if (config.format == CFG_FORMAT_T1SF)
1874          {
1875          if (verbose) printf("Sending 'CSU loop up' inband cmd for 10 secs...");
1876          ioctl_snmp_send(TSEND_LINE);
1877          sleep(10);
1878          ioctl_snmp_send(TSEND_NORMAL);
1879          if (verbose) printf("done\n");
1880	  }
1881        else
1882          printf("Inband loopback cmds only work in T1-SF format");
1883        break;
1884        }
1885      case 'l': /* send line loopback deactivate BOP msg */
1886        {
1887        if (config.format == CFG_FORMAT_T1ESF)
1888          {
1889          ioctl_snmp_send(TSEND_RESET);
1890          if (verbose) printf("Sent 'Line Loop Down' BOP cmd\n");
1891	  }
1892        else
1893          printf("BOP msgs only work in T1-ESF format\n");
1894        break;
1895        }
1896      case 'L': /* send line loopback activate BOP msg */
1897        {
1898        if (config.format == CFG_FORMAT_T1ESF)
1899          {
1900          ioctl_snmp_send(TSEND_LINE);
1901          if (verbose) printf("Sent 'Line Loop Up' BOP cmd\n");
1902	  }
1903        else
1904          printf("BOP msgs only work in T1-ESF format\n");
1905        break;
1906        }
1907      case 'p': /* send payload loopback deactivate BOP msg */
1908        {
1909        if (config.format == CFG_FORMAT_T1ESF)
1910          {
1911          ioctl_snmp_send(TSEND_RESET);
1912          if (verbose) printf("Sent 'Payload Loop Down' BOP cmd\n");
1913	  }
1914        else
1915          printf("BOP msgs only work in T1-ESF format\n");
1916        break;
1917        }
1918      case 'P': /* send payload loopback activate BOP msg */
1919        {
1920        if (config.format == CFG_FORMAT_T1ESF)
1921          {
1922          ioctl_snmp_send(TSEND_PAYLOAD);
1923          if (verbose) printf("Sent 'Payload Loop Up' BOP cmd\n");
1924	  }
1925        else
1926          printf("BOP msgs only work in T1-ESF format\n");
1927        break;
1928        }
1929      case 't': /* stop sending test pattern */
1930        {
1931        ioctl_snmp_send(TSEND_NORMAL);
1932        if (verbose) printf("Stop sending test pattern\n");
1933        break;
1934        }
1935      case 'T': /* start sending test pattern */
1936        {
1937        u_int8_t patt = strtoul(optarg, NULL, 0);
1938        write_framer(Bt8370_TPATT, 0x10 + patt);
1939        write_framer(Bt8370_RPATT, 0x30 + patt);
1940        if (verbose) print_test_pattern(patt);
1941        break;
1942        }
1943      case 'u': /* set transmit pulse shape */
1944        {
1945        config.tx_pulse = strtoul(optarg, NULL, 0);
1946        if (verbose) print_tx_pulse();
1947        update = 1;
1948        break;
1949        }
1950      case 'U': /* set tx line build-out */
1951        {
1952        if (config.tx_pulse == CFG_PULSE_T1CSU)
1953          {
1954          config.tx_lbo = strtoul(optarg, NULL, 0);
1955          if (verbose) print_tx_pulse();
1956          update = 1;
1957	  }
1958        else
1959          printf("LBO only meaningful if Tx Pulse is T1CSU\n");
1960        break;
1961        }
1962      case 'v': /* set verbose mode */
1963        {
1964        verbose = 1;
1965        break;
1966        }
1967      case 'x': /* disable transmitter outputs */
1968        {
1969        write_mii(16, read_mii(16) & ~MII16_T1_XOE);
1970        if (verbose) printf("Transmitter outputs disabled\n");
1971        break;
1972	}
1973      case 'X': /* enable transmitter outputs */
1974        {
1975        write_mii(16, read_mii(16) |  MII16_T1_XOE);
1976        if (verbose) printf("Transmitter outputs enabled\n");
1977        break;
1978        }
1979      default:
1980        {
1981        printf("Unknown command char: %c\n", ch);
1982        exit(1);
1983        } /* case */
1984      } /* switch */
1985    } /* while */
1986} /* proc */
1987
1988/* used when reading Motorola S-Record format ROM files */
1989static unsigned char
1990read_hex(FILE *f)
1991{
1992  unsigned char a, b, c;
1993  for (a=0, b=0; a<2; a++)
1994    {
1995    c = fgetc(f);
1996    c -= 48;
1997    if (c > 9) c -= 7;
1998    b = (b<<4) | (c & 0xF);
1999    }
2000  checksum += b;
2001  return b;
2002}
2003
2004static void
2005load_xilinx(char *name)
2006{
2007  FILE *f;
2008  char *ucode;
2009  int i, length;
2010  int c;
2011
2012  if (verbose) printf("Load firmware from file %s...\n", name);
2013  if ((f = fopen(name, "r")) == 0)
2014    {
2015    perror("Failed to open file");
2016    exit(1);
2017    }
2018
2019  ucode = (char *)malloc(8192); bzero(ucode, 8192);
2020
2021  c = fgetc(f);
2022  if (c == 'X')
2023    { /* Xilinx raw bits file (foo.rbt) */
2024    /* skip seven lines of boiler plate */
2025    for (i=0; i<7;) if ((c=fgetc(f))=='\n') i++;
2026    /* build a dense bit array */
2027    i = length = 0;
2028    while ((c=fgetc(f))!=EOF)
2029      {  /* LSB first */
2030      if (c=='1') ucode[length] |= 1<<i++;
2031      if (c=='0') i++;
2032      if (i==8) { i=0; length++; }
2033      }
2034    }
2035  else if (c == 'S')
2036    { /* Motarola S records (foo.exo) */
2037    int blklen;
2038    length = 0;
2039    ungetc(c, f);
2040    while ((c = fgetc(f)) != EOF)
2041      {
2042      if (c != 'S')
2043        {
2044        printf("I'm confused; I expected an 'S'\n");
2045        exit(1);
2046        }
2047      c = fgetc(f);
2048      if (c == '9') break;
2049      else if (c == '1')
2050        {
2051        checksum = 0;
2052        blklen = read_hex(f) -3;
2053        read_hex(f); /* hi blkaddr */
2054        read_hex(f); /* lo blkaddr */
2055        for (i=0; i<blklen; i++)
2056          ucode[length++] = read_hex(f);
2057        read_hex(f); /* process but ignore checksum */
2058        if (checksum != 0xFF)
2059          {
2060          printf("File checksum error\n");
2061          exit(1);
2062          }
2063        c = fgetc(f); /* throw away eol */
2064        c = fgetc(f); /* throw away eol */
2065        }
2066      else
2067        {
2068        printf("I'm confused; I expected a '1' or a '9'\n");
2069        exit(1);
2070        }
2071      } /* while */
2072    } /* Motorola S-Record */
2073  else
2074    {
2075    printf("Unknown file type giving up\n");
2076    exit(1);
2077    }
2078
2079  load_xilinx_from_file(ucode, length);
2080}
2081
2082/* 32-bit CRC calculated right-to-left over 8-bit bytes */
2083static u_int32_t
2084crc32(char *bufp, int len)
2085{
2086  int bit, i;
2087  u_int32_t data;
2088  u_int32_t crc  = 0xFFFFFFFFL;
2089  u_int32_t poly = 0xEDB88320L;
2090
2091  for (i = 0; i < len; i++)
2092    for (data = *bufp++, bit = 0; bit < 8; bit++, data >>= 1)
2093      crc = (crc >> 1) ^ (((crc ^ data) & 1) ? poly : 0);
2094
2095  return crc;
2096}
2097
2098/* 8-bit CRC calculated left-to-right over 16-bit words */
2099static u_int8_t
2100crc8(u_int16_t *bufp, int len)
2101{
2102  int bit, i;
2103  u_int16_t data;
2104  u_int8_t crc  = 0xFF;
2105  u_int8_t poly = 0x07;
2106
2107  for (i = 0; i < len; i++)
2108    for (data = *bufp++, bit = 15; bit >= 0; bit--)
2109      {
2110      if ((i==8) && (bit==7)) break;
2111      crc = (crc << 1) ^ ((((crc >> 7) ^ (data >> bit)) & 1) ? poly : 0);
2112      }
2113  return crc;
2114}
2115
2116/* HSSI=3, DS3=4, SSI=5, T1E1=6, HSSIc=7, SDSL=8 */
2117void
2118init_srom(int board)
2119{
2120  int i;
2121  u_int16_t srom[64];
2122
2123  /* zero the entire rom */
2124  for (i=0; i<64; i++) srom[i] = 0;
2125
2126  srom[0]  = 0x1376; /* subsys vendor id */
2127  srom[1]  = board ? board : (read_mii(3)>>4 & 0xF) +1;
2128  srom[8]  = crc8(srom, 9);
2129  /* Tulip hardware checks this checksum */
2130  srom[10] = 0x6000; /* ethernet address */
2131  srom[11] = 0x0099; /* ethernet address */
2132  srom[12] = 0x0000; /* ethernet address */
2133  /* srom checksum is low 16 bits of Ethernet CRC-32 */
2134  srom[63] = crc32((char *)srom, 126) ^ 0xFFFFFFFFL;
2135
2136  /* write the SROM */
2137#if 1 /* really write it */
2138  for (i=0; i<64; i++) write_srom(i, srom[i]);
2139#else /* print what would be written */
2140  printf("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
2141  for (i=0; i<64; i++)
2142    {
2143    if (i%8 == 0) printf("\n%02X: ", i<<1);
2144    printf("%02X %02X ", srom[i] & 0xFF, srom[i]>>8);
2145    }
2146  printf("\n\n");
2147#endif
2148}
2149
2150int
2151main(int argc, char **argv)
2152{
2153  int i, error, ch;
2154  char *optstring = "13a:bBcCdDeEf:Fhi:L:mM:pP:sS:tT:uUvVwW:xXyYzZ?";
2155
2156  progname = (char *)argv[0];
2157
2158  /* Here is the overall plan:
2159   *  1) Read the interface name from the command line.
2160   *  2) Open the device; decide if netgraph is being used.
2161   *  3) Read the current interface configuration from the driver.
2162   *  4) Read the command line args and carry out their actions.
2163   *  5) Write the modified interface configuration to the driver.
2164   */
2165
2166  /* 1) Read the interface name from the command line. */
2167#if __linux__
2168  ifname = (argc==1) ? "hdlc0" : (char *) argv[1];
2169#else
2170  ifname = (argc==1) ? DEVICE_NAME"0" : (char *) argv[1];
2171#endif
2172
2173  /* 2) Open the device; decide if netgraph is being used, */
2174  /* use netgraph if ifname ends with ":" */
2175  for (i=0; i<16; i++) if (ifname[i] == 0) break;
2176
2177  /* Get a socket type file descriptor. */
2178#if defined(NETGRAPH)
2179  if ((netgraph = (ifname[i-1] == ':')))
2180    error = NgMkSockNode(NULL, &fdcs, NULL);
2181  else
2182#endif
2183    error = fdcs = socket(AF_INET, SOCK_DGRAM, 0);
2184  if (error < 0)
2185    {
2186    fprintf(stderr, "%s: %s() failed: %s\n", progname,
2187     netgraph? "NgMkSockNode" : "socket", strerror(errno));
2188    exit(1);
2189    }
2190
2191  /* 3) Read the current interface configuration from the driver. */
2192  ioctl_read_config();
2193  ioctl_read_status();
2194
2195  summary = (argc <= 2);  /* print summary at end */
2196  update  = 0;	/* write to card at end */
2197
2198  /* 4) Read the command line args and carry out their actions. */
2199  optind = 2;
2200  while (((ch = getopt(argc, argv, optstring)) != -1) && (argc > 2))
2201    {
2202    switch (ch)
2203      {
2204      case '1': /* T1 commands */
2205        {
2206        if (verbose) printf("Doing T1 settings\n");
2207        if (status.card_type != TLP_CSID_T1E1)
2208          {
2209          printf("T1 settings only apply to T1E1 cards\n");
2210          exit(1);
2211          }
2212        t1_cmd(argc, argv);
2213        break;
2214        }
2215      case '3': /* T3 commands */
2216        {
2217        if (verbose) printf("Doing T3 settings\n");
2218        if (status.card_type != TLP_CSID_T3)
2219          {
2220          printf("T3 settings only apply to T3 cards\n");
2221          exit(1);
2222          }
2223        t3_cmd(argc, argv);
2224        break;
2225        }
2226      case 'a': /* clock source */
2227        {
2228        if ((status.card_type != TLP_CSID_T1E1) ||
2229            (status.card_type != TLP_CSID_HSSI) ||
2230            (status.card_type != TLP_CSID_HSSIc))
2231          {
2232          if (verbose) print_tx_clk_src();
2233          config.tx_clk_src = strtoul(optarg, NULL, 0);
2234          update = 1;
2235	  }
2236        else
2237          printf("txclksrc only applies to T1E1 and HSSI card types\n");
2238        break;
2239        }
2240      case 'b': /* read bios rom */
2241        {
2242        int i;
2243        printf("Bios ROM:\n");
2244        printf("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
2245        for (i=0; i<256; i++)
2246          {
2247          if (i%16 == 0) printf("\n%02X: ", i);
2248          printf("%02X ", read_bios_rom(i));
2249	  }
2250        printf("\n\n");
2251        break;
2252	}
2253      case 'B': /* write bios rom */
2254        {
2255        int i;
2256        for (i=0; i<256; i++) write_bios_rom(i, 255-i);
2257        if (verbose) printf("wrote (0..255) to bios rom addrs (0..255)\n");
2258        break;
2259	}
2260      case 'c': /* set crc_len = 16 */
2261        {
2262        config.crc_len = CFG_CRC_16;
2263        if (verbose) print_crc_len();
2264        update = 1;
2265        break;
2266        }
2267      case 'C': /* set crc_len = 32 */
2268        {
2269        config.crc_len = CFG_CRC_32;
2270        if (verbose) print_crc_len();
2271        update = 1;
2272        break;
2273        }
2274      case 'd': /* clear DEBUG flag */
2275        {
2276        config.debug = 0;
2277        if (verbose) printf("DEBUG flag cleared\n");
2278        update = 1;
2279        break;
2280	}
2281      case 'D': /* set DEBUG flag */
2282        {
2283        config.debug = 1;
2284        if (verbose) printf("DEBUG flag set\n");
2285        update = 1;
2286        break;
2287	}
2288      case 'e': /* set DTE (default) */
2289        {
2290        if ((status.card_type == TLP_CSID_SSI) ||
2291            (status.card_type == TLP_CSID_HSSIc))
2292          {
2293          config.dte_dce = CFG_DTE;
2294          if (verbose) print_dte_dce();
2295          update = 1;
2296	  }
2297        else
2298          printf("DTE cmd only applies to SSI & HSSIc cards\n");
2299        break;
2300	}
2301      case 'E': /* set DCE */
2302        {
2303        if ((status.card_type == TLP_CSID_SSI) ||
2304            (status.card_type == TLP_CSID_HSSIc))
2305          {
2306          config.dte_dce = CFG_DCE;
2307          if (verbose) print_dte_dce();
2308          update = 1;
2309	  }
2310        else
2311          printf("DCE cmd only applies to SSI & HSSIc cards\n");
2312        break;
2313	}
2314      case 'f': /* set synth osc freq */
2315        {
2316        if ((status.card_type == TLP_CSID_SSI) ||
2317            (status.card_type == TLP_CSID_HSSIc))
2318          {
2319          synth_freq(strtoul(optarg, NULL, 0));
2320          write_synth(config.synth);
2321          if (verbose) print_synth_freq();
2322	  }
2323        else
2324          printf("synth osc freq only applies to SSI & HSSIc cards\n");
2325        break;
2326        }
2327      case 'F': /* set SPPP line protocol to Frame-Relay */
2328        {
2329        config.line_prot = PROT_FRM_RLY;
2330        config.keep_alive = 1; /* required for LMI operation */
2331        if (verbose) printf("SPPP line protocol set to Frame-Relay\n");
2332        update = 1;
2333        break;
2334	}
2335      case 'h': /* help */
2336      case '?':
2337        {
2338        usage();
2339        exit(0);
2340        }
2341      case 'i': /* interface name */
2342        {
2343        /* already scanned this */
2344        break;
2345        }
2346      case 'L': /* set loopback modes */
2347        {
2348        config.loop_back = strtoul(optarg, NULL, 0);
2349        if (verbose) print_loop_back();
2350        update = 1;
2351        break;
2352	}
2353      case 'm': /* read and print MII regs */
2354        {
2355        printf("MII regs:\n");
2356        printf("      0    1    2    3    4    5    6    7");
2357        for (i=0; i<32; i++)
2358          {
2359          u_int16_t mii = read_mii(i);
2360          if (i%8 == 0) printf("\n%02X: ", i);
2361          printf("%04X ", mii);
2362	  }
2363        printf("\n\n");
2364        break;
2365        }
2366      case 'M': /* write MII reg */
2367        {
2368        u_int32_t addr = strtoul(optarg, NULL, 0);
2369        u_int32_t data = strtoul(argv[optind++], NULL, 0);
2370        write_mii(addr, data);
2371        if (verbose)
2372          {
2373          data = read_mii(addr);
2374          printf("Write mii register: addr = 0x%02X data = 0x%04X\n", addr, data);
2375	  }
2376        break;
2377        }
2378      case 'p': /* read and print PCI config regs */
2379        {
2380        int i;
2381        printf("21140A PCI Config regs:\n");
2382        printf("       0        1        2        3");
2383        for (i=0; i<16; i++)
2384          {
2385          if (i%4 == 0) printf("\n%X: ", i);
2386          printf("%08X ", read_pci_config(i<<2));
2387	  }
2388        printf("\n\n");
2389        break;
2390	}
2391      case 'P': /* write PCI config reg */
2392        {
2393        u_int32_t addr = strtoul(optarg, NULL, 0);
2394        u_int32_t data = strtoul(argv[optind++], NULL, 0);
2395        write_pci_config(addr, data);
2396        if (verbose)
2397          {
2398          data = read_pci_config(addr);
2399          printf("Write PCI config reg: addr = 0x%02X data = 0x%08X\n", addr, data);
2400	  }
2401        break;
2402	}
2403      case 's': /* read and print Tulip SROM */
2404        {
2405        int i;
2406        printf("21140A SROM:\n");
2407        printf("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");
2408        for (i=0; i<64; i++)
2409          {
2410          u_int16_t srom = read_srom(i);
2411          if (i%8 == 0) printf("\n%02X: ", i<<1);
2412          printf("%02X %02X ", srom & 0xFF, srom>>8);
2413	  }
2414        printf("\n\n");
2415        break;
2416	}
2417      case 'S': /* write Tulip SROM loc */
2418        {
2419#if 0  /* write a single location -- not too useful */
2420        u_int32_t addr = strtoul(optarg, NULL, 0);
2421        u_int32_t data = strtoul(argv[optind++], NULL, 0);
2422        write_mii(addr, data);
2423        data = read_mii(addr);
2424        printf("Write SROM: addr = 0x%02X data = 0x%04X\n", addr, data);
2425#endif
2426#if 0  /* write the whole SROM -- very dangerous */
2427        init_srom(strtoul(optarg, NULL, 0));
2428#endif
2429        printf("Caution! Recompile %s to enable this.\n", progname);
2430        break;
2431	}
2432      case 't': /* read and print Tulip CSRs */
2433        {
2434        int i;
2435        printf("21140A CSRs:\n");
2436        printf("       0        1        2        3");
2437        for (i=0; i<16; i++)
2438          {
2439          if (i%4 == 0) printf("\n%X: ", i);
2440          printf("%08X ", read_csr(i));
2441	  }
2442        printf("\n\n");
2443        break;
2444	}
2445      case 'T': /* write Tulip CSR */
2446        {
2447        u_int32_t addr = strtoul(optarg, NULL, 0);
2448        u_int32_t data = strtoul(argv[optind++], NULL, 0);
2449        write_csr(addr, data);
2450        if (verbose)
2451          {
2452          data = read_csr(addr);
2453          printf("Write 21140A CSR: addr = 0x%02X data = 0x%08X\n", addr, data);
2454	  }
2455        break;
2456	}
2457      case 'u': /* reset event counters */
2458        {
2459        ioctl_reset_cntrs();
2460        if (verbose) printf("Event counters reset\n");
2461        break;
2462	}
2463      case 'U': /* reset gate array */
2464        {
2465        reset_xilinx();
2466        if (verbose) printf("gate array reset\n");
2467        break;
2468        }
2469      case 'v': /* set verbose mode */
2470        {
2471        verbose = 1;
2472        break;
2473        }
2474      case 'V': /* print card configuration */
2475        {
2476        summary = 1;
2477        break;
2478	}
2479      case 'w': /* load gate array microcode from ROM */
2480        {
2481        load_xilinx_from_rom();
2482        if (verbose) printf("gate array configured from on-board ROM\n");
2483        break;
2484        }
2485      case 'W': /* load gate array microcode from file */
2486        {
2487        load_xilinx(optarg);
2488        if (verbose) printf("gate array configured from file %s\n", optarg);
2489        break;
2490        }
2491      case 'x': /* select RAWIP protocol */
2492        {
2493        config.line_pkg = PKG_RAWIP;
2494        if (verbose) printf("RAWIP mode selected\n");
2495        update = 1;
2496        break;
2497	}
2498      case 'X': /* Select in-kernel line protocol packages */
2499        {
2500        config.line_pkg = 0;
2501        if (verbose) printf("line protocol mode selected\n");
2502        update = 1;
2503        break;
2504	}
2505      case 'y': /* disable SPPP keep-alive packets */
2506        {
2507        if ((config.line_pkg  == PKG_SPPP) &&
2508            (config.line_prot == PROT_FRM_RLY))
2509          printf("keep-alives must be ON for Frame-Relay/SPPP\n");
2510        else
2511          {
2512          config.keep_alive = 0;
2513          if (verbose) printf("SPPP keep-alive packets disabled\n");
2514          update = 1;
2515	  }
2516        break;
2517	}
2518      case 'Y': /* enable SPPP keep-alive packets */
2519        {
2520        config.keep_alive = 1;
2521        if (verbose) printf("SPPP keep-alive packets enabled\n");
2522        update = 1;
2523        break;
2524	}
2525      case 'z': /* set SPPP line protocol to Cisco HDLC */
2526        {
2527        config.line_prot = PROT_C_HDLC;
2528        config.keep_alive = 1;
2529        if (verbose) printf("SPPP line protocol set to Cisco-HDLC\n");
2530        update = 1;
2531        break;
2532	}
2533      case 'Z': /* set SPPP line protocol to PPP */
2534        {
2535        config.line_prot = PROT_PPP;
2536        config.keep_alive = 0;
2537        if (verbose) printf("SPPP line protocol set to PPP\n");
2538        update = 1;
2539        break;
2540	}
2541      default:
2542        {
2543        printf("Unknown command char: %c\n", ch);
2544        exit(1);
2545	}
2546      } /* switch */
2547    } /* while */
2548
2549  if (summary) print_summary();
2550
2551  /*  5) Write the modified interface configuration to the driver. */
2552  if (update) ioctl_write_config();
2553
2554  exit(0);
2555}
2556