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