1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Initialize and re-initialize synchronous serial clocking and loopback
31*0Sstevel@tonic-gate  * options.  Interfaces through the S_IOCGETMODE and S_IOCSETMODE ioctls.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate 
34*0Sstevel@tonic-gate #include <sys/types.h>
35*0Sstevel@tonic-gate #include <ctype.h>
36*0Sstevel@tonic-gate #include <sys/ioctl.h>
37*0Sstevel@tonic-gate #include <stdio.h>
38*0Sstevel@tonic-gate #include <stdlib.h>
39*0Sstevel@tonic-gate #include <unistd.h>
40*0Sstevel@tonic-gate #include <string.h>
41*0Sstevel@tonic-gate #include <sys/stream.h>
42*0Sstevel@tonic-gate #include <sys/stropts.h>
43*0Sstevel@tonic-gate #include <fcntl.h>
44*0Sstevel@tonic-gate #include <errno.h>
45*0Sstevel@tonic-gate #include <sys/ser_sync.h>
46*0Sstevel@tonic-gate #include <libdlpi.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate static void usage(void);
49*0Sstevel@tonic-gate static int prefix(char *arg, char *pref);
50*0Sstevel@tonic-gate static int lookup(char **table, char *arg);
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate static char *yesno[] = {
53*0Sstevel@tonic-gate 	"no",
54*0Sstevel@tonic-gate 	"yes",
55*0Sstevel@tonic-gate 	"silent",
56*0Sstevel@tonic-gate 	0,
57*0Sstevel@tonic-gate };
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate static char *txnames[] = {
60*0Sstevel@tonic-gate 	"txc",
61*0Sstevel@tonic-gate 	"rxc",
62*0Sstevel@tonic-gate 	"baud",
63*0Sstevel@tonic-gate 	"pll",
64*0Sstevel@tonic-gate 	"sysclk",
65*0Sstevel@tonic-gate 	"-txc",
66*0Sstevel@tonic-gate 	0,
67*0Sstevel@tonic-gate };
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate static char *rxnames[] = {
70*0Sstevel@tonic-gate 	"rxc",
71*0Sstevel@tonic-gate 	"txc",
72*0Sstevel@tonic-gate 	"baud",
73*0Sstevel@tonic-gate 	"pll",
74*0Sstevel@tonic-gate 	"sysclk",
75*0Sstevel@tonic-gate 	"-rxc",
76*0Sstevel@tonic-gate 	0,
77*0Sstevel@tonic-gate };
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate #ifdef notdef
80*0Sstevel@tonic-gate static char *txdnames[] = {
81*0Sstevel@tonic-gate 	"txd",
82*0Sstevel@tonic-gate 	" ",	/* dummy entry, do not remove */
83*0Sstevel@tonic-gate 	"-txd",
84*0Sstevel@tonic-gate 	0,
85*0Sstevel@tonic-gate };
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate static char *rxdnames[] = {
88*0Sstevel@tonic-gate 	"rxd",
89*0Sstevel@tonic-gate 	"-rxd",
90*0Sstevel@tonic-gate 	0,
91*0Sstevel@tonic-gate };
92*0Sstevel@tonic-gate 
93*0Sstevel@tonic-gate static char *portab[] = {
94*0Sstevel@tonic-gate 	"rs422",
95*0Sstevel@tonic-gate 	"v35",
96*0Sstevel@tonic-gate 	0,
97*0Sstevel@tonic-gate };
98*0Sstevel@tonic-gate #endif
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate #define	equal(a, b)	(strcmp((a), (b)) == 0)
101*0Sstevel@tonic-gate #define	MAXWAIT		15
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate int
104*0Sstevel@tonic-gate main(int argc, char **argv)
105*0Sstevel@tonic-gate {
106*0Sstevel@tonic-gate 	char cnambuf[MAXPATHLEN];
107*0Sstevel@tonic-gate 	struct scc_mode sm;
108*0Sstevel@tonic-gate 	struct strioctl sioc;
109*0Sstevel@tonic-gate 	int fd, speed;
110*0Sstevel@tonic-gate 	char *arg, *cp;
111*0Sstevel@tonic-gate 	char loopchange = 0;
112*0Sstevel@tonic-gate 	char echochange = 0;
113*0Sstevel@tonic-gate 	char clockchange = 0;
114*0Sstevel@tonic-gate 	char *devstr =  "/dev/";
115*0Sstevel@tonic-gate 	int devstrlen;
116*0Sstevel@tonic-gate 	ulong_t ppa;
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	if (argc == 1) {
119*0Sstevel@tonic-gate 		usage();
120*0Sstevel@tonic-gate 		exit(1);
121*0Sstevel@tonic-gate 	}
122*0Sstevel@tonic-gate 	argc--;
123*0Sstevel@tonic-gate 	argv++;
124*0Sstevel@tonic-gate 	devstrlen = strlen(devstr);
125*0Sstevel@tonic-gate 	if (strncmp(devstr, argv[0], devstrlen) != 0) {
126*0Sstevel@tonic-gate 		if (snprintf(cnambuf, sizeof (cnambuf), "%s%s", devstr,
127*0Sstevel@tonic-gate 		    argv[0]) >= sizeof (cnambuf)) {
128*0Sstevel@tonic-gate 			(void) fprintf(stderr,
129*0Sstevel@tonic-gate 			    "syncinit: invalid device name (too long) %s\n",
130*0Sstevel@tonic-gate 			    argv[0]);
131*0Sstevel@tonic-gate 			exit(1);
132*0Sstevel@tonic-gate 		}
133*0Sstevel@tonic-gate 	}
134*0Sstevel@tonic-gate 	cp = cnambuf;
135*0Sstevel@tonic-gate 	while (*cp)			/* find the end of the name */
136*0Sstevel@tonic-gate 		cp++;
137*0Sstevel@tonic-gate 	cp--;
138*0Sstevel@tonic-gate 	if (!isdigit(*cp)) {
139*0Sstevel@tonic-gate 		(void) fprintf(stderr,
140*0Sstevel@tonic-gate 			"syncinit: %s missing minor device number\n", argv[0]);
141*0Sstevel@tonic-gate 		exit(1);
142*0Sstevel@tonic-gate 	}
143*0Sstevel@tonic-gate 	while (isdigit(*(cp - 1)))
144*0Sstevel@tonic-gate 		cp--;
145*0Sstevel@tonic-gate 	ppa = strtoul(cp, NULL, 10);
146*0Sstevel@tonic-gate 	*cp = '\0';	/* drop number, leaving name of clone device. */
147*0Sstevel@tonic-gate 	fd = open(cnambuf, O_RDWR|O_EXCL, 0);
148*0Sstevel@tonic-gate 	if (fd < 0) {
149*0Sstevel@tonic-gate 		perror("syncinit: open");
150*0Sstevel@tonic-gate 		exit(1);
151*0Sstevel@tonic-gate 	}
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	if (dlpi_attach(fd, MAXWAIT, ppa) != 0) {
154*0Sstevel@tonic-gate 		perror("syncinit: dlpi_attach");
155*0Sstevel@tonic-gate 		exit(1);
156*0Sstevel@tonic-gate 	}
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate 	(void) printf("device: %s  ppa: %d\n", cnambuf, (int)ppa);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	argc--;
161*0Sstevel@tonic-gate 	argv++;
162*0Sstevel@tonic-gate 	if (argc) {	/* setting things */
163*0Sstevel@tonic-gate 		sioc.ic_cmd = S_IOCGETMODE;
164*0Sstevel@tonic-gate 		sioc.ic_timout = -1;
165*0Sstevel@tonic-gate 		sioc.ic_len = sizeof (struct scc_mode);
166*0Sstevel@tonic-gate 		sioc.ic_dp = (char *)&sm;
167*0Sstevel@tonic-gate 		if (ioctl(fd, I_STR, &sioc) < 0) {
168*0Sstevel@tonic-gate 			perror("S_IOCGETMODE");
169*0Sstevel@tonic-gate 			(void) fprintf(stderr,
170*0Sstevel@tonic-gate 				"syncinit: can't get sync mode info for %s\n",
171*0Sstevel@tonic-gate 				cnambuf);
172*0Sstevel@tonic-gate 			exit(1);
173*0Sstevel@tonic-gate 		}
174*0Sstevel@tonic-gate 		while (argc-- > 0) {
175*0Sstevel@tonic-gate 			arg = *argv++;
176*0Sstevel@tonic-gate 			if (sscanf(arg, "%d", &speed) == 1)
177*0Sstevel@tonic-gate 				sm.sm_baudrate = speed;
178*0Sstevel@tonic-gate 			else if (strchr(arg, '=')) {
179*0Sstevel@tonic-gate 				if (prefix(arg, "loop")) {
180*0Sstevel@tonic-gate 					if (lookup(yesno, arg))
181*0Sstevel@tonic-gate 						sm.sm_config |= CONN_LPBK;
182*0Sstevel@tonic-gate 					else
183*0Sstevel@tonic-gate 						sm.sm_config &= ~CONN_LPBK;
184*0Sstevel@tonic-gate 					loopchange++;
185*0Sstevel@tonic-gate 				} else if (prefix(arg, "echo")) {
186*0Sstevel@tonic-gate 					if (lookup(yesno, arg))
187*0Sstevel@tonic-gate 						sm.sm_config |= CONN_ECHO;
188*0Sstevel@tonic-gate 					else
189*0Sstevel@tonic-gate 						sm.sm_config &= ~CONN_ECHO;
190*0Sstevel@tonic-gate 					echochange++;
191*0Sstevel@tonic-gate 				} else if (prefix(arg, "nrzi")) {
192*0Sstevel@tonic-gate 					if (lookup(yesno, arg))
193*0Sstevel@tonic-gate 						sm.sm_config |= CONN_NRZI;
194*0Sstevel@tonic-gate 					else
195*0Sstevel@tonic-gate 						sm.sm_config &= ~CONN_NRZI;
196*0Sstevel@tonic-gate 				} else if (prefix(arg, "txc")) {
197*0Sstevel@tonic-gate 					sm.sm_txclock = lookup(txnames, arg);
198*0Sstevel@tonic-gate 					clockchange++;
199*0Sstevel@tonic-gate 				} else if (prefix(arg, "rxc")) {
200*0Sstevel@tonic-gate 					sm.sm_rxclock = lookup(rxnames, arg);
201*0Sstevel@tonic-gate 					clockchange++;
202*0Sstevel@tonic-gate 				} else if (prefix(arg, "speed")) {
203*0Sstevel@tonic-gate 					arg = strchr(arg, '=') + 1;
204*0Sstevel@tonic-gate 					if (sscanf(arg, "%d", &speed) == 1) {
205*0Sstevel@tonic-gate 						sm.sm_baudrate = speed;
206*0Sstevel@tonic-gate 					} else
207*0Sstevel@tonic-gate 						(void) fprintf(stderr,
208*0Sstevel@tonic-gate 						    "syncinit: %s %s\n",
209*0Sstevel@tonic-gate 						    "bad speed:", arg);
210*0Sstevel@tonic-gate 				}
211*0Sstevel@tonic-gate 			} else if (equal(arg, "external")) {
212*0Sstevel@tonic-gate 				sm.sm_txclock = TXC_IS_TXC;
213*0Sstevel@tonic-gate 				sm.sm_rxclock = RXC_IS_RXC;
214*0Sstevel@tonic-gate 				sm.sm_config &= ~CONN_LPBK;
215*0Sstevel@tonic-gate 			} else if (equal(arg, "sender")) {
216*0Sstevel@tonic-gate 				sm.sm_txclock = TXC_IS_BAUD;
217*0Sstevel@tonic-gate 				sm.sm_rxclock = RXC_IS_RXC;
218*0Sstevel@tonic-gate 				sm.sm_config &= ~CONN_LPBK;
219*0Sstevel@tonic-gate 			} else if (equal(arg, "internal")) {
220*0Sstevel@tonic-gate 				sm.sm_txclock = TXC_IS_PLL;
221*0Sstevel@tonic-gate 				sm.sm_rxclock = RXC_IS_PLL;
222*0Sstevel@tonic-gate 				sm.sm_config &= ~CONN_LPBK;
223*0Sstevel@tonic-gate 			} else if (equal(arg, "stop")) {
224*0Sstevel@tonic-gate 				sm.sm_baudrate = 0;
225*0Sstevel@tonic-gate 			} else
226*0Sstevel@tonic-gate 				(void) fprintf(stderr, "Bad arg: %s\n", arg);
227*0Sstevel@tonic-gate 		}
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 		/*
230*0Sstevel@tonic-gate 		 * If we're going to change the state of loopback, and we
231*0Sstevel@tonic-gate 		 * don't have our own plans for clock sources, use defaults.
232*0Sstevel@tonic-gate 		 */
233*0Sstevel@tonic-gate 		if (loopchange && !clockchange) {
234*0Sstevel@tonic-gate 			if (sm.sm_config & CONN_LPBK) {
235*0Sstevel@tonic-gate 				sm.sm_txclock = TXC_IS_BAUD;
236*0Sstevel@tonic-gate 				sm.sm_rxclock = RXC_IS_BAUD;
237*0Sstevel@tonic-gate 			} else {
238*0Sstevel@tonic-gate 				sm.sm_txclock = TXC_IS_TXC;
239*0Sstevel@tonic-gate 				sm.sm_rxclock = RXC_IS_RXC;
240*0Sstevel@tonic-gate 			}
241*0Sstevel@tonic-gate 		}
242*0Sstevel@tonic-gate 		sioc.ic_cmd = S_IOCSETMODE;
243*0Sstevel@tonic-gate 		sioc.ic_timout = -1;
244*0Sstevel@tonic-gate 		sioc.ic_len = sizeof (struct scc_mode);
245*0Sstevel@tonic-gate 		sioc.ic_dp = (char *)&sm;
246*0Sstevel@tonic-gate 		if (ioctl(fd, I_STR, &sioc) < 0) {
247*0Sstevel@tonic-gate 			perror("S_IOCSETMODE");
248*0Sstevel@tonic-gate 			(void) ioctl(fd, S_IOCGETMODE, &sm);
249*0Sstevel@tonic-gate 			(void) fprintf(stderr,
250*0Sstevel@tonic-gate 				"syncinit: ioctl failure code = %x\n",
251*0Sstevel@tonic-gate 				sm.sm_retval);
252*0Sstevel@tonic-gate 			exit(1);
253*0Sstevel@tonic-gate 		}
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	/* Report State */
257*0Sstevel@tonic-gate 	sioc.ic_cmd = S_IOCGETMODE;
258*0Sstevel@tonic-gate 	sioc.ic_timout = -1;
259*0Sstevel@tonic-gate 	sioc.ic_len = sizeof (struct scc_mode);
260*0Sstevel@tonic-gate 	sioc.ic_dp = (char *)&sm;
261*0Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &sioc) < 0) {
262*0Sstevel@tonic-gate 		perror("S_IOCGETMODE");
263*0Sstevel@tonic-gate 		(void) fprintf(stderr,
264*0Sstevel@tonic-gate 			"syncinit: can't get sync mode info for %s\n",
265*0Sstevel@tonic-gate 			cnambuf);
266*0Sstevel@tonic-gate 		exit(1);
267*0Sstevel@tonic-gate 	}
268*0Sstevel@tonic-gate 	(void) printf(
269*0Sstevel@tonic-gate "speed=%d, loopback=%s, echo=%s, nrzi=%s, txc=%s, rxc=%s\n",
270*0Sstevel@tonic-gate 		sm.sm_baudrate,
271*0Sstevel@tonic-gate 		yesno[((int)(sm.sm_config & CONN_LPBK) > 0)],
272*0Sstevel@tonic-gate 		yesno[((int)(sm.sm_config & CONN_ECHO) > 0)],
273*0Sstevel@tonic-gate 		yesno[((int)(sm.sm_config & CONN_NRZI) > 0)],
274*0Sstevel@tonic-gate 		txnames[sm.sm_txclock],
275*0Sstevel@tonic-gate 		rxnames[sm.sm_rxclock]);
276*0Sstevel@tonic-gate 	return (0);
277*0Sstevel@tonic-gate }
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate static void
280*0Sstevel@tonic-gate usage()
281*0Sstevel@tonic-gate {
282*0Sstevel@tonic-gate 	(void) fprintf(stderr, "Usage: syncinit cnambuf \\\n");
283*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\t[baudrate] [loopback=[yes|no]] ");
284*0Sstevel@tonic-gate 	(void) fprintf(stderr, "[echo=[yes|no]] [nrzi=[yes|no]] \\\n");
285*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\t[txc=[txc|rxc|baud|pll]] \\\n");
286*0Sstevel@tonic-gate 	(void) fprintf(stderr, "\t[rxc=[rxc|txc|baud|pll]]\n");
287*0Sstevel@tonic-gate 	exit(1);
288*0Sstevel@tonic-gate }
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate static int
291*0Sstevel@tonic-gate prefix(char *arg, char *pref)
292*0Sstevel@tonic-gate {
293*0Sstevel@tonic-gate 	return (strncmp(arg, pref, strlen(pref)) == 0);
294*0Sstevel@tonic-gate }
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate static int
297*0Sstevel@tonic-gate lookup(char **table, char *arg)
298*0Sstevel@tonic-gate {
299*0Sstevel@tonic-gate 	char *val = strchr(arg, '=') + 1;
300*0Sstevel@tonic-gate 	int ival;
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	for (ival = 0; *table != 0; ival++, table++)
303*0Sstevel@tonic-gate 		if (equal(*table, val))
304*0Sstevel@tonic-gate 			return (ival);
305*0Sstevel@tonic-gate 	(void) fprintf(stderr, "syncinit: bad arg: %s\n", arg);
306*0Sstevel@tonic-gate 	exit(1);
307*0Sstevel@tonic-gate 	/* NOTREACHED */
308*0Sstevel@tonic-gate }
309