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