From ba2978aa9f9abb3bd6b0c49f1626645a35181d3e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 21 Dec 2004 13:42:07 +0000 Subject: [PATCH] Add pcxhrloader Added pcxhrloader, the firmware loader for Digigram PCXHR driver. --- Makefile | 2 +- pcxhrloader/Makefile.am | 18 +++ pcxhrloader/README | 54 +++++++ pcxhrloader/configure.in | 11 ++ pcxhrloader/pcxhrloader.c | 288 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 pcxhrloader/Makefile.am create mode 100644 pcxhrloader/README create mode 100644 pcxhrloader/configure.in create mode 100644 pcxhrloader/pcxhrloader.c diff --git a/Makefile b/Makefile index 8416c63..44390a9 100644 --- a/Makefile +++ b/Makefile @@ -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: diff --git a/pcxhrloader/Makefile.am b/pcxhrloader/Makefile.am new file mode 100644 index 0000000..1352f59 --- /dev/null +++ b/pcxhrloader/Makefile.am @@ -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) diff --git a/pcxhrloader/README b/pcxhrloader/README new file mode 100644 index 0000000..68dfce9 --- /dev/null +++ b/pcxhrloader/README @@ -0,0 +1,54 @@ + pcxhrloader - Firmware loader for Digigram pcxhr compatible soundcards + Digigram + + +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 +Distributable under GPL. + +The firmware files included in alsa-firmware package are copyright +by Digigram SA diff --git a/pcxhrloader/configure.in b/pcxhrloader/configure.in new file mode 100644 index 0000000..0565dcf --- /dev/null +++ b/pcxhrloader/configure.in @@ -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) diff --git a/pcxhrloader/pcxhrloader.c b/pcxhrloader/pcxhrloader.c new file mode 100644 index 0000000..a5ef079 --- /dev/null +++ b/pcxhrloader/pcxhrloader.c @@ -0,0 +1,288 @@ +/* + * Firmware Loaderfor Digigram pcxhr compatible soundcards + * + * Copyright (c) 2004 by Digigram + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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; +} -- 2.47.1