[ALSA] wavefront - Use standard firmware loader
Takashi Iwai [Tue, 21 Aug 2007 13:20:26 +0000 (15:20 +0200)]
Use the standard firmware loader for loading ICS2115 OS firmware file.
This is the last old bad guy that is still using sys_open() and sys_read()
calls, and now all should be gone.
The patch also adds the missing description of module options related
with wavefront_synth.c.
Due to this rewrite, user will have to copy or make symlink the firmware
file appropriately to the standard firmware path such as /lib/firmware.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>

Documentation/sound/alsa/ALSA-Configuration.txt
sound/isa/Kconfig
sound/isa/wavefront/wavefront_synth.c

index d766054..3df33ea 100644 (file)
@@ -1716,8 +1716,52 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     dma2            - DMA2 # for CS4232 PCM interface.
     isapnp          - ISA PnP detection - 0 = disable, 1 = enable (default)
 
+    The below are options for wavefront_synth features:
+    wf_raw         - Assume that we need to boot the OS (default:no)
+       If yes, then during driver loading, the state of the board is
+       ignored, and we reset the board and load the firmware anyway.
+    fx_raw         - Assume that the FX process needs help (default:yes)
+       If false, we'll leave the FX processor in whatever state it is
+       when the driver is loaded.  The default is to download the
+       microprogram and associated coefficients to set it up for
+       "default" operation, whatever that means.
+    debug_default   - Debug parameters for card initialization
+    wait_usecs     - How long to wait without sleeping, usecs
+                     (default:150)
+       This magic number seems to give pretty optimal throughput
+       based on my limited experimentation. 
+       If you want to play around with it and find a better value, be
+       my guest. Remember, the idea is to get a number that causes us
+       to just busy wait for as many WaveFront commands as possible,
+       without coming up with a number so large that we hog the whole
+       CPU. 
+       Specifically, with this number, out of about 134,000 status
+       waits, only about 250 result in a sleep. 
+    sleep_interval  - How long to sleep when waiting for reply
+                     (default: 100)
+    sleep_tries            - How many times to try sleeping during a wait
+                     (default: 50)
+    ospath         - Pathname to processed ICS2115 OS firmware
+                     (default:wavefront.os)
+       The path name of the ISC2115 OS firmware.  In the recent
+       version, it's handled via firmware loader framework, so it
+       must be installed in the proper path, typically,
+       /lib/firmware.
+    reset_time     - How long to wait for a reset to take effect
+                     (default:2)
+    ramcheck_time   - How many seconds to wait for the RAM test
+                     (default:20)
+    osrun_time     - How many seconds to wait for the ICS2115 OS
+                     (default:10)
+
     This module supports multiple cards and ISA PnP.
 
+    Note: the firmware file "wavefront.os" was located in the earlier
+          version in /etc.  Now it's loaded via firmware loader, and
+         must be in the proper firmware path, such as /lib/firmware.
+         Copy (or symlink) the file appropriately if you get an error
+         regarding firmware downloading after upgrading the kernel.
+
   Module snd-sonicvibes
   ---------------------
 
index ea5084a..6b6aa2c 100644 (file)
@@ -414,7 +414,7 @@ config SND_SSCAPE
 config SND_WAVEFRONT
        tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)"
        depends on SND
-       select FW_LOADER if !SND_WAVEFRONT_FIRMWARE_IN_KERNEL
+       select FW_LOADER
        select SND_OPL3_LIB
        select SND_MPU401_UART
        select SND_CS4231_LIB
@@ -430,8 +430,9 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL
        depends on SND_WAVEFRONT
        default y
        help
-         Say Y here to include the static firmware built in the kernel
-         for the Wavefront driver.  If you choose N here, you need to
-         install the firmware files from the alsa-firmware package.
+         Say Y here to include the static firmware for FX DSP built in
+         the kernel for the Wavefront driver.  If you choose N here,
+         you need to install the firmware files from the
+         alsa-firmware package.
 
 endmenu
index bacc51c..2da11e8 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/firmware.h>
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/snd_wavefront.h>
@@ -53,9 +54,8 @@ static int debug_default = 0;  /* you can set this to control debugging
 
 /* XXX this needs to be made firmware and hardware version dependent */
 
