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