--- /dev/null
+AC_INIT(sscape_ctl.c)
+AM_INIT_AUTOMAKE(sscape_ctl, 0.1.0)
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_HEADER_STDC
+AM_PATH_ALSA(0.9.0)
+
+dnl kernel header files
+AC_MSG_CHECKING(for kernel header files)
+AC_ARG_WITH(kernel,
+ [ --with-kernel=ver specify kernel version (for example 2.5.5-pre1)],
+ [kerneldir="$withval"], [kerneldir=""])
+if test "$kerneldir" != "" -a -r "/lib/modules/$kerneldir/build/include/sound"; then
+ kerneldir="/lib/modules/$kerneldir/build/include"
+ AC_MSG_RESULT($kerneldir)
+else
+ if test -z "$kerneldir"; then
+ AC_MSG_RESULT("not specified")
+ else
+ AC_MSG_RESULT("directory /lib/modules/$kerneldir/build/include/sound not found")
+ fi
+ kerneldir=""
+fi
+
+dnl path for sound/asound.h
+AC_MSG_CHECKING(for directory with ALSA kernel headers)
+AC_ARG_WITH(soundbase,
+ [ --with-soundbase=dir specify base directory with kernel sound headers (optional)],
+ [soundbasedir="$withval"], [soundbasedir="$kerneldir"])
+if test "$soundbasedir" != "" -a -r "$soundbasedir/sound" ; then
+ ALSA_CFLAGS="$ALSA_CFLAGS -I$soundbasedir"
+ CFLAGS="$CFLAGS -I$soundbasedir"
+ AC_MSG_RESULT($ALSA_CFLAGS)
+else
+ if test "x$prefix" != xNONE; then
+ aprefix=$prefix
+ else
+ aprefix=$ac_default_prefix
+ fi
+ if test -z "$soundbasedir" -a -r "$aprefix/include/sound"; then
+ ALSA_CFLAGS="$ALSA_CFLAGS -I$aprefix/include"
+ CFLAGS="$CFLAGS -I$aprefix/include"
+ AC_MSG_RESULT($ALSA_CFLAGS)
+ else
+ AC_MSG_RESULT("not specified - using C compilator defaults")
+ fi
+fi
+
+CFLAGS="$CFLAGS $ALSA_FLAGS"
+LDFLAGS="$LDFLAGS $ALSA_LIBS"
+
+AC_OUTPUT(Makefile)
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+
+#include <sound/sscape_ioctl.h>
+#include <alsa/asoundlib.h>
+
+
+const char default_dir[] = "/sndscape";
+const char scope[] = "scope.cod";
+
+
+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->code));
+ 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' },
+ { NULL, 0, NULL, '\0' }
+};
+
+static const char option[] = "c:d:";
+
+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;
+
+ default:
+ fprintf(stderr, "Unknown option \'%c\'\n", c);
+ break;
+ } /* switch */
+ } /* while */
+
+ ret = EXIT_FAILURE;
+ sprintf(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;
+
+ 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;
+}
+