cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sb16_csp.c (33052B)


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