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 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 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 282 prefix(char *arg, char *pref) 283 { 284 return (strncmp(arg, pref, strlen(pref)) == 0); 285 } 286 287 static int 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