*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
MODULE_DESCRIPTION("ALSA driver for SB16 Creative Signal Processor");
MODULE_LICENSE("GPL");
+#ifndef CONFIG_SND_SB16_CSP_FIRMWARE_IN_KERNEL
+MODULE_FIRMWARE("sb16/mulaw_main.csp");
+MODULE_FIRMWARE("sb16/alaw_main.csp");
+MODULE_FIRMWARE("sb16/ima_adpcm_init.csp");
+MODULE_FIRMWARE("sb16/ima_adpcm_playback.csp");
+MODULE_FIRMWARE("sb16/ima_adpcm_capture.csp");
+#endif
#ifdef SNDRV_LITTLE_ENDIAN
#define CSP_HDR_VALUE(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep)
{
struct snd_sb_csp *p;
- int version, err;
+ int uninitialized_var(version);
+ int err;
struct snd_hwdep *hw;
if (rhwdep)
*/
static void snd_sb_csp_free(struct snd_hwdep *hwdep)
{
+#ifndef CONFIG_SND_SB16_CSP_FIRMWARE_IN_KERNEL
+ int i;
+#endif
struct snd_sb_csp *p = hwdep->private_data;
if (p) {
if (p->running & SNDRV_SB_CSP_ST_RUNNING)
snd_sb_csp_stop(p);
+#ifndef CONFIG_SND_SB16_CSP_FIRMWARE_IN_KERNEL
+ for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i)
+ release_firmware(p->csp_programs[i]);
+#endif
kfree(p);
}
}
return err;
}
+#ifdef CONFIG_SND_SB16_CSP_FIRMWARE_IN_KERNEL
#include "sb16_csp_codecs.h"
+static const struct firmware snd_sb_csp_static_programs[] = {
+ { .data = mulaw_main, .size = sizeof mulaw_main },
+ { .data = alaw_main, .size = sizeof alaw_main },
+ { .data = ima_adpcm_init, .size = sizeof ima_adpcm_init },
+ { .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback },
+ { .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture },
+};
+#endif
+
+static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)
+{
+ static const char *const names[] = {
+ "sb16/mulaw_main.csp",
+ "sb16/alaw_main.csp",
+ "sb16/ima_adpcm_init.csp",
+ "sb16/ima_adpcm_playback.csp",
+ "sb16/ima_adpcm_capture.csp",
+ };
+ const struct firmware *program;
+
+ BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT);
+ program = p->csp_programs[index];
+ if (!program) {
+#ifdef CONFIG_SND_SB16_CSP_FIRMWARE_IN_KERNEL
+ program = &snd_sb_csp_static_programs[index];
+#else
+ int err = request_firmware(&program, names[index],
+ p->chip->card->dev);
+ if (err < 0)
+ return err;
+#endif
+ p->csp_programs[index] = program;
+ }
+ return snd_sb_csp_load(p, program->data, program->size, flags);
+}
+
/*
* autoload hardware codec if necessary
* return 0 if CSP is loaded and ready to run (p->running != 0)
} else {
switch (pcm_sfmt) {
case SNDRV_PCM_FORMAT_MU_LAW:
- err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0);
+ err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0);
p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
break;
case SNDRV_PCM_FORMAT_A_LAW:
- err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0);
+ err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0);
p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
break;
case SNDRV_PCM_FORMAT_IMA_ADPCM:
- err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init),
- SNDRV_SB_CSP_LOAD_INITBLOCK);
+ err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT,
+ SNDRV_SB_CSP_LOAD_INITBLOCK);
if (err)
break;
if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {
- err = snd_sb_csp_load(p, &ima_adpcm_playback[0],
- sizeof(ima_adpcm_playback), 0);
+ err = snd_sb_csp_firmware_load
+ (p, CSP_PROGRAM_ADPCM_PLAYBACK, 0);
p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;
} else {
- err = snd_sb_csp_load(p, &ima_adpcm_capture[0],
- sizeof(ima_adpcm_capture), 0);
+ err = snd_sb_csp_firmware_load
+ (p, CSP_PROGRAM_ADPCM_CAPTURE, 0);
p->mode = SNDRV_SB_CSP_MODE_DSP_READ;
}
p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;
* QSound mixer control for PCM
*/
-static int snd_sb_qsound_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_sb_qsound_switch_info snd_ctl_boolean_mono_info
static int snd_sb_qsound_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{