syncinit.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Initialize and re-initialize synchronous serial clocking and loopback
* options. Interfaces through the S_IOCGETMODE and S_IOCSETMODE ioctls.
*/
#include <sys/types.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stream.h>
#include <sys/stropts.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ser_sync.h>
#include <libdlpi.h>
static void usage(void);
static int prefix(char *arg, char *pref);
static int lookup(char **table, char *arg);
static char *yesno[] = {
"no",
"yes",
"silent",
0,
};
static char *txnames[] = {
"txc",
"rxc",
"baud",
"pll",
"sysclk",
"-txc",
0,
};
static char *rxnames[] = {
"rxc",
"txc",
"baud",
"pll",
"sysclk",
"-rxc",
0,
};
#ifdef notdef
static char *txdnames[] = {
"txd",
" ", /* dummy entry, do not remove */
"-txd",
0,
};
static char *rxdnames[] = {
"rxd",
"-rxd",
0,
};
static char *portab[] = {
"rs422",
"v35",
0,
};
#endif
#define equal(a, b) (strcmp((a), (b)) == 0)
#define MAXWAIT 15
int
main(int argc, char **argv)
{
char cnambuf[MAXPATHLEN];
struct scc_mode sm;
struct strioctl sioc;
int fd, speed;
char *arg, *cp;
char loopchange = 0;
char echochange = 0;
char clockchange = 0;
char *devstr = "/dev/";
int devstrlen;
ulong_t ppa;
if (argc == 1) {
usage();
exit(1);
}
argc--;
argv++;
devstrlen = strlen(devstr);
if (strncmp(devstr, argv[0], devstrlen) != 0) {
if (snprintf(cnambuf, sizeof (cnambuf), "%s%s", devstr,
argv[0]) >= sizeof (cnambuf)) {
(void) fprintf(stderr,
"syncinit: invalid device name (too long) %s\n",
argv[0]);
exit(1);
}
}
cp = cnambuf;
while (*cp) /* find the end of the name */
cp++;
cp--;
if (!isdigit(*cp)) {
(void) fprintf(stderr,
"syncinit: %s missing minor device number\n", argv[0]);
exit(1);
}
while (isdigit(*(cp - 1)))
cp--;
ppa = strtoul(cp, NULL, 10);
*cp = '\0'; /* drop number, leaving name of clone device. */
fd = open(cnambuf, O_RDWR|O_EXCL, 0);
if (fd < 0) {
perror("syncinit: open");
exit(1);
}
if (dlpi_attach(fd, MAXWAIT, ppa) != 0) {
perror("syncinit: dlpi_attach");
exit(1);
}
(void) printf("device: %s ppa: %d\n", cnambuf, (int)ppa);
argc--;
argv++;
if (argc) { /* setting things */
sioc.ic_cmd = S_IOCGETMODE;
sioc.ic_timout = -1;
sioc.ic_len = sizeof (struct scc_mode);
sioc.ic_dp = (char *)&sm;
if (ioctl(fd, I_STR, &sioc) < 0) {
perror("S_IOCGETMODE");
(void) fprintf(stderr,
"syncinit: can't get sync mode info for %s\n",
cnambuf);
exit(1);
}
while (argc-- > 0) {
arg = *argv++;
if (sscanf(arg, "%d", &speed) == 1)
sm.sm_baudrate = speed;
else if (strchr(arg, '=')) {
if (prefix(arg, "loop")) {
if (lookup(yesno, arg))
sm.sm_config |= CONN_LPBK;
else
sm.sm_config &= ~CONN_LPBK;
loopchange++;
} else if (prefix(arg, "echo")) {
if (lookup(yesno, arg))
sm.sm_config |= CONN_ECHO;
else
sm.sm_config &= ~CONN_ECHO;
echochange++;
} else if (prefix(arg, "nrzi")) {
if (lookup(yesno, arg))
sm.sm_config |= CONN_NRZI;
else
sm.sm_config &= ~CONN_NRZI;
} else if (prefix(arg, "txc")) {
sm.sm_txclock = lookup(txnames, arg);
clockchange++;
} else if (prefix(arg, "rxc")) {
sm.sm_rxclock = lookup(rxnames, arg);
clockchange++;
} else if (prefix(arg, "speed")) {
arg = strchr(arg, '=') + 1;
if (sscanf(arg, "%d", &speed) == 1) {
sm.sm_baudrate = speed;
} else
(void) fprintf(stderr,
"syncinit: %s %s\n",
"bad speed:", arg);
}
} else if (equal(arg, "external")) {
sm.sm_txclock = TXC_IS_TXC;
sm.sm_rxclock = RXC_IS_RXC;
sm.sm_config &= ~CONN_LPBK;
} else if (equal(arg, "sender")) {
sm.sm_txclock = TXC_IS_BAUD;
sm.sm_rxclock = RXC_IS_RXC;
sm.sm_config &= ~CONN_LPBK;
} else if (equal(arg, "internal")) {
sm.sm_txclock = TXC_IS_PLL;
sm.sm_rxclock = RXC_IS_PLL;
sm.sm_config &= ~CONN_LPBK;
} else if (equal(arg, "stop")) {
sm.sm_baudrate = 0;
} else
(void) fprintf(stderr, "Bad arg: %s\n", arg);
}
/*
* If we're going to change the state of loopback, and we
* don't have our own plans for clock sources, use defaults.
*/
if (loopchange && !clockchange) {
if (sm.sm_config & CONN_LPBK) {
sm.sm_txclock = TXC_IS_BAUD;
sm.sm_rxclock = RXC_IS_BAUD;
} else {
sm.sm_txclock = TXC_IS_TXC;
sm.sm_rxclock = RXC_IS_RXC;
}
}
sioc.ic_cmd = S_IOCSETMODE;
sioc.ic_timout = -1;
sioc.ic_len = sizeof (struct scc_mode);
sioc.ic_dp = (char *)&sm;
if (ioctl(fd, I_STR, &sioc) < 0) {
perror("S_IOCSETMODE");
(void) ioctl(fd, S_IOCGETMODE, &sm);
(void) fprintf(stderr,
"syncinit: ioctl failure code = %x\n",
sm.sm_retval);
exit(1);
}
}
/* Report State */
sioc.ic_cmd = S_IOCGETMODE;
sioc.ic_timout = -1;
sioc.ic_len = sizeof (struct scc_mode);
sioc.ic_dp = (char *)&sm;
if (ioctl(fd, I_STR, &sioc) < 0) {
perror("S_IOCGETMODE");
(void) fprintf(stderr,
"syncinit: can't get sync mode info for %s\n",
cnambuf);
exit(1);
}
(void) printf(
"speed=%d, loopback=%s, echo=%s, nrzi=%s, txc=%s, rxc=%s\n",
sm.sm_baudrate,
yesno[((int)(sm.sm_config & CONN_LPBK) > 0)],
yesno[((int)(sm.sm_config & CONN_ECHO) > 0)],
yesno[((int)(sm.sm_config & CONN_NRZI) > 0)],
txnames[sm.sm_txclock],
rxnames[sm.sm_rxclock]);
return (0);
}
static void
usage()
{
(void) fprintf(stderr, "Usage: syncinit cnambuf \\\n");
(void) fprintf(stderr, "\t[baudrate] [loopback=[yes|no]] ");
(void) fprintf(stderr, "[echo=[yes|no]] [nrzi=[yes|no]] \\\n");
(void) fprintf(stderr, "\t[txc=[txc|rxc|baud|pll]] \\\n");
(void) fprintf(stderr, "\t[rxc=[rxc|txc|baud|pll]]\n");
exit(1);
}
static int
prefix(char *arg, char *pref)
{
return (strncmp(arg, pref, strlen(pref)) == 0);
}
static int
lookup(char **table, char *arg)
{
char *val = strchr(arg, '=') + 1;
int ival;
for (ival = 0; *table != 0; ival++, table++)
if (equal(*table, val))
return (ival);
(void) fprintf(stderr, "syncinit: bad arg: %s\n", arg);
exit(1);
/* NOTREACHED */
}