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