Add pcxhrloader

Added pcxhrloader, the firmware loader for Digigram PCXHR driver.
This commit is contained in:
Takashi Iwai 2004-12-21 13:42:07 +00:00
parent a41170e153
commit ba2978aa9f
5 changed files with 372 additions and 1 deletions

View file

@ -1,7 +1,7 @@
VERSION = 1.0.7
TOP = .
SUBDIRS = ac3dec as10k1 envy24control hdsploader hdspconf hdspmixer \
mixartloader rmedigicontrol sb16_csp seq sscape_ctl us428control \
mixartloader pcxhrloader rmedigicontrol sb16_csp seq sscape_ctl us428control \
usx2yloader vxloader
all:

18
pcxhrloader/Makefile.am Normal file
View file

@ -0,0 +1,18 @@
# # Process this file with automake to produce Makefile.in.
AUTOMAKE_OPTIONS = 1.3 foreign
MYNAME = pcxhrloader
AM_CFLAGS = -DDATAPATH=\"$(datadir)/alsa/firmware/$(MYNAME)\"
bin_PROGRAMS = pcxhrloader
pcxhrloader_SOURCES = pcxhrloader.c
EXTRA_DIST = depcomp
alsa-dist: distdir
@rm -rf ../distdir/$(MYNAME)
@mkdir -p ../distdir/$(MYNAME)
@cp -RLpv $(distdir)/* ../distdir/$(MYNAME)
@rm -rf $(distdir)

54
pcxhrloader/README Normal file
View file

@ -0,0 +1,54 @@
pcxhrloader - Firmware loader for Digigram pcxhr compatible soundcards
Digigram <alsa@digigram.com>
GENERAL
=======
pcxhrloader is a helper program to load the firmware binaries
onto Digigram's pcxhr compatible board sound drivers.
The following modules require this program:
snd-pcxhr
These drivers don't work properly at all until the certain firmwares
are loaded, i.e. no PCM nor mixer devices will appear.
USAGE
=====
When pcxhrloader is invoked without options, it will probe all existing
soundcards until a valid pcxhr-driver is found. If a valid pcxhr-driver is
found, pcxhrloader reads the board type from the driver. The corresponding
firmware binaries are then read and transferred to the driver.
Finally, pcxhrloader initializes the PCM and the mixer devices on the
driver for making the soundcard full functional.
Instead of auto-probing, you can specify the card number or the hwdep
device name via -c and -D options, respectively.
% pcxhrloader -c 1
% pcxhrloader -D hw:0
For loading the firmware automatically after the module is loaded, use
the post-install command. For example, add the following entry to
/etc/modules.conf for pcxhr driver:
post-install snd-pcxhr /usr/bin/pcxhrloader
FILES
=====
The firmware binaries are installed on /usr/share/alsa/firmware/pcxhrloader
(or /usr/local/share/alsa/firmware/pcxhrloader, depending to the prefix
option of configure). There will be *.conf files, which define the dsp image
files for each different card type.
COPYRIGHT
=========
Copyright (c) 2004 Digigram SA <alsa@digigram.com>
Distributable under GPL.
The firmware files included in alsa-firmware package are copyright
by Digigram SA

11
pcxhrloader/configure.in Normal file
View file

@ -0,0 +1,11 @@
AC_INIT(pcxhrloader.c)
AM_INIT_AUTOMAKE(pcxhrloader, 1.0)
AC_PROG_CC
AC_PROG_INSTALL
AC_HEADER_STDC
AM_PATH_ALSA(1.0.0)
CFLAGS="$CFLAGS $ALSA_CFLAGS"
LDFLAGS="$LDFLAGS $ALSA_LIBS"
AC_OUTPUT(Makefile)

288
pcxhrloader/pcxhrloader.c Normal file
View file

@ -0,0 +1,288 @@
/*
* Firmware Loaderfor Digigram pcxhr compatible soundcards
*
* Copyright (c) 2004 by Digigram <alsa@digigram.com>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <alsa/asoundlib.h>
#define PROGNAME "pcxhrloader"
/* max. number of cards (shouldn't be in the public header?) */
#define SND_CARDS 8
static int verbose = 0;
static void usage(void)
{
printf("Boot loader for Digigram pcxhr compatible cards\n");
printf("version %s\n", VERSION);
printf("usage: pcxhrloader [-c card] [-D device]\n");
}
static void error(const char *fmt, ...)
{
if (verbose) {
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s: ", PROGNAME);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
}
/*
* parse the index file and get the file to read from the key
*/
#define MAX_PATH 128
static int get_file_name(const char *key, unsigned int idx, char *fname)
{
FILE *fp;
char buf[128];
char temp[32], *p;
int len;
snprintf(buf, sizeof(buf), "%s/%s.conf", DATAPATH, key);
if ((fp = fopen(buf, "r")) == NULL) {
error("cannot open the index file %s\n", buf);
return -ENODEV;
}
sprintf(temp, "dsp%d", idx);
len = strlen(temp);
while (fgets(buf, sizeof(buf), fp)) {
if (strncmp(buf, temp, len))
continue;
for (p = buf + len; *p && isspace(*p); p++)
;
if (*p == '/') {
strncpy(fname, p, MAX_PATH);
} else {
snprintf(fname, MAX_PATH, "%s/%s", DATAPATH, p);
}
fname[MAX_PATH-1] = 0;
/* chop the last linefeed */
for (p = fname; *p && *p != '\n'; p++)
;
*p = 0;
fclose(fp);
return 0;
}
fclose(fp);
error("cannot find the file entry for %s\n", temp);
return -ENODEV;
}
/*
* read and transfer the firmware binary
*/
static int load_firmware(snd_hwdep_t *hw, const char *id, unsigned int idx)
{
int err;
char fname[MAX_PATH];
snd_hwdep_dsp_image_t *dsp;
struct stat st;
int fd, length;
unsigned char *imgbuf;
if (get_file_name(id, idx, fname) < 0)
return -EINVAL;
snd_hwdep_dsp_image_alloca(&dsp);
snd_hwdep_dsp_image_set_name(dsp, fname);
if (stat(fname, &st) < 0) {
error("cannot call stat %s\n", fname);
return -ENODEV;
}
length = st.st_size;
if (length == 0) {
error("zero file size %s\n", fname);
return -EINVAL;
}
imgbuf = malloc(st.st_size);
if (! imgbuf) {
error("cannot malloc %d bytes\n", length);
return -ENOMEM;
}
snd_hwdep_dsp_image_set_length(dsp, length);
snd_hwdep_dsp_image_set_image(dsp, imgbuf);
fd = open(fname, O_RDONLY);
if (fd < 0) {
error("cannot open %s\n", fname);
return -ENODEV;
}
if (read(fd, imgbuf, length) != length) {
error("cannot read %d bytes from %s\n", length, fname);
close(fd);
return -EINVAL;
}
close(fd);
snd_hwdep_dsp_image_set_index(dsp, idx);
err = snd_hwdep_dsp_load(hw, dsp);
if (err < 0)
error("error in loading %s\n", fname);
printf("%s loaded (%d bytes).\n",fname,length);
return err;
}
/*
* check the name id of the given hwdep handle
*/
static int check_hwinfo(snd_hwdep_t *hw, const char *id)
{
snd_hwdep_info_t *info;
int err;
snd_hwdep_info_alloca(&info);
if ((err = snd_hwdep_info(hw, info)) < 0)
return err;
if (strcmp(snd_hwdep_info_get_id(info), id))
return -ENODEV;
return 0; /* ok */
}
/*
* load the firmware binaries
*/
static int pcxhr_boot(const char *devname)
{
snd_hwdep_t *hw;
const char *id;
int err;
unsigned int idx, dsps, loaded;
snd_hwdep_dsp_status_t *stat;
if ((err = snd_hwdep_open(&hw, devname, O_RDWR)) < 0) {
error("cannot open hwdep %s\n", devname);
return err;
}
/* check hwdep ID string */
if (check_hwinfo(hw, "pcxhr loader") < 0) {
error("invalid hwdep ID string %s\n", devname);
snd_hwdep_close(hw);
return -ENODEV;
}
snd_hwdep_dsp_status_alloca(&stat);
/* get the current status (number of files to load = 5)*/
if ((err = snd_hwdep_dsp_status(hw, stat)) < 0) {
printf("cannot get version for %s\n", devname);
snd_hwdep_close(hw);
return err;
}
if (snd_hwdep_dsp_status_get_chip_ready(stat))
{
printf("nothing to do for device %s.\n", devname);
return 0; /* already loaded */
}
/* get "pcxhr" string */
id = snd_hwdep_dsp_status_get_id(stat);
dsps = snd_hwdep_dsp_status_get_num_dsps(stat);
loaded = snd_hwdep_dsp_status_get_dsp_loaded(stat);
for (idx = 0; idx < dsps; idx++) {
if (loaded & (1 << idx))
{
printf("%d already loaded (loaded = %d).\n", idx, loaded);
continue;
}
if ((err = load_firmware(hw, id, idx)) < 0) {
snd_hwdep_close(hw);
return err;
}
}
snd_hwdep_close(hw);
return 0;
}
int main(int argc, char **argv)
{
int c;
int card = -1;
char *device_name = NULL;
char name[64];
while ((c = getopt(argc, argv, "c:D:")) != -1) {
switch (c) {
case 'c':
card = atoi(optarg);
break;
case 'D':
device_name = optarg;
break;
default:
usage();
return 1;
}
}
if (device_name) {
verbose = 1;
return pcxhr_boot(device_name) != 0;
}
if (card >= 0) {
sprintf(name, "hw:%d", card);
verbose = 1;
return pcxhr_boot(name) != 0;
}
/* probe the all cards */
for (c = 0; c < SND_CARDS; c++) {
sprintf(name, "hw:%d", c);
if (! pcxhr_boot(name))
card = c;
}
if (card < 0) {
fprintf(stderr, PROGNAME ": no pcxhr-compatible card found\n");
return 1;
}
return 0;
}