/* * scmctrl.c * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: scmctrl.c,v 1.1 2004/03/11 03:59:31 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include #include #include #include #include #include #include #include #include "cdev.h" #define bool char #define MIN(a,b) ((a > b) ? b : a) static const char opts[] = "vd:f:"; static int fd; static bool verbose = 0; static int dev_ind = 0; static int port_ind = -1; static char *ul_file; static char dev_file[128]; #define IMG_HEADER_LEN 33 /* speed -> speed code mappings and speed value validation */ struct speed_map_node { float speed; unsigned char code; }; static struct speed_map_node speed_map[] = { { 2.4, SP_24 }, { 4.8, SP_48 }, { 7.2, SP_72 }, { 9.6, SP_96 }, { 12.0, SP_120 }, { 14.4, SP_144 }, { 16.8, SP_168 }, { 19.2, SP_192 }, { 21.6, SP_216 }, { 24.0, SP_240 }, { 26.4, SP_264 }, { 28.8, SP_288 }, { 31.2, SP_312 }, { 33.6, SP_336 }, { 0.0, 0 } }; /* Prototypes for functions later in the code */ int upload_cpucode(); int set_speed(); /* Print information on how to use the program */ void usage() { fprintf(stderr, "Usage: scmctrl [options] command\n"); fprintf(stderr, "Refer to scmctrl(8) for details\n"); } /* Handle a SIGINT during an upload */ void abort_upload(int sig) { printf("\nUpload Aborted\n"); ioctl(fd, SCMIOC_ABORT); exit(-1); } /* Process the options and issue commands to the driver */ int main(int argc, char **argv) { int c; char *cmd; /* get command modifiers */ while(1) { c = getopt(argc, argv, opts); if(c == -1) break; switch(c) { case 'v': verbose = !verbose; break; case 'd': dev_ind = atoi(optarg); break; case 'p': port_ind = atoi(optarg); break; case 'f': ul_file = optarg; break; case ':': usage(); return -1; case '?': usage(); return -1; } } /* Open the control device */ sprintf(dev_file, "/dev/scm%d", dev_ind); fd = open(dev_file, O_RDWR, 0); if(fd < 0) { fprintf(stderr, "Error opening %s: %s\n", dev_file, strerror(errno)); return -errno; } /* Get the command */ if(optind < argc) cmd = argv[optind]; else { usage(); return -1; } /* Set the modem connect speeds of one or more ports */ if(!strcasecmp(cmd, "speed")) { c = set_speed(argc, argv); if(c) fprintf(stderr, "speed: %s\n", strerror(errno)); return -errno; } /* Reset the adapter to uninitialized */ else if(!strcasecmp(cmd, "reset")) { c = ioctl(fd, SCMIOC_RESET); if(c) fprintf(stderr, "reset: %s\n", strerror(errno)); return -errno; } /* Print the ROM or OS version information */ else if(!strcasecmp(cmd, "version")) { struct ioc_version ver; c = ioctl(fd, SCMIOC_OSVER, &ver); if(c) { fprintf(stderr, "version: %s\n", strerror(errno)); return -errno; } else if(verbose) printf("Version: %f, Release Date: %02d%02d-%02d-%02d\n", (float) ver.version / 100, ver.century, ver.year, ver.month, ver.day); return (int) ver.version; } /* Load the OS software */ else if(!strcasecmp(cmd, "load")) { c = upload_cpucode(); if(c) fprintf(stderr, "load: %s\n", strerror(errno)); return -errno; } /* Initialize the adapter after upload */ else if(!strcasecmp(cmd, "start")) { c = ioctl(fd, SCMIOC_OSSTART); if(c) fprintf(stderr, "start: %s\n", strerror(errno)); return -errno; } /* Stop a running board */ else if(!strcasecmp(cmd, "stop")) { c = ioctl(fd, SCMIOC_OSSTOP); if(c) fprintf(stderr, "stop: %s\n", strerror(errno)); return -errno; } else { fprintf(stderr, "error: Unknown command \"%s\"\n", cmd); usage(); return -1; } } /* Upload a OS image to the adapter */ int upload_cpucode() { int c, t = 0, ot = 0, g, bs; int i_fd = 0; char *i_buf; char sver[9]; char h_buf[IMG_HEADER_LEN + 1]; int i_size, i_version, i_magic; int fail = 0, nr_fail = 0; /* Install the abort handler */ signal(SIGINT, abort_upload); if(ul_file == NULL) { i_fd = dup2(fileno(stdin), i_fd); if(i_fd < 0) { fprintf(stderr, "load: error reading from stdin: %s\n", strerror(errno)); return -errno; } } else { /* Open the image file */ i_fd = open(ul_file, O_RDONLY, 0); if(i_fd < 0) { fprintf(stderr, "load: error opening image %s: %s\n", ul_file, strerror(errno)); return -errno; } } /* Get the image size */ read(i_fd, h_buf, IMG_HEADER_LEN); sscanf(h_buf, "%x %x %x", &i_magic, &i_size, &i_version); if(i_magic != 0x12345678) { fprintf(stderr, "load: invalid image file format\n"); return -1; } sprintf(sver, "%d.%d.%d", (i_version & 0x00ff0000) >> 16, (i_version & 0x0000ff00) >> 8, i_version & 0x000000ff); /* Tell the driver the type and size of the image */ c = ioctl(fd, SCMIOC_OSLOAD, i_size); if(c) { fprintf(stderr, "load: Driver refused code upload (already loaded?)\n"); return c; } /* dump the image to the driver */ i_buf = malloc(BLK_SIZE); if(!i_buf) { fprintf(stderr, "load: no memory for operation\n"); return -ENOMEM; } /* Prep the output display */ if(verbose) { fflush(stdout); setbuf(stdout, NULL); printf("Loading %d bytes [ ]\r", i_size); printf("Loading %d bytes [", i_size); } bs = i_size / 32; /* Load the blocks */ while(i_size > 0) { c = read(i_fd, i_buf, MIN(BLK_SIZE, i_size)); g = write(fd, i_buf, c); if(g < 0) { nr_fail++; fail = 1; } i_size -= c; t += c; if(verbose && t / bs > ot) { ot = t / bs; if(!nr_fail) { if(ot > 1) printf("\b->"); else printf(">"); } else { fail = 0; if(ot > 1) printf("\bx>"); else printf(">"); } } } /* Close the display output */ if(verbose) { if(nr_fail) printf("\b-] Done with errors.\n"); else printf("\b-] Done.\n"); } free(i_buf); return nr_fail ? -1 : 0; } /* Set the modems speed */ int set_speed(int argc, char **argv) { float max_sp = 0.0, min_sp = 2.4; unsigned char max_c = 0, min_c = 0; struct ioc_speed sp; int i; if(optind + 1 < argc) max_sp = atof(argv[optind + 1]); if(optind + 2 < argc) min_sp = atof(argv[optind + 2]); if(optind + 3 < argc) { fprintf(stderr, "speed: Too many arguments (%d > 2 max)\n", argc - (optind + 2)); return -1; } if(max_sp == 0.0) { fprintf(stderr, "speed: No speed indicated\n"); return -1; } /* Lookup the speed */ for(i = 0 ; speed_map[i].speed != 0.0 ; i++) { if(speed_map[i].speed == max_sp) max_c = speed_map[i].code; if(speed_map[i].speed == min_sp) min_c = speed_map[i].code; } if(max_c == 0) { fprintf(stderr, "speed: Invalid maximum speed indicated: %s\n", argv[optind+1]); return -1; } if(min_c == 0) { fprintf(stderr, "speed: Invalid minimum speed indicated: %s\n", argv[optind+2]); return -1; } sp.port = port_ind; sp.max_speed = max_c; sp.min_speed = min_c; return ioctl(fd, SCMIOC_SPEED, &sp); }