diff options
| -rw-r--r-- | include/sound/sb16_csp.h | 14 | ||||
| -rw-r--r-- | sound/isa/Kconfig | 1 | ||||
| -rw-r--r-- | sound/isa/sb/sb16_csp.c | 61 |
3 files changed, 68 insertions, 8 deletions
diff --git a/include/sound/sb16_csp.h b/include/sound/sb16_csp.h index caf6fe21514d..736eac71d053 100644 --- a/include/sound/sb16_csp.h +++ b/include/sound/sb16_csp.h | |||
| @@ -114,9 +114,21 @@ struct snd_sb_csp_info { | |||
| 114 | #ifdef __KERNEL__ | 114 | #ifdef __KERNEL__ |
| 115 | #include "sb.h" | 115 | #include "sb.h" |
| 116 | #include "hwdep.h" | 116 | #include "hwdep.h" |
| 117 | #include <linux/firmware.h> | ||
| 117 | 118 | ||
| 118 | struct snd_sb_csp; | 119 | struct snd_sb_csp; |
| 119 | 120 | ||
| 121 | /* indices for the known CSP programs */ | ||
| 122 | enum { | ||
| 123 | CSP_PROGRAM_MULAW, | ||
| 124 | CSP_PROGRAM_ALAW, | ||
| 125 | CSP_PROGRAM_ADPCM_INIT, | ||
| 126 | CSP_PROGRAM_ADPCM_PLAYBACK, | ||
| 127 | CSP_PROGRAM_ADPCM_CAPTURE, | ||
| 128 | |||
| 129 | CSP_PROGRAM_COUNT | ||
| 130 | }; | ||
| 131 | |||
| 120 | /* | 132 | /* |
| 121 | * CSP operators | 133 | * CSP operators |
| 122 | */ | 134 | */ |
| @@ -159,6 +171,8 @@ struct snd_sb_csp { | |||
| 159 | struct snd_kcontrol *qsound_space; | 171 | struct snd_kcontrol *qsound_space; |
| 160 | 172 | ||
| 161 | struct mutex access_mutex; /* locking */ | 173 | struct mutex access_mutex; /* locking */ |
| 174 | |||
| 175 | const struct firmware *csp_programs[CSP_PROGRAM_COUNT]; | ||
| 162 | }; | 176 | }; |
| 163 | 177 | ||
| 164 | int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep); | 178 | int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep); |
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 57371f1a441f..565ed2add38b 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
| @@ -358,6 +358,7 @@ config SND_SBAWE | |||
| 358 | config SND_SB16_CSP | 358 | config SND_SB16_CSP |
| 359 | bool "Sound Blaster 16/AWE CSP support" | 359 | bool "Sound Blaster 16/AWE CSP support" |
| 360 | depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) | 360 | depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) |
| 361 | select FW_LOADER | ||
| 361 | help | 362 | help |
| 362 | Say Y here to include support for the CSP core. This special | 363 | Say Y here to include support for the CSP core. This special |
| 363 | coprocessor can do variable tasks like various compression and | 364 | coprocessor can do variable tasks like various compression and |
diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index fcd638090a9e..3d9d7e0107ca 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c | |||
| @@ -161,10 +161,13 @@ int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep) | |||
| 161 | */ | 161 | */ |
| 162 | static void snd_sb_csp_free(struct snd_hwdep *hwdep) | 162 | static void snd_sb_csp_free(struct snd_hwdep *hwdep) |
| 163 | { | 163 | { |
| 164 | int i; | ||
| 164 | struct snd_sb_csp *p = hwdep->private_data; | 165 | struct snd_sb_csp *p = hwdep->private_data; |
| 165 | if (p) { | 166 | if (p) { |
| 166 | if (p->running & SNDRV_SB_CSP_ST_RUNNING) | 167 | if (p->running & SNDRV_SB_CSP_ST_RUNNING) |
| 167 | snd_sb_csp_stop(p); | 168 | snd_sb_csp_stop(p); |
| 169 | for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i) | ||
| 170 | release_firmware(p->csp_programs[i]); | ||
| 168 | kfree(p); | 171 | kfree(p); |
| 169 | } | 172 | } |
| 170 | } | 173 | } |
| @@ -687,8 +690,50 @@ static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __use | |||
| 687 | return err; | 690 | return err; |
| 688 | } | 691 | } |
| 689 | 692 | ||
| 693 | #define FIRMWARE_IN_THE_KERNEL | ||
| 694 | |||
| 695 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
| 690 | #include "sb16_csp_codecs.h" | 696 | #include "sb16_csp_codecs.h" |
| 691 | 697 | ||
| 698 | static const struct firmware snd_sb_csp_static_programs[] = { | ||
| 699 | { .data = mulaw_main, .size = sizeof mulaw_main }, | ||
| 700 | { .data = alaw_main, .size = sizeof alaw_main }, | ||
| 701 | { .data = ima_adpcm_init, .size = sizeof ima_adpcm_init }, | ||
| 702 | { .data = ima_adpcm_playback, .size = sizeof ima_adpcm_playback }, | ||
| 703 | { .data = ima_adpcm_capture, .size = sizeof ima_adpcm_capture }, | ||
| 704 | }; | ||
| 705 | #endif | ||
| 706 | |||
| 707 | static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags) | ||
| 708 | { | ||
| 709 | static const char *const names[] = { | ||
| 710 | "sb16/mulaw_main.csp", | ||
| 711 | "sb16/alaw_main.csp", | ||
| 712 | "sb16/ima_adpcm_init.csp", | ||
| 713 | "sb16/ima_adpcm_playback.csp", | ||
| 714 | "sb16/ima_adpcm_capture.csp", | ||
| 715 | }; | ||
| 716 | const struct firmware *program; | ||
| 717 | int err; | ||
| 718 | |||
| 719 | BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT); | ||
| 720 | program = p->csp_programs[index]; | ||
| 721 | if (!program) { | ||
| 722 | err = request_firmware(&program, names[index], | ||
| 723 | p->chip->card->dev); | ||
| 724 | if (err >= 0) | ||
| 725 | p->csp_programs[index] = program; | ||
| 726 | else { | ||
| 727 | #ifdef FIRMWARE_IN_THE_KERNEL | ||
| 728 | program = &snd_sb_csp_static_programs[index]; | ||
| 729 | #else | ||
| 730 | return err; | ||
| 731 | #endif | ||
| 732 | } | ||
| 733 | } | ||
| 734 | return snd_sb_csp_load(p, program->data, program->size, flags); | ||
| 735 | } | ||
| 736 | |||
| 692 | /* | 737 | /* |
| 693 | * autoload hardware codec if necessary | 738 | * autoload hardware codec if necessary |
| 694 | * return 0 if CSP is loaded and ready to run (p->running != 0) | 739 | * return 0 if CSP is loaded and ready to run (p->running != 0) |
| @@ -708,27 +753,27 @@ static int snd_sb_csp_autoload(struct snd_sb_csp * p, int pcm_sfmt, int play_rec | |||
| 708 | } else { | 753 | } else { |
| 709 | switch (pcm_sfmt) { | 754 | switch (pcm_sfmt) { |
| 710 | case SNDRV_PCM_FORMAT_MU_LAW: | 755 | case SNDRV_PCM_FORMAT_MU_LAW: |
| 711 | err = snd_sb_csp_load(p, &mulaw_main[0], sizeof(mulaw_main), 0); | 756 | err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0); |
| 712 | p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW; | 757 | p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW; |
| 713 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; | 758 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; |
| 714 | break; | 759 | break; |
| 715 | case SNDRV_PCM_FORMAT_A_LAW: | 760 | case SNDRV_PCM_FORMAT_A_LAW: |
| 716 | err = snd_sb_csp_load(p, &alaw_main[0], sizeof(alaw_main), 0); | 761 | err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0); |
| 717 | p->acc_format = SNDRV_PCM_FMTBIT_A_LAW; | 762 | p->acc_format = SNDRV_PCM_FMTBIT_A_LAW; |
| 718 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; | 763 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE; |
| 719 | break; | 764 | break; |
| 720 | case SNDRV_PCM_FORMAT_IMA_ADPCM: | 765 | case SNDRV_PCM_FORMAT_IMA_ADPCM: |
| 721 | err = snd_sb_csp_load(p, &ima_adpcm_init[0], sizeof(ima_adpcm_init), | 766 | err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT, |
| 722 | SNDRV_SB_CSP_LOAD_INITBLOCK); | 767 | SNDRV_SB_CSP_LOAD_INITBLOCK); |
| 723 | if (err) | 768 | if (err) |
| 724 | break; | 769 | break; |
| 725 | if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) { | 770 | if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) { |
| 726 | err = snd_sb_csp_load(p, &ima_adpcm_playback[0], | 771 | err = snd_sb_csp_firmware_load |
| 727 | sizeof(ima_adpcm_playback), 0); | 772 | (p, CSP_PROGRAM_ADPCM_PLAYBACK, 0); |
| 728 | p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE; | 773 | p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE; |
| 729 | } else { | 774 | } else { |
| 730 | err = snd_sb_csp_load(p, &ima_adpcm_capture[0], | 775 | err = snd_sb_csp_firmware_load |
| 731 | sizeof(ima_adpcm_capture), 0); | 776 | (p, CSP_PROGRAM_ADPCM_CAPTURE, 0); |
| 732 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ; | 777 | p->mode = SNDRV_SB_CSP_MODE_DSP_READ; |
| 733 | } | 778 | } |
| 734 | p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM; | 779 | p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM; |