-static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed
-                                                   version of the WaveFront OS
-                                                */
+#define DEFAULT_OSPATH "wavefront.os"
+static char *ospath = DEFAULT_OSPATH; /* the firmware file name */
 
 static int wait_usecs = 150; /* This magic number seems to give pretty optimal
                                throughput based on my limited experimentation.
@@ -97,7 +97,7 @@ MODULE_PARM_DESC(sleep_interval, "how long to sleep when waiting for reply");
 module_param(sleep_tries, int, 0444);
 MODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait");
 module_param(ospath, charp, 0444);
-MODULE_PARM_DESC(ospath, "full pathname to processed ICS2115 OS firmware");
+MODULE_PARM_DESC(ospath, "pathname to processed ICS2115 OS firmware");
 module_param(reset_time, int, 0444);
 MODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect");
 module_param(ramcheck_time, int, 0444);
@@ -1938,111 +1938,75 @@ wavefront_reset_to_cleanliness (snd_wavefront_t *dev)
        return (1);
 }
 
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/unistd.h>
-#include <linux/syscalls.h>
-#include <asm/uaccess.h>
-
-
 static int __devinit
 wavefront_download_firmware (snd_wavefront_t *dev, char *path)
 
 {
-       unsigned char section[WF_SECTION_MAX];
-       signed char section_length; /* yes, just a char; max value is WF_SECTION_MAX */
+       unsigned char *buf;
+       int len, err;
        int section_cnt_downloaded = 0;
-       int fd;
-       int c;
-       int i;
-       mm_segment_t fs;
-
-       /* This tries to be a bit cleverer than the stuff Alan Cox did for
-          the generic sound firmware, in that it actually knows
-          something about the structure of the Motorola firmware. In
-          particular, it uses a version that has been stripped of the
-          20K of useless header information, and had section lengths
-          added, making it possible to load the entire OS without any
-          [kv]malloc() activity, since the longest entity we ever read is
-          42 bytes (well, WF_SECTION_MAX) long.
-       */
-
-       fs = get_fs();
-       set_fs (get_ds());
+       const struct firmware *firmware;
 
-       if ((fd = sys_open ((char __user *) path, 0, 0)) < 0) {
-               snd_printk ("Unable to load \"%s\".\n",
-                       path);
+       err = request_firmware(&firmware, path, dev->card->dev);
+       if (err < 0) {
+               snd_printk(KERN_ERR "firmware (%s) download failed!!!\n", path);
                return 1;
        }
 
-       while (1) {
-               int x;
-
-               if ((x = sys_read (fd, (char __user *) &section_length, sizeof (section_length))) !=
-                   sizeof (section_length)) {
-                       snd_printk ("firmware read error.\n");
-                       goto failure;
-               }
-
-               if (section_length == 0) {
+       len = 0;
+       buf = firmware->data;
+       for (;;) {
+               int section_length = *(signed char *)buf;
+               if (section_length == 0)
                        break;
-               }
-
                if (section_length < 0 || section_length > WF_SECTION_MAX) {
-                       snd_printk ("invalid firmware section length %d\n",
-                                   section_length);
+                       snd_printk(KERN_ERR
+                                  "invalid firmware section length %d\n",
+                                  section_length);
                        goto failure;
                }
+               buf++;
+               len++;
 
-               if (sys_read (fd, (char __user *) section, section_length) != section_length) {
-                       snd_printk ("firmware section "
-                               "read error.\n");
+               if (firmware->size < len + section_length) {
+                       snd_printk(KERN_ERR "firmware section read error.\n");
                        goto failure;
                }
 
                /* Send command */
-       
-               if (wavefront_write (dev, WFC_DOWNLOAD_OS)) {
+               if (wavefront_write(dev, WFC_DOWNLOAD_OS))
                        goto failure;
-               }
        
-               for (i = 0; i < section_length; i++) {
-                       if (wavefront_write (dev, section[i])) {
+               for (; section_length; section_length--) {
+                       if (wavefront_write(dev, *buf))
                                goto failure;
-                       }
+                       buf++;
+                       len++;
                }
        
                /* get ACK */
-       
-               if (wavefront_wait (dev, STAT_CAN_READ)) {
-
-                       if ((c = inb (dev->data_port)) != WF_ACK) {
-
-                               snd_printk ("download "
-                                           "of section #%d not "
-                                           "acknowledged, ack = 0x%x\n",
-                                           section_cnt_downloaded + 1, c);
-                               goto failure;
-               
-                       }
-
-               } else {
-                       snd_printk ("time out for firmware ACK.\n");
+               if (!wavefront_wait(dev, STAT_CAN_READ)) {
+                       snd_printk(KERN_ERR "time out for firmware ACK.\n");
+                       goto failure;
+               }
+               err = inb(dev->data_port);
+               if (err != WF_ACK) {
+                       snd_printk(KERN_ERR
+                                  "download of section #%d not "
+                                  "acknowledged, ack = 0x%x\n",
+                                  section_cnt_downloaded + 1, err);
                        goto failure;
                }
 
+               section_cnt_downloaded++;
        }
 
-       sys_close (fd);
-       set_fs (fs);
+       release_firmware(firmware);
        return 0;
 
  failure:
-       sys_close (fd);
-       set_fs (fs);
-       snd_printk ("firmware download failed!!!\n");
+       release_firmware(firmware);
+       snd_printk(KERN_ERR "firmware download failed!!!\n");
        return 1;
 }
 
@@ -2232,3 +2196,5 @@ snd_wavefront_detect (snd_wavefront_card_t *card)
 
        return 0;
 }
+
+MODULE_FIRMWARE(DEFAULT_OSPATH);