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