]> git.alsa-project.org Git - alsa-tools.git/commitdiff
Add pcxhrloader
authorTakashi Iwai <tiwai@suse.de>
Tue, 21 Dec 2004 13:42:07 +0000 (13:42 +0000)
committerTakashi Iwai <tiwai@suse.de>
Tue, 21 Dec 2004 13:42:07 +0000 (13:42 +0000)
Added pcxhrloader, the firmware loader for Digigram PCXHR driver.

Makefile
pcxhrloader/Makefile.am [new file with mode: 0644]
pcxhrloader/README [new file with mode: 0644]
pcxhrloader/configure.in [new file with mode: 0644]
pcxhrloader/pcxhrloader.c [new file with mode: 0644]

index 8416c63d4625572252d069230597f79b431fe2ee..44390a94530e92cdbce7744dd3c926f10c2340ef 100644 (file)
--- 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 (file)
index 0000000..1352f59
--- /dev/null
@@ -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 (file)
index 0000000..68dfce9
--- /dev/null
@@ -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
diff --git a/pcxhrloader/configure.in b/pcxhrloader/configure.in
new file mode 100644 (file)
index 0000000..0565dcf
--- /dev/null
@@ -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 (file)
index 0000000..a5ef079
--- /dev/null
@@ -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;
+}