^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 1999 by Uros Bizjak <uros@kss-loka.si>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Takashi Iwai <tiwai@suse.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * SB16ASP/AWE32 CSP control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * CSP microcode loader:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * alsa-tools/sb16_csp/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <sound/control.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <sound/info.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <sound/sb16_csp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <sound/initval.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) MODULE_DESCRIPTION("ALSA driver for SB16 Creative Signal Processor");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) MODULE_FIRMWARE("sb16/mulaw_main.csp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) MODULE_FIRMWARE("sb16/alaw_main.csp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) MODULE_FIRMWARE("sb16/ima_adpcm_init.csp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) MODULE_FIRMWARE("sb16/ima_adpcm_playback.csp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) MODULE_FIRMWARE("sb16/ima_adpcm_capture.csp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #ifdef SNDRV_LITTLE_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define CSP_HDR_VALUE(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define CSP_HDR_VALUE(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define RIFF_HEADER CSP_HDR_VALUE('R', 'I', 'F', 'F')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define CSP__HEADER CSP_HDR_VALUE('C', 'S', 'P', ' ')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define LIST_HEADER CSP_HDR_VALUE('L', 'I', 'S', 'T')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define FUNC_HEADER CSP_HDR_VALUE('f', 'u', 'n', 'c')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define CODE_HEADER CSP_HDR_VALUE('c', 'o', 'd', 'e')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define INIT_HEADER CSP_HDR_VALUE('i', 'n', 'i', 't')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define MAIN_HEADER CSP_HDR_VALUE('m', 'a', 'i', 'n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * RIFF data format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct riff_header {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) __le32 name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) __le32 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct desc_header {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct riff_header info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) __le16 func_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) __le16 VOC_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) __le16 flags_play_rec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) __le16 flags_16bit_8bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) __le16 flags_stereo_mono;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) __le16 flags_rates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * prototypes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static void snd_sb_csp_free(struct snd_hwdep *hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static int snd_sb_csp_open(struct snd_hwdep * hw, struct file *file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static int snd_sb_csp_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static int snd_sb_csp_release(struct snd_hwdep * hw, struct file *file);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static int csp_detect(struct snd_sb *chip, int *version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static int set_codec_parameter(struct snd_sb *chip, unsigned char par, unsigned char val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int set_register(struct snd_sb *chip, unsigned char reg, unsigned char val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static int read_register(struct snd_sb *chip, unsigned char reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static int set_mode_register(struct snd_sb *chip, unsigned char mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static int get_version(struct snd_sb *chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct snd_sb_csp_microcode __user * code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int snd_sb_csp_unload(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __user *buf, int size, int load_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int snd_sb_csp_check_version(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int snd_sb_csp_use(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static int snd_sb_csp_unuse(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) static int snd_sb_csp_start(struct snd_sb_csp * p, int sample_width, int channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int snd_sb_csp_stop(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static int snd_sb_csp_pause(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int snd_sb_csp_restart(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static int snd_sb_qsound_build(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static void snd_sb_qsound_destroy(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static int snd_sb_csp_qsound_transfer(struct snd_sb_csp * p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static int init_proc_entry(struct snd_sb_csp * p, int device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static void info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * Detect CSP chip and create a new instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) int snd_sb_csp_new(struct snd_sb *chip, int device, struct snd_hwdep ** rhwdep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct snd_sb_csp *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) int version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct snd_hwdep *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (rhwdep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) *rhwdep = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (csp_detect(chip, &version))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if ((err = snd_hwdep_new(chip->card, "SB16-CSP", device, &hw)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if ((p = kzalloc(sizeof(*p), GFP_KERNEL)) == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) snd_device_free(chip->card, hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) p->chip = chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) p->version = version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* CSP operators */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) p->ops.csp_use = snd_sb_csp_use;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) p->ops.csp_unuse = snd_sb_csp_unuse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) p->ops.csp_autoload = snd_sb_csp_autoload;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) p->ops.csp_start = snd_sb_csp_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) p->ops.csp_stop = snd_sb_csp_stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) p->ops.csp_qsound_transfer = snd_sb_csp_qsound_transfer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) mutex_init(&p->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) sprintf(hw->name, "CSP v%d.%d", (version >> 4), (version & 0x0f));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) hw->iface = SNDRV_HWDEP_IFACE_SB16CSP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) hw->private_data = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) hw->private_free = snd_sb_csp_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* operators - only write/ioctl */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) hw->ops.open = snd_sb_csp_open;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) hw->ops.ioctl = snd_sb_csp_ioctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) hw->ops.release = snd_sb_csp_release;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* create a proc entry */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) init_proc_entry(p, device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (rhwdep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) *rhwdep = hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * free_private for hwdep instance
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static void snd_sb_csp_free(struct snd_hwdep *hwdep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct snd_sb_csp *p = hwdep->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (p->running & SNDRV_SB_CSP_ST_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) snd_sb_csp_stop(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) for (i = 0; i < ARRAY_SIZE(p->csp_programs); ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) release_firmware(p->csp_programs[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /* ------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * open the device exclusively
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static int snd_sb_csp_open(struct snd_hwdep * hw, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct snd_sb_csp *p = hw->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return (snd_sb_csp_use(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * ioctl for hwdep device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static int snd_sb_csp_ioctl(struct snd_hwdep * hw, struct file *file, unsigned int cmd, unsigned long arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct snd_sb_csp *p = hw->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct snd_sb_csp_info info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct snd_sb_csp_start start_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (snd_BUG_ON(!p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (snd_sb_csp_check_version(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /* get information */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) case SNDRV_SB_CSP_IOCTL_INFO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) memset(&info, 0, sizeof(info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) *info.codec_name = *p->codec_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) info.func_nr = p->func_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) info.acc_format = p->acc_format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) info.acc_channels = p->acc_channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) info.acc_width = p->acc_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) info.acc_rates = p->acc_rates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) info.csp_mode = p->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) info.run_channels = p->run_channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) info.run_width = p->run_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) info.version = p->version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) info.state = p->running;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (copy_to_user((void __user *)arg, &info, sizeof(info)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) err = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /* load CSP microcode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) case SNDRV_SB_CSP_IOCTL_LOAD_CODE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) err = (p->running & SNDRV_SB_CSP_ST_RUNNING ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) -EBUSY : snd_sb_csp_riff_load(p, (struct snd_sb_csp_microcode __user *) arg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) case SNDRV_SB_CSP_IOCTL_UNLOAD_CODE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) err = (p->running & SNDRV_SB_CSP_ST_RUNNING ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) -EBUSY : snd_sb_csp_unload(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* change CSP running state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) case SNDRV_SB_CSP_IOCTL_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (copy_from_user(&start_info, (void __user *) arg, sizeof(start_info)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) err = -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) err = snd_sb_csp_start(p, start_info.sample_width, start_info.channels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) case SNDRV_SB_CSP_IOCTL_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) err = snd_sb_csp_stop(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) case SNDRV_SB_CSP_IOCTL_PAUSE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) err = snd_sb_csp_pause(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) case SNDRV_SB_CSP_IOCTL_RESTART:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) err = snd_sb_csp_restart(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) err = -ENOTTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * close the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static int snd_sb_csp_release(struct snd_hwdep * hw, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) struct snd_sb_csp *p = hw->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return (snd_sb_csp_unuse(p));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* ------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * acquire device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static int snd_sb_csp_use(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) mutex_lock(&p->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (p->used) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) mutex_unlock(&p->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) return -EAGAIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) p->used++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) mutex_unlock(&p->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * release device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) static int snd_sb_csp_unuse(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) mutex_lock(&p->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) p->used--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) mutex_unlock(&p->access_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) * load microcode via ioctl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) * code is user-space pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static int snd_sb_csp_riff_load(struct snd_sb_csp * p,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct snd_sb_csp_microcode __user * mcode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct snd_sb_csp_mc_header info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) unsigned char __user *data_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) unsigned char __user *data_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) unsigned short func_nr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) struct riff_header file_h, item_h, code_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) __le32 item_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) struct desc_header funcdesc_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (copy_from_user(&info, mcode, sizeof(info)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) data_ptr = mcode->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (copy_from_user(&file_h, data_ptr, sizeof(file_h)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if ((le32_to_cpu(file_h.name) != RIFF_HEADER) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) (le32_to_cpu(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) snd_printd("%s: Invalid RIFF header\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) data_ptr += sizeof(file_h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) data_end = data_ptr + le32_to_cpu(file_h.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (le32_to_cpu(item_type) != CSP__HEADER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) snd_printd("%s: Invalid RIFF file type\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) data_ptr += sizeof (item_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) for (; data_ptr < data_end; data_ptr += le32_to_cpu(item_h.len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (copy_from_user(&item_h, data_ptr, sizeof(item_h)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) data_ptr += sizeof(item_h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (le32_to_cpu(item_h.name) != LIST_HEADER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) switch (le32_to_cpu(item_type)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) case FUNC_HEADER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (copy_from_user(&funcdesc_h, data_ptr + sizeof(item_type), sizeof(funcdesc_h)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) func_nr = le16_to_cpu(funcdesc_h.func_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) case CODE_HEADER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (func_nr != info.func_req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) break; /* not required function, try next */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) data_ptr += sizeof(item_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) /* destroy QSound mixer element */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) snd_sb_qsound_destroy(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) /* Clear all flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) p->running = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) p->mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) /* load microcode blocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (data_ptr >= data_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) /* init microcode blocks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (le32_to_cpu(code_h.name) != INIT_HEADER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) data_ptr += sizeof(code_h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) err = snd_sb_csp_load_user(p, data_ptr, le32_to_cpu(code_h.len),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) SNDRV_SB_CSP_LOAD_INITBLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) data_ptr += le32_to_cpu(code_h.len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) /* main microcode block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (le32_to_cpu(code_h.name) != MAIN_HEADER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) snd_printd("%s: Missing 'main' microcode\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) data_ptr += sizeof(code_h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) err = snd_sb_csp_load_user(p, data_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) le32_to_cpu(code_h.len), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) /* fill in codec header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) strlcpy(p->codec_name, info.codec_name, sizeof(p->codec_name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) p->func_nr = func_nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) p->mode = le16_to_cpu(funcdesc_h.flags_play_rec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) switch (le16_to_cpu(funcdesc_h.VOC_type)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) case 0x0001: /* QSound decoder */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (le16_to_cpu(funcdesc_h.flags_play_rec) == SNDRV_SB_CSP_MODE_DSP_WRITE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) if (snd_sb_qsound_build(p) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* set QSound flag and clear all other mode flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) p->mode = SNDRV_SB_CSP_MODE_QSOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) p->acc_format = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) case 0x0006: /* A Law codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) case 0x0007: /* Mu Law codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) case 0x0011: /* what Creative thinks is IMA ADPCM codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) case 0x0200: /* Creative ADPCM codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) case 201: /* Text 2 Speech decoder */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) /* TODO: Text2Speech handling routines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) p->acc_format = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) case 0x0202: /* Fast Speech 8 codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) case 0x0203: /* Fast Speech 10 codec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) p->acc_format = SNDRV_PCM_FMTBIT_SPECIAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) default: /* other codecs are unsupported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) p->acc_format = p->acc_width = p->acc_rates = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) p->mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) snd_printd("%s: Unsupported CSP codec type: 0x%04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) le16_to_cpu(funcdesc_h.VOC_type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) p->acc_channels = le16_to_cpu(funcdesc_h.flags_stereo_mono);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) p->acc_width = le16_to_cpu(funcdesc_h.flags_16bit_8bit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) p->acc_rates = le16_to_cpu(funcdesc_h.flags_rates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) /* Decouple CSP from IRQ and DMAREQ lines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) spin_lock_irqsave(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) set_mode_register(p->chip, 0xfc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) set_mode_register(p->chip, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) spin_unlock_irqrestore(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) /* finished loading successfully */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) p->running = SNDRV_SB_CSP_ST_LOADED; /* set LOADED flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) snd_printd("%s: Function #%d not found\n", __func__, info.func_req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) * unload CSP microcode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) static int snd_sb_csp_unload(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) if (p->running & SNDRV_SB_CSP_ST_RUNNING)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) if (!(p->running & SNDRV_SB_CSP_ST_LOADED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) /* clear supported formats */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) p->acc_format = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) p->acc_channels = p->acc_width = p->acc_rates = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) /* destroy QSound mixer element */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) snd_sb_qsound_destroy(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /* clear all flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) p->running = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) p->mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) * send command sequence to DSP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) static inline int command_seq(struct snd_sb *chip, const unsigned char *seq, int size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) for (i = 0; i < size; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (!snd_sbdsp_command(chip, seq[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) * set CSP codec parameter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static int set_codec_parameter(struct snd_sb *chip, unsigned char par, unsigned char val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) unsigned char dsp_cmd[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) dsp_cmd[0] = 0x05; /* CSP set codec parameter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) dsp_cmd[1] = val; /* Parameter value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) dsp_cmd[2] = par; /* Parameter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) command_seq(chip, dsp_cmd, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) snd_sbdsp_command(chip, 0x03); /* DSP read? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (snd_sbdsp_get_byte(chip) != par)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * set CSP register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) static int set_register(struct snd_sb *chip, unsigned char reg, unsigned char val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) unsigned char dsp_cmd[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) dsp_cmd[0] = 0x0e; /* CSP set register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) dsp_cmd[1] = reg; /* CSP Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dsp_cmd[2] = val; /* value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) return command_seq(chip, dsp_cmd, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) * read CSP register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) * return < 0 -> error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) static int read_register(struct snd_sb *chip, unsigned char reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) unsigned char dsp_cmd[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) dsp_cmd[0] = 0x0f; /* CSP read register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) dsp_cmd[1] = reg; /* CSP Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) command_seq(chip, dsp_cmd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) return snd_sbdsp_get_byte(chip); /* Read DSP value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) * set CSP mode register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static int set_mode_register(struct snd_sb *chip, unsigned char mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) unsigned char dsp_cmd[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) dsp_cmd[0] = 0x04; /* CSP set mode register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) dsp_cmd[1] = mode; /* mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) return command_seq(chip, dsp_cmd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) * Detect CSP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) * return 0 if CSP exists.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) static int csp_detect(struct snd_sb *chip, int *version)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) unsigned char csp_test1, csp_test2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) int result = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) spin_lock_irqsave(&chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) set_codec_parameter(chip, 0x00, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) set_mode_register(chip, 0xfc); /* 0xfc = ?? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) csp_test1 = read_register(chip, 0x83);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) set_register(chip, 0x83, ~csp_test1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) csp_test2 = read_register(chip, 0x83);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) if (csp_test2 != (csp_test1 ^ 0xff))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) set_register(chip, 0x83, csp_test1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) csp_test2 = read_register(chip, 0x83);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (csp_test2 != csp_test1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) set_mode_register(chip, 0x00); /* 0x00 = ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) *version = get_version(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) snd_sbdsp_reset(chip); /* reset DSP after getversion! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) if (*version >= 0x10 && *version <= 0x1f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) result = 0; /* valid version id */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) __fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) spin_unlock_irqrestore(&chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) * get CSP version number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) static int get_version(struct snd_sb *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) unsigned char dsp_cmd[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) dsp_cmd[0] = 0x08; /* SB_DSP_!something! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) dsp_cmd[1] = 0x03; /* get chip version id? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) command_seq(chip, dsp_cmd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return (snd_sbdsp_get_byte(chip));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) * check if the CSP version is valid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) static int snd_sb_csp_check_version(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (p->version < 0x10 || p->version > 0x1f) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) snd_printd("%s: Invalid CSP version: 0x%x\n", __func__, p->version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) * download microcode to CSP (microcode should have one "main" block).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int size, int load_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) int status, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) int result = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) spin_lock_irqsave(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) snd_sbdsp_command(p->chip, 0x01); /* CSP download command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (snd_sbdsp_get_byte(p->chip)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) snd_printd("%s: Download command failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /* Send CSP low byte (size - 1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) snd_sbdsp_command(p->chip, (unsigned char)(size - 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) /* Send high byte */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) snd_sbdsp_command(p->chip, (unsigned char)((size - 1) >> 8));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) /* send microcode sequence */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) /* load from kernel space */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) while (size--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) if (!snd_sbdsp_command(p->chip, *buf++))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) if (snd_sbdsp_get_byte(p->chip))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if (load_flags & SNDRV_SB_CSP_LOAD_INITBLOCK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) /* some codecs (FastSpeech) take some time to initialize */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) snd_sbdsp_command(p->chip, 0x03);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) status = snd_sbdsp_get_byte(p->chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) if (status == 0x55 || ++i >= 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) udelay (10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) if (status != 0x55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) snd_printd("%s: Microcode initialization failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) * Read mixer register SB_DSP4_DMASETUP after loading 'main' code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) * Start CSP chip if no 16bit DMA channel is set - some kind
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) * of autorun or perhaps a bugfix?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) spin_lock(&p->chip->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) status = snd_sbmixer_read(p->chip, SB_DSP4_DMASETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) spin_unlock(&p->chip->mixer_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (!(status & (SB_DMASETUP_DMA7 | SB_DMASETUP_DMA6 | SB_DMASETUP_DMA5))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) err = (set_codec_parameter(p->chip, 0xaa, 0x00) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) set_codec_parameter(p->chip, 0xff, 0x00));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) snd_sbdsp_reset(p->chip); /* really! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) set_mode_register(p->chip, 0xc0); /* c0 = STOP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) set_mode_register(p->chip, 0x70); /* 70 = RUN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) __fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) spin_unlock_irqrestore(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __user *buf, int size, int load_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) unsigned char *kbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) kbuf = memdup_user(buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) if (IS_ERR(kbuf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) return PTR_ERR(kbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) err = snd_sb_csp_load(p, kbuf, size, load_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) kfree(kbuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) static const char *const names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) "sb16/mulaw_main.csp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) "sb16/alaw_main.csp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) "sb16/ima_adpcm_init.csp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) "sb16/ima_adpcm_playback.csp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) "sb16/ima_adpcm_capture.csp",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) const struct firmware *program;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) program = p->csp_programs[index];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) if (!program) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) int err = request_firmware(&program, names[index],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) p->chip->card->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) p->csp_programs[index] = program;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) return snd_sb_csp_load(p, program->data, program->size, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) * autoload hardware codec if necessary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) * return 0 if CSP is loaded and ready to run (p->running != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) /* if CSP is running or manually loaded then exit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) if (p->running & (SNDRV_SB_CSP_ST_RUNNING | SNDRV_SB_CSP_ST_LOADED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) /* autoload microcode only if requested hardware codec is not already loaded */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) if (((1U << (__force int)pcm_sfmt) & p->acc_format) && (play_rec_mode & p->mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) p->running = SNDRV_SB_CSP_ST_AUTO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) switch (pcm_sfmt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) case SNDRV_PCM_FORMAT_MU_LAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) case SNDRV_PCM_FORMAT_A_LAW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) case SNDRV_PCM_FORMAT_IMA_ADPCM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) SNDRV_SB_CSP_LOAD_INITBLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) err = snd_sb_csp_firmware_load
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) (p, CSP_PROGRAM_ADPCM_PLAYBACK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) err = snd_sb_csp_firmware_load
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) (p, CSP_PROGRAM_ADPCM_CAPTURE, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) p->mode = SNDRV_SB_CSP_MODE_DSP_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) /* Decouple CSP from IRQ and DMAREQ lines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if (p->running & SNDRV_SB_CSP_ST_AUTO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) spin_lock_irqsave(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) set_mode_register(p->chip, 0xfc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) set_mode_register(p->chip, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) spin_unlock_irqrestore(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) p->running = 0; /* clear autoloaded flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) p->acc_format = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) p->acc_channels = p->acc_width = p->acc_rates = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) p->running = 0; /* clear autoloaded flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) p->mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) return (err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) p->running = SNDRV_SB_CSP_ST_AUTO; /* set autoloaded flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) p->acc_width = SNDRV_SB_CSP_SAMPLE_16BIT; /* only 16 bit data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) p->acc_channels = SNDRV_SB_CSP_MONO | SNDRV_SB_CSP_STEREO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) p->acc_rates = SNDRV_SB_CSP_RATE_ALL; /* HW codecs accept all rates */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) return (p->running & SNDRV_SB_CSP_ST_AUTO) ? 0 : -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) * start CSP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static int snd_sb_csp_start(struct snd_sb_csp * p, int sample_width, int channels)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) unsigned char s_type; /* sample type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) unsigned char mixL, mixR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) int result = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) if (!(p->running & (SNDRV_SB_CSP_ST_LOADED | SNDRV_SB_CSP_ST_AUTO))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) snd_printd("%s: Microcode not loaded\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) if (p->running & SNDRV_SB_CSP_ST_RUNNING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) snd_printd("%s: CSP already running\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) if (!(sample_width & p->acc_width)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) snd_printd("%s: Unsupported PCM sample width\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) if (!(channels & p->acc_channels)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) snd_printd("%s: Invalid number of channels\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) /* Mute PCM volume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) spin_lock_irqsave(&p->chip->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) spin_lock(&p->chip->reg_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) set_mode_register(p->chip, 0xc0); /* c0 = STOP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) set_mode_register(p->chip, 0x70); /* 70 = RUN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) s_type = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (channels == SNDRV_SB_CSP_MONO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) s_type = 0x11; /* 000n 000n (n = 1 if mono) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) if (sample_width == SNDRV_SB_CSP_SAMPLE_8BIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) s_type |= 0x22; /* 00dX 00dX (d = 1 if 8 bit samples) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (set_codec_parameter(p->chip, 0x81, s_type)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) snd_printd("%s: Set sample type command failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) if (set_codec_parameter(p->chip, 0x80, 0x00)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) snd_printd("%s: Codec start command failed\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) goto __fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) p->run_width = sample_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) p->run_channels = channels;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) p->running |= SNDRV_SB_CSP_ST_RUNNING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (p->mode & SNDRV_SB_CSP_MODE_QSOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) set_codec_parameter(p->chip, 0xe0, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) /* enable QSound decoder */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) set_codec_parameter(p->chip, 0x00, 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) set_codec_parameter(p->chip, 0x01, 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) p->running |= SNDRV_SB_CSP_ST_QSOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) /* set QSound startup value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) snd_sb_csp_qsound_transfer(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) __fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) spin_unlock(&p->chip->reg_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) /* restore PCM volume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) spin_lock_irqsave(&p->chip->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) * stop CSP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) static int snd_sb_csp_stop(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) unsigned char mixL, mixR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) if (!(p->running & SNDRV_SB_CSP_ST_RUNNING))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) /* Mute PCM volume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) spin_lock_irqsave(&p->chip->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) spin_lock(&p->chip->reg_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) set_codec_parameter(p->chip, 0xe0, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) /* disable QSound decoder */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) set_codec_parameter(p->chip, 0x00, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) set_codec_parameter(p->chip, 0x01, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) p->running &= ~SNDRV_SB_CSP_ST_QSOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) result = set_mode_register(p->chip, 0xc0); /* c0 = STOP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) spin_unlock(&p->chip->reg_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) /* restore PCM volume */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) spin_lock_irqsave(&p->chip->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) spin_unlock_irqrestore(&p->chip->mixer_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) if (!(result))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) p->running &= ~(SNDRV_SB_CSP_ST_PAUSED | SNDRV_SB_CSP_ST_RUNNING);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) * pause CSP codec and hold DMA transfer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static int snd_sb_csp_pause(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) if (!(p->running & SNDRV_SB_CSP_ST_RUNNING))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) spin_lock_irqsave(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) result = set_codec_parameter(p->chip, 0x80, 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) spin_unlock_irqrestore(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) if (!(result))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) p->running |= SNDRV_SB_CSP_ST_PAUSED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) * restart CSP codec and resume DMA transfer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) static int snd_sb_csp_restart(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) if (!(p->running & SNDRV_SB_CSP_ST_PAUSED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) spin_lock_irqsave(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) result = set_codec_parameter(p->chip, 0x80, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) spin_unlock_irqrestore(&p->chip->reg_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) if (!(result))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) p->running &= ~SNDRV_SB_CSP_ST_PAUSED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) /* ------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) * QSound mixer control for PCM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) #define snd_sb_qsound_switch_info snd_ctl_boolean_mono_info
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) static int snd_sb_qsound_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) ucontrol->value.integer.value[0] = p->q_enabled ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) static int snd_sb_qsound_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) int change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) unsigned char nval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) nval = ucontrol->value.integer.value[0] & 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) spin_lock_irqsave(&p->q_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) change = p->q_enabled != nval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) p->q_enabled = nval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) spin_unlock_irqrestore(&p->q_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) return change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) static int snd_sb_qsound_space_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) uinfo->count = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) uinfo->value.integer.min = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) uinfo->value.integer.max = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) static int snd_sb_qsound_space_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) spin_lock_irqsave(&p->q_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) ucontrol->value.integer.value[0] = p->qpos_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) ucontrol->value.integer.value[1] = p->qpos_right;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) spin_unlock_irqrestore(&p->q_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) static int snd_sb_qsound_space_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) int change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) unsigned char nval1, nval2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) nval1 = ucontrol->value.integer.value[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) if (nval1 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) nval1 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) nval2 = ucontrol->value.integer.value[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) if (nval2 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) nval2 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) spin_lock_irqsave(&p->q_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) change = p->qpos_left != nval1 || p->qpos_right != nval2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) p->qpos_left = nval1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) p->qpos_right = nval2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) p->qpos_changed = change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) spin_unlock_irqrestore(&p->q_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) return change;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) static const struct snd_kcontrol_new snd_sb_qsound_switch = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) .name = "3D Control - Switch",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) .info = snd_sb_qsound_switch_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) .get = snd_sb_qsound_switch_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) .put = snd_sb_qsound_switch_put
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) static const struct snd_kcontrol_new snd_sb_qsound_space = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) .name = "3D Control - Space",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) .info = snd_sb_qsound_space_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) .get = snd_sb_qsound_space_get,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) .put = snd_sb_qsound_space_put
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) static int snd_sb_qsound_build(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) if (snd_BUG_ON(!p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) card = p->chip->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) p->qpos_left = p->qpos_right = SNDRV_SB_CSP_QSOUND_MAX_RIGHT / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) p->qpos_changed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) spin_lock_init(&p->q_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) if ((err = snd_ctl_add(card, p->qsound_switch = snd_ctl_new1(&snd_sb_qsound_switch, p))) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) p->qsound_switch = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) goto __error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) if ((err = snd_ctl_add(card, p->qsound_space = snd_ctl_new1(&snd_sb_qsound_space, p))) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) p->qsound_space = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) goto __error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) __error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) snd_sb_qsound_destroy(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) static void snd_sb_qsound_destroy(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) struct snd_card *card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) if (snd_BUG_ON(!p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) card = p->chip->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) down_write(&card->controls_rwsem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) if (p->qsound_switch) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) snd_ctl_remove(card, p->qsound_switch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) p->qsound_switch = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (p->qsound_space) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) snd_ctl_remove(card, p->qsound_space);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) p->qsound_space = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) up_write(&card->controls_rwsem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) /* cancel pending transfer of QSound parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) spin_lock_irqsave (&p->q_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) p->qpos_changed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) spin_unlock_irqrestore (&p->q_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) * Transfer qsound parameters to CSP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) * function should be called from interrupt routine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) static int snd_sb_csp_qsound_transfer(struct snd_sb_csp * p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) int err = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) spin_lock(&p->q_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) set_codec_parameter(p->chip, 0xe0, 0x01);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) /* left channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) set_codec_parameter(p->chip, 0x00, p->qpos_left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) set_codec_parameter(p->chip, 0x02, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) /* right channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) set_codec_parameter(p->chip, 0x00, p->qpos_right);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) set_codec_parameter(p->chip, 0x03, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) p->qpos_changed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) spin_unlock(&p->q_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) /* ------------------------------ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) * proc interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) static int init_proc_entry(struct snd_sb_csp * p, int device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) char name[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) sprintf(name, "cspD%d", device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) snd_card_ro_proc_new(p->chip->card, name, p, info_read);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) static void info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) struct snd_sb_csp *p = entry->private_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) snd_iprintf(buffer, "Creative Signal Processor [v%d.%d]\n", (p->version >> 4), (p->version & 0x0f));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) snd_iprintf(buffer, "State: %cx%c%c%c\n", ((p->running & SNDRV_SB_CSP_ST_QSOUND) ? 'Q' : '-'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) ((p->running & SNDRV_SB_CSP_ST_PAUSED) ? 'P' : '-'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) ((p->running & SNDRV_SB_CSP_ST_RUNNING) ? 'R' : '-'),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) ((p->running & SNDRV_SB_CSP_ST_LOADED) ? 'L' : '-'));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) if (p->running & SNDRV_SB_CSP_ST_LOADED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) snd_iprintf(buffer, "Codec: %s [func #%d]\n", p->codec_name, p->func_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) snd_iprintf(buffer, "Sample rates: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) if (p->acc_rates == SNDRV_SB_CSP_RATE_ALL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) snd_iprintf(buffer, "All\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) snd_iprintf(buffer, "%s%s%s%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) ((p->acc_rates & SNDRV_SB_CSP_RATE_8000) ? "8000Hz " : ""),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) ((p->acc_rates & SNDRV_SB_CSP_RATE_11025) ? "11025Hz " : ""),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) ((p->acc_rates & SNDRV_SB_CSP_RATE_22050) ? "22050Hz " : ""),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) ((p->acc_rates & SNDRV_SB_CSP_RATE_44100) ? "44100Hz" : ""));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) snd_iprintf(buffer, "QSound decoder %sabled\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) p->q_enabled ? "en" : "dis");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) snd_iprintf(buffer, "PCM format ID: 0x%x (%s/%s) [%s/%s] [%s/%s]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) p->acc_format,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) ((p->acc_width & SNDRV_SB_CSP_SAMPLE_16BIT) ? "16bit" : "-"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) ((p->acc_width & SNDRV_SB_CSP_SAMPLE_8BIT) ? "8bit" : "-"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) ((p->acc_channels & SNDRV_SB_CSP_MONO) ? "mono" : "-"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) ((p->acc_channels & SNDRV_SB_CSP_STEREO) ? "stereo" : "-"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) ((p->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) ? "playback" : "-"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) ((p->mode & SNDRV_SB_CSP_MODE_DSP_READ) ? "capture" : "-"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) if (p->running & SNDRV_SB_CSP_ST_AUTO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) snd_iprintf(buffer, "Autoloaded Mu-Law, A-Law or Ima-ADPCM hardware codec\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) if (p->running & SNDRV_SB_CSP_ST_RUNNING) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) snd_iprintf(buffer, "Processing %dbit %s PCM samples\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) ((p->run_width & SNDRV_SB_CSP_SAMPLE_16BIT) ? 16 : 8),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) ((p->run_channels & SNDRV_SB_CSP_MONO) ? "mono" : "stereo"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) if (p->running & SNDRV_SB_CSP_ST_QSOUND) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) snd_iprintf(buffer, "Qsound position: left = 0x%x, right = 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) p->qpos_left, p->qpos_right);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) /* */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) EXPORT_SYMBOL(snd_sb_csp_new);