/* * ALSA SoundScape control utility * * Copyright (c) 2003 by Chris Rankin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include const char default_dir[] = "/sndscape"; const char scope[] = "scope.cod"; unsigned char _microcode[SSCAPE_MICROCODE_SIZE]; static void show_usage(void) { printf("sscape_ctl: [--card card number]\n" " [--directory firmware directory]\n" "sscape_ctl: --help\n" "sscape_ctl: --version\n"); } static void show_version(void) { printf("ALSA SoundScape control utility: v" VERSION "\n"); } void safe_close(int fd) { int err; while (((err = close(fd)) != 0) && (errno == EINTR)) {} } size_t get_directory(const char *dir, char *buffer, size_t bufsize) { size_t len; len = snprintf(buffer, bufsize, "%s/", dir); if (len >= bufsize) return 0; if ((len > 1) && (buffer[len - 1] == '/') && (buffer[len - 2] == '/')) { buffer[--len] = '\0'; } return len; } size_t get_bootfile(const char *filename, char *buffer, size_t bufsize) { size_t len = snprintf(buffer, bufsize, "%s", filename); if (len >= bufsize) return 0; return len; } size_t get_mcodefile(unsigned version, char *buffer, size_t bufsize) { static const char sndscape[] = "sndscape.co%u"; size_t len = snprintf(buffer, bufsize, sndscape, version); if (len >= bufsize) return 0; return len; } int load_bootblock(const char *fname, struct sscape_bootblock *boot) { int err; int fd; printf("Bootblock: %s\n", fname); err = fd = open(fname, O_RDONLY); if (err >= 0) { int save_errno; err = read(fd, boot->code, sizeof(boot->code)); if (err >= 0) { printf("Bootblock: read %d bytes\n", err); err = 0; } save_errno = errno; safe_close(fd); errno = save_errno; } return err; } int load_microcode(const char *fname, struct sscape_microcode *microcode) { int err; int fd; printf("Microcode: %s\n", fname); err = fd = open(fname, O_RDONLY); if (err >= 0) { int save_errno; err = read(fd, microcode->code, sizeof(_microcode)); if (err >= 0) { printf("Microcode: read %d bytes\n", err); err = 0; } save_errno = errno; safe_close(fd); errno = save_errno; } return err; } static const struct option long_option[] = { { "card", 1, NULL, 'c' }, { "directory", 1, NULL, 'd' }, { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'v' }, { NULL, 0, NULL, '\0' } }; static const char option[] = "c:d:hv"; int main(int argc, char *argv[]) { char devicename[32]; int ret, err; snd_hwdep_t *handle; const char *directory = default_dir; int card = 0; int oindex; int c; while ( (c = getopt_long(argc, argv, option, long_option, &oindex)) != EOF ) { switch(c) { case 'c': card = snd_card_get_index(optarg); if (card < 0 || card > 31) { fprintf(stderr, "Wrong -c argument '%s'\n", optarg); return EXIT_FAILURE; } break; case 'd': directory = optarg; break; case 'h': show_usage(); return EXIT_SUCCESS; case 'v': show_version(); return EXIT_SUCCESS; default: return EXIT_FAILURE; } /* switch */ } /* while */ ret = EXIT_FAILURE; snprintf(devicename, sizeof(devicename), "hw:%i,0", card); err = snd_hwdep_open(&handle, devicename, O_WRONLY); if (err < 0) { fprintf(stderr, "Error opening %s: %s\n", devicename, snd_strerror(err)); } else { char filename[FILENAME_MAX]; size_t len; struct sscape_bootblock boot; struct sscape_microcode microcode; microcode.code = _microcode; if ((len = get_directory(directory, filename, sizeof(filename))) == 0) { fprintf(stderr, "Invalid directory - pathname too long\n"); } else if (get_bootfile(scope, filename + len, sizeof(filename) - len) == 0) { fprintf(stderr, "Invalid filename - full pathname too long\n"); } else if (load_bootblock(filename, &boot) < 0) { fprintf(stderr, "Failed to load file [%s]: %s\n", filename, strerror(errno)); } else if (snd_hwdep_ioctl(handle, SND_SSCAPE_LOAD_BOOTB, &boot) < 0) { fprintf(stderr, "IOCTL error: %s\n", strerror(errno)); } else if (get_mcodefile(boot.version & 0x0f, filename + len, sizeof(filename) - len) == 0) { fprintf(stderr, "Invalid filename - full pathname too long\n"); } else if (load_microcode(filename, µcode) < 0) { fprintf(stderr, "Failed to load microcode [%s]\n", filename); } else if (snd_hwdep_ioctl(handle, SND_SSCAPE_LOAD_MCODE, µcode) < 0) { fprintf(stderr, "IOCTL error: %s\n", strerror(errno)); } else { printf("Microcode loaded.\n"); ret = EXIT_SUCCESS; } snd_hwdep_close(handle); } return ret; }