aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/sccd/files/scc.c
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/sccd/files/scc.c')
-rw-r--r--recipes/sccd/files/scc.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/recipes/sccd/files/scc.c b/recipes/sccd/files/scc.c
new file mode 100644
index 0000000000..b917bf1ee8
--- /dev/null
+++ b/recipes/sccd/files/scc.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2006
+ * Protium Computing, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Protium Computing, Inc.
+ * 4. The name of Protium Computing, Inc. may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY PROTIUM COMPUTING ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL PROTIUM COMPUTING BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <termios.h>
+
+#include "scc.h"
+
+char * prog;
+int initialize = 0;
+int verbose = 0;
+
+scc_cmd_t powercmds[] = {
+ { "a", 0x61000000},
+ { "run", SCC_RUN},
+ { "off", SCC_STOP},
+ { "advoff", SCC_ADVISESTOP},
+ { "restart", SCC_RESTART,},
+ { "advrestart", SCC_ADVISERESTART},
+ { "reset", SCC_RESET,},
+ { "advreset", SCC_ADVISERESET},
+ { "EOT", -1}};
+
+scc_cmd_t ledcmds[] = {
+ { "off", SCC_LEDOFF},
+ { "blue", SCC_LEDBLUE},
+ { "red", SCC_LEDRED},
+ { "blueflash", SCC_LEDBLUEFLASH},
+ { "redflash", SCC_LEDREDFLASH},
+ { "alternate", SCC_LEDALTERNATE1},
+ { "alternate3", SCC_LEDALTERNATE3},
+ { "EOT", -1}};
+
+scc_cmd_t fancmds[]= {
+ { "auto", SCC_FANAUTO},
+ { "on", SCC_FANON},
+ { "EOT", -1}};
+
+void
+usage(void)
+{
+ int i;
+ scc_cmd_t *c;
+
+ fprintf(stderr, "Usage: %s OPTIONS\n", prog);
+ fprintf(stderr,"%s controls the Iomega StorCenter's LED, fan and soft power.\n\n", prog);
+ fprintf(stderr," -?\t\tthis message\n");
+ fprintf(stderr," -v\t\tverbose, show all packets\n");
+ fprintf(stderr," -d\t\tsend send directly, stop/restart only\n");
+ fprintf(stderr,"\n -p POWER\tcontrol soft power\n");
+ fprintf(stderr,"\t\tPOWER=[");
+ for (c = powercmds,i=0; c->scc_cmdval != -1; c++,i++) {
+ if (i) fprintf(stderr,"|");
+ fprintf(stderr,"%s", c->scc_cmd);
+ }
+ fprintf(stderr,"]\n\n");
+
+ fprintf(stderr," -l LED\tcontrol LED state\n");
+ fprintf(stderr,"\t\tLED=[");
+ for (c = ledcmds,i=0; c->scc_cmdval != -1; c++,i++) {
+ if (i) fprintf(stderr,"|");
+ fprintf(stderr,"%s", c->scc_cmd);
+ }
+ fprintf(stderr,"]\n -r RATE\tRate the LED flashes (0<=RATE<256)\n\n");
+
+
+ fprintf(stderr," -f FAN\tcontrol fan operation\n");
+ fprintf(stderr,"\t\tFAN=[");
+ for (c = fancmds,i=0; c->scc_cmdval != -1; c++,i++) {
+ if (i) fprintf(stderr,"|");
+ fprintf(stderr,"%s", c->scc_cmd);
+ }
+ fprintf(stderr,"]\n -h TEMP\tHot temp when FAN=auto should go on (0<=TEMP<256)\n");
+ fprintf(stderr," -c TEMP\tCold temp when FAN=auto should go off (0<=TEMP<256)\n");
+
+ (void)exit(2);
+}
+
+int
+sendrecv(int fd, int *i, int *j)
+{
+ char buf[8];
+ int rc;
+ fd_set fds;
+ struct timeval sec = {1, 0};
+ struct timespec tenth_sec = {0, 100000000};
+
+
+ /* build the buffer */
+ *(int *)(buf) = *i;
+ *(int *)(buf + 4) = *j;
+
+ if (verbose)
+ printf("Send: [0x%08x 0x%08x]\n", *i, *j);
+
+ if ((rc = write(fd, buf, 8)) != 8) {
+ perror("write failed failed");
+ return(-1);
+ }
+
+ /* Wait for data */
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ rc = select(1024, &fds, NULL, NULL, &sec);
+
+ if (rc == -1) {
+ perror("select failed");
+ return (-1);
+ } else if (!rc) {
+ perror("select timedout");
+ return (-1);
+ }
+
+ /* Consume it */
+ if ((rc = read(fd, buf, 8)) != 8) {
+ perror("read failed failed");
+ return(-1);
+ }
+
+ *i = *(int *)(buf);
+ *j = *(int *)(buf + 4);
+
+ if (verbose)
+ printf("Recv: [0x%08x 0x%08x]\n", *i, *j);
+
+ /* Let it rest */
+ nanosleep(&tenth_sec, NULL);
+
+ return(0);
+}
+
+int
+setup_clnt()
+{
+ int s, len;
+ struct sockaddr_un remote;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ return(-1);
+ }
+
+ remote.sun_family = AF_UNIX;
+ strcpy(remote.sun_path, SCC_SOCKET);
+ len = strlen(remote.sun_path) + sizeof(remote.sun_family);
+ if (connect(s, (struct sockaddr *)&remote, len) == -1) {
+ return(-1);
+ }
+
+ return(s);
+}
+
+int
+setup_cntlr(int *i, int *j)
+{
+ int fd;
+ char *dev = SCC_DEVICE;
+ struct termios ti;
+
+ /* setup the serial connection to 9600, 8n1 */
+ if ((fd = open(dev, O_RDWR|O_NOCTTY)) < 0) {
+ perror("Open failed");
+ return(-1);
+ }
+
+ if (ioctl(fd, TCGETS, &ti) < 0) {
+ perror("TCGETS failed");
+ return(-1);
+ }
+
+ if (ioctl(fd, TCFLSH, 0) < 0) {
+ perror("TCFLSH failed");
+ return(-1);
+ }
+
+ ti.c_iflag = IGNPAR;
+ ti.c_oflag = 0;
+ ti.c_cflag = (B9600 | CS8 | CREAD | CLOCAL);
+ ti.c_lflag = 0;
+ ti.c_line = N_TTY;
+ bzero(ti.c_cc, NCCS);
+ ti.c_cc[VMIN] = 0x08;
+
+ if (ioctl(fd, TCSETS, &ti) < 0) {
+ perror("TCSETS failed");
+ return(-1);
+ }
+
+ if (verbose) printf("Resetting microcontroller\n");
+ *i = SCC_RESETW1;
+ *j = SCC_RESETW2;
+ scc_setval(i, SCC_IDMASK, SCC_HOST);
+ scc_setval(j, SCC_CKSUMMASK, (int)scc_cksum(i, j));
+ if (sendrecv(fd, i, j) < 0)
+ return(-1);
+
+ return(fd);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ int devfd, w1, w2, h1, h2;
+ int coldtemp, hottemp, fancmd;
+ int ledrate, ledcmd;
+ int powercmd;
+ int direct;
+ int c;
+ char buf[SCC_PACKETLEN];
+ scc_cmd_t *ct;
+
+ extern char *optarg;
+ extern int optind, opterr, optopt;
+
+ prog = argv[0];
+ fancmd = coldtemp = hottemp = -1;
+ ledcmd = ledrate = -1;
+ powercmd = -1;
+ direct = 0;
+
+ while ((c = getopt(argc, argv, "c:df:h:l:p:r:wv?")) != EOF) {
+ switch (c) {
+ case 'c':
+ if (coldtemp != -1) /* more than one -c arg */
+ usage();
+
+ coldtemp = atoi(optarg);
+ if ((coldtemp > 255) || (coldtemp < 0))
+ usage();
+ break;
+ case 'd':
+ direct = 1;
+ break;
+ case 'f':
+ if (fancmd != -1) /* more than one -f arg */
+ usage();
+
+ for (ct = fancmds; ct->scc_cmdval != -1; ct++) {
+ if (!strcmp(ct->scc_cmd, optarg)) {
+ fancmd = ct->scc_cmdval;
+ }
+ }
+
+ if (fancmd == -1) /* Failed to find the req */
+ usage();
+
+ break;
+ case 'h':
+ if (hottemp != -1) /* more than one -h arg */
+ usage();
+
+ hottemp = atoi(optarg);
+ if ((hottemp > 255) || (hottemp < 0))
+ usage();
+ break;
+ case 'l':
+ if (ledcmd != -1) /* more than one -l arg */
+ usage();
+
+ for (ct = ledcmds; ct->scc_cmdval != -1; ct++) {
+ if (!strcmp(ct->scc_cmd, optarg)) {
+ ledcmd = ct->scc_cmdval;
+ }
+ }
+
+ if (ledcmd == -1) /* Failed to find the req */
+ usage();
+ break;
+ case 'p':
+ if (powercmd != -1) /* more than one -p arg */
+ usage();
+
+ for (ct = powercmds; ct->scc_cmdval != -1; ct++) {
+ if (!strcmp(ct->scc_cmd, optarg)) {
+ powercmd = ct->scc_cmdval;
+ }
+ }
+
+ if (powercmd == -1) /* Failed to find the req */
+ usage();
+ break;
+ case 'r':
+ if (ledrate != -1) /* more than one -h arg */
+ usage();
+
+ ledrate = atoi(optarg);
+ if ((ledrate > 255) || (ledrate < 0))
+ usage();
+ break;
+ case 'v':
+ verbose=1;
+ break;
+ case '?':
+ usage();
+ break;
+
+ }
+ }
+
+ if (direct) {
+ /*
+ * Setup the cntlr connection
+ */
+ if ((devfd = setup_cntlr(&w1, &w2)) < 0)
+ exit(1);
+ scc_defaults(&w1, &w2);
+ } else {
+ /*
+ * Setup the clnt connection, if we get an connection
+ * refused that means the daemon isn't listening.
+ * so go direct
+ */
+ w1 = 0;
+ w2 = 0;
+ if ((devfd = setup_clnt()) < 0) {
+ /* log it */
+ if ((devfd = setup_cntlr(&w1, &w2)) < 0)
+ exit(1);
+ direct = 1;
+ scc_defaults(&w1, &w2);
+ }
+ }
+
+ /*
+ * Direct (direct to the cntlr):
+ * w1 and w2 are setup with the default cntlr packet.
+ * Now lets poke the command line args into the packet.
+ *
+ * Nondirect (via the daemon):
+ * w1 and w2 are setup with nulls. The packet sent to the daemon
+ * contains only the changes to the current state.
+ */
+ if (powercmd != -1)
+ scc_setval(&w1, SCC_POWERMASK, powercmd);
+ if (ledcmd != -1)
+ scc_setval(&w1, SCC_LEDMASK, ledcmd);
+ if (ledrate != -1)
+ scc_setrate(&w1, SCC_LEDRATEMASK, SCC_LEDRATESHIFT, ledrate);
+ if (fancmd != -1)
+ scc_setval(&w1, SCC_FANMASK, fancmd);
+
+ if (coldtemp != -1)
+ scc_setrate(&w2,
+ SCC_FANTEMPOFFMASK, SCC_FANTEMPOFFSHIFT, coldtemp);
+ if (hottemp != -1)
+ scc_setrate(&w2,
+ SCC_FANTEMPONMASK, SCC_FANTEMPONSHIFT, hottemp);
+
+ scc_setval(&w2, SCC_IDMASK, SCC_HOST);
+ scc_setval(&w2, SCC_CKSUMMASK, (int)scc_cksum(&w1, &w2));
+
+
+ if (direct) {
+ if (verbose) {
+ printf("New State: \n");
+ scc_validate(&w1, &w2, verbose);
+ }
+
+ if (sendrecv(devfd, &w1, &w2) < 0)
+ exit(1);
+ } else {
+ *(int *)(&buf[0]) = w1;
+ *(int *)(&buf[4]) = w2;
+
+ if (send(devfd, buf, SCC_PACKETLEN, 0) == -1) {
+ perror("send");
+ exit(1);
+ }
+ }
+
+ close(devfd);
+ exit(0);
+}