brintos

brintos / linux-shallow public Read only

0
0
Text · 32.3 KiB · 071ba85 Raw
1190 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) 1999 by Uros Bizjak <uros@kss-loka.si>4 *                        Takashi Iwai <tiwai@suse.de>5 *6 *  SB16ASP/AWE32 CSP control7 *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_ENDIAN32#define CSP_HDR_VALUE(a,b,c,d)	((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))33#else34#define CSP_HDR_VALUE(a,b,c,d)	((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))35#endif36 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 format47 */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 * prototypes65 */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 instance101 */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 instance155 */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 exclusively173 */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		else214			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		else232			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 device253 */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 device264 */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 device281 */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 pointer294 */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	struct device *dev = p->chip->card->dev;300 301	unsigned char __user *data_ptr;302	unsigned char __user *data_end;303	unsigned short func_nr = 0;304 305	struct riff_header file_h, item_h, code_h;306	__le32 item_type;307	struct desc_header funcdesc_h;308 309	unsigned long flags;310	int err;311 312	if (copy_from_user(&info, mcode, sizeof(info)))313		return -EFAULT;314	data_ptr = mcode->data;315 316	if (copy_from_user(&file_h, data_ptr, sizeof(file_h)))317		return -EFAULT;318	if ((le32_to_cpu(file_h.name) != RIFF_HEADER) ||319	    (le32_to_cpu(file_h.len) >= SNDRV_SB_CSP_MAX_MICROCODE_FILE_SIZE - sizeof(file_h))) {320		dev_dbg(dev, "%s: Invalid RIFF header\n", __func__);321		return -EINVAL;322	}323	data_ptr += sizeof(file_h);324	data_end = data_ptr + le32_to_cpu(file_h.len);325 326	if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))327		return -EFAULT;328	if (le32_to_cpu(item_type) != CSP__HEADER) {329		dev_dbg(dev, "%s: Invalid RIFF file type\n", __func__);330		return -EINVAL;331	}332	data_ptr += sizeof (item_type);333 334	for (; data_ptr < data_end; data_ptr += le32_to_cpu(item_h.len)) {335		if (copy_from_user(&item_h, data_ptr, sizeof(item_h)))336			return -EFAULT;337		data_ptr += sizeof(item_h);338		if (le32_to_cpu(item_h.name) != LIST_HEADER)339			continue;340 341		if (copy_from_user(&item_type, data_ptr, sizeof(item_type)))342			 return -EFAULT;343		switch (le32_to_cpu(item_type)) {344		case FUNC_HEADER:345			if (copy_from_user(&funcdesc_h, data_ptr + sizeof(item_type), sizeof(funcdesc_h)))346				return -EFAULT;347			func_nr = le16_to_cpu(funcdesc_h.func_nr);348			break;349		case CODE_HEADER:350			if (func_nr != info.func_req)351				break;	/* not required function, try next */352			data_ptr += sizeof(item_type);353 354			/* destroy QSound mixer element */355			if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {356				snd_sb_qsound_destroy(p);357			}358			/* Clear all flags */359			p->running = 0;360			p->mode = 0;361 362			/* load microcode blocks */363			for (;;) {364				if (data_ptr >= data_end)365					return -EINVAL;366				if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))367					return -EFAULT;368 369				/* init microcode blocks */370				if (le32_to_cpu(code_h.name) != INIT_HEADER)371					break;372				data_ptr += sizeof(code_h);373				err = snd_sb_csp_load_user(p, data_ptr, le32_to_cpu(code_h.len),374						      SNDRV_SB_CSP_LOAD_INITBLOCK);375				if (err)376					return err;377				data_ptr += le32_to_cpu(code_h.len);378			}379			/* main microcode block */380			if (copy_from_user(&code_h, data_ptr, sizeof(code_h)))381				return -EFAULT;382 383			if (le32_to_cpu(code_h.name) != MAIN_HEADER) {384				dev_dbg(dev, "%s: Missing 'main' microcode\n", __func__);385				return -EINVAL;386			}387			data_ptr += sizeof(code_h);388			err = snd_sb_csp_load_user(p, data_ptr,389						   le32_to_cpu(code_h.len), 0);390			if (err)391				return err;392 393			/* fill in codec header */394			strscpy(p->codec_name, info.codec_name, sizeof(p->codec_name));395			p->func_nr = func_nr;396			p->mode = le16_to_cpu(funcdesc_h.flags_play_rec);397			switch (le16_to_cpu(funcdesc_h.VOC_type)) {398			case 0x0001:	/* QSound decoder */399				if (le16_to_cpu(funcdesc_h.flags_play_rec) == SNDRV_SB_CSP_MODE_DSP_WRITE) {400					if (snd_sb_qsound_build(p) == 0)401						/* set QSound flag and clear all other mode flags */402						p->mode = SNDRV_SB_CSP_MODE_QSOUND;403				}404				p->acc_format = 0;405				break;406			case 0x0006:	/* A Law codec */407				p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;408				break;409			case 0x0007:	/* Mu Law codec */410				p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;411				break;412			case 0x0011:	/* what Creative thinks is IMA ADPCM codec */413			case 0x0200:	/* Creative ADPCM codec */414				p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;415				break;416			case    201:	/* Text 2 Speech decoder */417				/* TODO: Text2Speech handling routines */418				p->acc_format = 0;419				break;420			case 0x0202:	/* Fast Speech 8 codec */421			case 0x0203:	/* Fast Speech 10 codec */422				p->acc_format = SNDRV_PCM_FMTBIT_SPECIAL;423				break;424			default:	/* other codecs are unsupported */425				p->acc_format = p->acc_width = p->acc_rates = 0;426				p->mode = 0;427				dev_dbg(dev, "%s: Unsupported CSP codec type: 0x%04x\n",428					__func__,429					le16_to_cpu(funcdesc_h.VOC_type));430				return -EINVAL;431			}432			p->acc_channels = le16_to_cpu(funcdesc_h.flags_stereo_mono);433			p->acc_width = le16_to_cpu(funcdesc_h.flags_16bit_8bit);434			p->acc_rates = le16_to_cpu(funcdesc_h.flags_rates);435 436			/* Decouple CSP from IRQ and DMAREQ lines */437			spin_lock_irqsave(&p->chip->reg_lock, flags);438			set_mode_register(p->chip, 0xfc);439			set_mode_register(p->chip, 0x00);440			spin_unlock_irqrestore(&p->chip->reg_lock, flags);441 442			/* finished loading successfully */443			p->running = SNDRV_SB_CSP_ST_LOADED;	/* set LOADED flag */444			return 0;445		}446	}447	dev_dbg(dev, "%s: Function #%d not found\n", __func__, info.func_req);448	return -EINVAL;449}450 451/*452 * unload CSP microcode453 */454static int snd_sb_csp_unload(struct snd_sb_csp * p)455{456	if (p->running & SNDRV_SB_CSP_ST_RUNNING)457		return -EBUSY;458	if (!(p->running & SNDRV_SB_CSP_ST_LOADED))459		return -ENXIO;460 461	/* clear supported formats */462	p->acc_format = 0;463	p->acc_channels = p->acc_width = p->acc_rates = 0;464	/* destroy QSound mixer element */465	if (p->mode == SNDRV_SB_CSP_MODE_QSOUND) {466		snd_sb_qsound_destroy(p);467	}468	/* clear all flags */469	p->running = 0;470	p->mode = 0;471	return 0;472}473 474/*475 * send command sequence to DSP476 */477static inline int command_seq(struct snd_sb *chip, const unsigned char *seq, int size)478{479	int i;480	for (i = 0; i < size; i++) {481		if (!snd_sbdsp_command(chip, seq[i]))482			return -EIO;483	}484	return 0;485}486 487/*488 * set CSP codec parameter489 */490static int set_codec_parameter(struct snd_sb *chip, unsigned char par, unsigned char val)491{492	unsigned char dsp_cmd[3];493 494	dsp_cmd[0] = 0x05;	/* CSP set codec parameter */495	dsp_cmd[1] = val;	/* Parameter value */496	dsp_cmd[2] = par;	/* Parameter */497	command_seq(chip, dsp_cmd, 3);498	snd_sbdsp_command(chip, 0x03);	/* DSP read? */499	if (snd_sbdsp_get_byte(chip) != par)500		return -EIO;501	return 0;502}503 504/*505 * set CSP register506 */507static int set_register(struct snd_sb *chip, unsigned char reg, unsigned char val)508{509	unsigned char dsp_cmd[3];510 511	dsp_cmd[0] = 0x0e;	/* CSP set register */512	dsp_cmd[1] = reg;	/* CSP Register */513	dsp_cmd[2] = val;	/* value */514	return command_seq(chip, dsp_cmd, 3);515}516 517/*518 * read CSP register519 * return < 0 -> error520 */521static int read_register(struct snd_sb *chip, unsigned char reg)522{523	unsigned char dsp_cmd[2];524 525	dsp_cmd[0] = 0x0f;	/* CSP read register */526	dsp_cmd[1] = reg;	/* CSP Register */527	command_seq(chip, dsp_cmd, 2);528	return snd_sbdsp_get_byte(chip);	/* Read DSP value */529}530 531/*532 * set CSP mode register533 */534static int set_mode_register(struct snd_sb *chip, unsigned char mode)535{536	unsigned char dsp_cmd[2];537 538	dsp_cmd[0] = 0x04;	/* CSP set mode register */539	dsp_cmd[1] = mode;	/* mode */540	return command_seq(chip, dsp_cmd, 2);541}542 543/*544 * Detect CSP545 * return 0 if CSP exists.546 */547static int csp_detect(struct snd_sb *chip, int *version)548{549	unsigned char csp_test1, csp_test2;550	unsigned long flags;551	int result = -ENODEV;552 553	spin_lock_irqsave(&chip->reg_lock, flags);554 555	set_codec_parameter(chip, 0x00, 0x00);556	set_mode_register(chip, 0xfc);		/* 0xfc = ?? */557 558	csp_test1 = read_register(chip, 0x83);559	set_register(chip, 0x83, ~csp_test1);560	csp_test2 = read_register(chip, 0x83);561	if (csp_test2 != (csp_test1 ^ 0xff))562		goto __fail;563 564	set_register(chip, 0x83, csp_test1);565	csp_test2 = read_register(chip, 0x83);566	if (csp_test2 != csp_test1)567		goto __fail;568 569	set_mode_register(chip, 0x00);		/* 0x00 = ? */570 571	*version = get_version(chip);572	snd_sbdsp_reset(chip);	/* reset DSP after getversion! */573	if (*version >= 0x10 && *version <= 0x1f)574		result = 0;		/* valid version id */575 576      __fail:577	spin_unlock_irqrestore(&chip->reg_lock, flags);578	return result;579}580 581/*582 * get CSP version number583 */584static int get_version(struct snd_sb *chip)585{586	unsigned char dsp_cmd[2];587 588	dsp_cmd[0] = 0x08;	/* SB_DSP_!something! */589	dsp_cmd[1] = 0x03;	/* get chip version id? */590	command_seq(chip, dsp_cmd, 2);591 592	return (snd_sbdsp_get_byte(chip));593}594 595/*596 * check if the CSP version is valid597 */598static int snd_sb_csp_check_version(struct snd_sb_csp * p)599{600	if (p->version < 0x10 || p->version > 0x1f) {601		dev_dbg(p->chip->card->dev,602			"%s: Invalid CSP version: 0x%x\n",603			__func__, p->version);604		return 1;605	}606	return 0;607}608 609/*610 * download microcode to CSP (microcode should have one "main" block).611 */612static int snd_sb_csp_load(struct snd_sb_csp * p, const unsigned char *buf, int size, int load_flags)613{614	int status, i;615	int err;616	int result = -EIO;617	unsigned long flags;618 619	spin_lock_irqsave(&p->chip->reg_lock, flags);620	snd_sbdsp_command(p->chip, 0x01);	/* CSP download command */621	if (snd_sbdsp_get_byte(p->chip)) {622		dev_dbg(p->chip->card->dev, "%s: Download command failed\n", __func__);623		goto __fail;624	}625	/* Send CSP low byte (size - 1) */626	snd_sbdsp_command(p->chip, (unsigned char)(size - 1));627	/* Send high byte */628	snd_sbdsp_command(p->chip, (unsigned char)((size - 1) >> 8));629	/* send microcode sequence */630	/* load from kernel space */631	while (size--) {632		if (!snd_sbdsp_command(p->chip, *buf++))633			goto __fail;634	}635	if (snd_sbdsp_get_byte(p->chip))636		goto __fail;637 638	if (load_flags & SNDRV_SB_CSP_LOAD_INITBLOCK) {639		i = 0;640		/* some codecs (FastSpeech) take some time to initialize */641		while (1) {642			snd_sbdsp_command(p->chip, 0x03);643			status = snd_sbdsp_get_byte(p->chip);644			if (status == 0x55 || ++i >= 10)645				break;646			udelay (10);647		}648		if (status != 0x55) {649			dev_dbg(p->chip->card->dev,650				"%s: Microcode initialization failed\n",651				__func__);652			goto __fail;653		}654	} else {655		/*656		 * Read mixer register SB_DSP4_DMASETUP after loading 'main' code.657		 * Start CSP chip if no 16bit DMA channel is set - some kind658		 * of autorun or perhaps a bugfix?659		 */660		spin_lock(&p->chip->mixer_lock);661		status = snd_sbmixer_read(p->chip, SB_DSP4_DMASETUP);662		spin_unlock(&p->chip->mixer_lock);663		if (!(status & (SB_DMASETUP_DMA7 | SB_DMASETUP_DMA6 | SB_DMASETUP_DMA5))) {664			err = (set_codec_parameter(p->chip, 0xaa, 0x00) ||665			       set_codec_parameter(p->chip, 0xff, 0x00));666			snd_sbdsp_reset(p->chip);		/* really! */667			if (err)668				goto __fail;669			set_mode_register(p->chip, 0xc0);	/* c0 = STOP */670			set_mode_register(p->chip, 0x70);	/* 70 = RUN */671		}672	}673	result = 0;674 675      __fail:676	spin_unlock_irqrestore(&p->chip->reg_lock, flags);677	return result;678}679 680static int snd_sb_csp_load_user(struct snd_sb_csp * p, const unsigned char __user *buf, int size, int load_flags)681{682	int err;683	unsigned char *kbuf;684 685	kbuf = memdup_user(buf, size);686	if (IS_ERR(kbuf))687		return PTR_ERR(kbuf);688 689	err = snd_sb_csp_load(p, kbuf, size, load_flags);690 691	kfree(kbuf);692	return err;693}694 695static int snd_sb_csp_firmware_load(struct snd_sb_csp *p, int index, int flags)696{697	static const char *const names[] = {698		"sb16/mulaw_main.csp",699		"sb16/alaw_main.csp",700		"sb16/ima_adpcm_init.csp",701		"sb16/ima_adpcm_playback.csp",702		"sb16/ima_adpcm_capture.csp",703	};704	const struct firmware *program;705 706	BUILD_BUG_ON(ARRAY_SIZE(names) != CSP_PROGRAM_COUNT);707	program = p->csp_programs[index];708	if (!program) {709		int err = request_firmware(&program, names[index],710				       p->chip->card->dev);711		if (err < 0)712			return err;713		p->csp_programs[index] = program;714	}715	return snd_sb_csp_load(p, program->data, program->size, flags);716}717 718/*719 * autoload hardware codec if necessary720 * return 0 if CSP is loaded and ready to run (p->running != 0)721 */722static int snd_sb_csp_autoload(struct snd_sb_csp * p, snd_pcm_format_t pcm_sfmt, int play_rec_mode)723{724	unsigned long flags;725	int err = 0;726 727	/* if CSP is running or manually loaded then exit */728	if (p->running & (SNDRV_SB_CSP_ST_RUNNING | SNDRV_SB_CSP_ST_LOADED)) 729		return -EBUSY;730 731	/* autoload microcode only if requested hardware codec is not already loaded */732	if (((1U << (__force int)pcm_sfmt) & p->acc_format) && (play_rec_mode & p->mode)) {733		p->running = SNDRV_SB_CSP_ST_AUTO;734	} else {735		switch (pcm_sfmt) {736		case SNDRV_PCM_FORMAT_MU_LAW:737			err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_MULAW, 0);738			p->acc_format = SNDRV_PCM_FMTBIT_MU_LAW;739			p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;740			break;741		case SNDRV_PCM_FORMAT_A_LAW:742			err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ALAW, 0);743			p->acc_format = SNDRV_PCM_FMTBIT_A_LAW;744			p->mode = SNDRV_SB_CSP_MODE_DSP_READ | SNDRV_SB_CSP_MODE_DSP_WRITE;745			break;746		case SNDRV_PCM_FORMAT_IMA_ADPCM:747			err = snd_sb_csp_firmware_load(p, CSP_PROGRAM_ADPCM_INIT,748						       SNDRV_SB_CSP_LOAD_INITBLOCK);749			if (err)750				break;751			if (play_rec_mode == SNDRV_SB_CSP_MODE_DSP_WRITE) {752				err = snd_sb_csp_firmware_load753					(p, CSP_PROGRAM_ADPCM_PLAYBACK, 0);754				p->mode = SNDRV_SB_CSP_MODE_DSP_WRITE;755			} else {756				err = snd_sb_csp_firmware_load757					(p, CSP_PROGRAM_ADPCM_CAPTURE, 0);758				p->mode = SNDRV_SB_CSP_MODE_DSP_READ;759			}760			p->acc_format = SNDRV_PCM_FMTBIT_IMA_ADPCM;761			break;				  762		default:763			/* Decouple CSP from IRQ and DMAREQ lines */764			if (p->running & SNDRV_SB_CSP_ST_AUTO) {765				spin_lock_irqsave(&p->chip->reg_lock, flags);766				set_mode_register(p->chip, 0xfc);767				set_mode_register(p->chip, 0x00);768				spin_unlock_irqrestore(&p->chip->reg_lock, flags);769				p->running = 0;			/* clear autoloaded flag */770			}771			return -EINVAL;772		}773		if (err) {774			p->acc_format = 0;775			p->acc_channels = p->acc_width = p->acc_rates = 0;776 777			p->running = 0;				/* clear autoloaded flag */778			p->mode = 0;779			return (err);780		} else {781			p->running = SNDRV_SB_CSP_ST_AUTO;	/* set autoloaded flag */782			p->acc_width = SNDRV_SB_CSP_SAMPLE_16BIT;	/* only 16 bit data */783			p->acc_channels = SNDRV_SB_CSP_MONO | SNDRV_SB_CSP_STEREO;784			p->acc_rates = SNDRV_SB_CSP_RATE_ALL;	/* HW codecs accept all rates */785		}   786 787	}788	return (p->running & SNDRV_SB_CSP_ST_AUTO) ? 0 : -ENXIO;789}790 791/*792 * start CSP793 */794static int snd_sb_csp_start(struct snd_sb_csp * p, int sample_width, int channels)795{796	struct device *dev = p->chip->card->dev;797	unsigned char s_type;	/* sample type */798	unsigned char mixL, mixR;799	int result = -EIO;800	unsigned long flags;801 802	if (!(p->running & (SNDRV_SB_CSP_ST_LOADED | SNDRV_SB_CSP_ST_AUTO))) {803		dev_dbg(dev, "%s: Microcode not loaded\n", __func__);804		return -ENXIO;805	}806	if (p->running & SNDRV_SB_CSP_ST_RUNNING) {807		dev_dbg(dev, "%s: CSP already running\n", __func__);808		return -EBUSY;809	}810	if (!(sample_width & p->acc_width)) {811		dev_dbg(dev, "%s: Unsupported PCM sample width\n", __func__);812		return -EINVAL;813	}814	if (!(channels & p->acc_channels)) {815		dev_dbg(dev, "%s: Invalid number of channels\n", __func__);816		return -EINVAL;817	}818 819	/* Mute PCM volume */820	spin_lock_irqsave(&p->chip->mixer_lock, flags);821	mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);822	mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);823	snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);824	snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);825	spin_unlock_irqrestore(&p->chip->mixer_lock, flags);826 827	spin_lock(&p->chip->reg_lock);828	set_mode_register(p->chip, 0xc0);	/* c0 = STOP */829	set_mode_register(p->chip, 0x70);	/* 70 = RUN */830 831	s_type = 0x00;832	if (channels == SNDRV_SB_CSP_MONO)833		s_type = 0x11;	/* 000n 000n    (n = 1 if mono) */834	if (sample_width == SNDRV_SB_CSP_SAMPLE_8BIT)835		s_type |= 0x22;	/* 00dX 00dX    (d = 1 if 8 bit samples) */836 837	if (set_codec_parameter(p->chip, 0x81, s_type)) {838		dev_dbg(dev, "%s: Set sample type command failed\n", __func__);839		goto __fail;840	}841	if (set_codec_parameter(p->chip, 0x80, 0x00)) {842		dev_dbg(dev, "%s: Codec start command failed\n", __func__);843		goto __fail;844	}845	p->run_width = sample_width;846	p->run_channels = channels;847 848	p->running |= SNDRV_SB_CSP_ST_RUNNING;849 850	if (p->mode & SNDRV_SB_CSP_MODE_QSOUND) {851		set_codec_parameter(p->chip, 0xe0, 0x01);852		/* enable QSound decoder */853		set_codec_parameter(p->chip, 0x00, 0xff);854		set_codec_parameter(p->chip, 0x01, 0xff);855		p->running |= SNDRV_SB_CSP_ST_QSOUND;856		/* set QSound startup value */857		snd_sb_csp_qsound_transfer(p);858	}859	result = 0;860 861      __fail:862	spin_unlock(&p->chip->reg_lock);863 864	/* restore PCM volume */865	spin_lock_irqsave(&p->chip->mixer_lock, flags);866	snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);867	snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);868	spin_unlock_irqrestore(&p->chip->mixer_lock, flags);869 870	return result;871}872 873/*874 * stop CSP875 */876static int snd_sb_csp_stop(struct snd_sb_csp * p)877{878	int result;879	unsigned char mixL, mixR;880	unsigned long flags;881 882	if (!(p->running & SNDRV_SB_CSP_ST_RUNNING))883		return 0;884 885	/* Mute PCM volume */886	spin_lock_irqsave(&p->chip->mixer_lock, flags);887	mixL = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV);888	mixR = snd_sbmixer_read(p->chip, SB_DSP4_PCM_DEV + 1);889	snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL & 0x7);890	snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR & 0x7);891	spin_unlock_irqrestore(&p->chip->mixer_lock, flags);892 893	spin_lock(&p->chip->reg_lock);894	if (p->running & SNDRV_SB_CSP_ST_QSOUND) {895		set_codec_parameter(p->chip, 0xe0, 0x01);896		/* disable QSound decoder */897		set_codec_parameter(p->chip, 0x00, 0x00);898		set_codec_parameter(p->chip, 0x01, 0x00);899 900		p->running &= ~SNDRV_SB_CSP_ST_QSOUND;901	}902	result = set_mode_register(p->chip, 0xc0);	/* c0 = STOP */903	spin_unlock(&p->chip->reg_lock);904 905	/* restore PCM volume */906	spin_lock_irqsave(&p->chip->mixer_lock, flags);907	snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV, mixL);908	snd_sbmixer_write(p->chip, SB_DSP4_PCM_DEV + 1, mixR);909	spin_unlock_irqrestore(&p->chip->mixer_lock, flags);910 911	if (!(result))912		p->running &= ~(SNDRV_SB_CSP_ST_PAUSED | SNDRV_SB_CSP_ST_RUNNING);913	return result;914}915 916/*917 * pause CSP codec and hold DMA transfer918 */919static int snd_sb_csp_pause(struct snd_sb_csp * p)920{921	int result;922	unsigned long flags;923 924	if (!(p->running & SNDRV_SB_CSP_ST_RUNNING))925		return -EBUSY;926 927	spin_lock_irqsave(&p->chip->reg_lock, flags);928	result = set_codec_parameter(p->chip, 0x80, 0xff);929	spin_unlock_irqrestore(&p->chip->reg_lock, flags);930	if (!(result))931		p->running |= SNDRV_SB_CSP_ST_PAUSED;932 933	return result;934}935 936/*937 * restart CSP codec and resume DMA transfer938 */939static int snd_sb_csp_restart(struct snd_sb_csp * p)940{941	int result;942	unsigned long flags;943 944	if (!(p->running & SNDRV_SB_CSP_ST_PAUSED))945		return -EBUSY;946 947	spin_lock_irqsave(&p->chip->reg_lock, flags);948	result = set_codec_parameter(p->chip, 0x80, 0x00);949	spin_unlock_irqrestore(&p->chip->reg_lock, flags);950	if (!(result))951		p->running &= ~SNDRV_SB_CSP_ST_PAUSED;952 953	return result;954}955 956/* ------------------------------ */957 958/*959 * QSound mixer control for PCM960 */961 962#define snd_sb_qsound_switch_info	snd_ctl_boolean_mono_info963 964static int snd_sb_qsound_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)965{966	struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);967	968	ucontrol->value.integer.value[0] = p->q_enabled ? 1 : 0;969	return 0;970}971 972static int snd_sb_qsound_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)973{974	struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);975	unsigned long flags;976	int change;977	unsigned char nval;978	979	nval = ucontrol->value.integer.value[0] & 0x01;980	spin_lock_irqsave(&p->q_lock, flags);981	change = p->q_enabled != nval;982	p->q_enabled = nval;983	spin_unlock_irqrestore(&p->q_lock, flags);984	return change;985}986 987static int snd_sb_qsound_space_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)988{989	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;990	uinfo->count = 2;991	uinfo->value.integer.min = 0;992	uinfo->value.integer.max = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;993	return 0;994}995 996static int snd_sb_qsound_space_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)997{998	struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);999	unsigned long flags;1000	1001	spin_lock_irqsave(&p->q_lock, flags);1002	ucontrol->value.integer.value[0] = p->qpos_left;1003	ucontrol->value.integer.value[1] = p->qpos_right;1004	spin_unlock_irqrestore(&p->q_lock, flags);1005	return 0;1006}1007 1008static int snd_sb_qsound_space_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)1009{1010	struct snd_sb_csp *p = snd_kcontrol_chip(kcontrol);1011	unsigned long flags;1012	int change;1013	unsigned char nval1, nval2;1014	1015	nval1 = ucontrol->value.integer.value[0];1016	if (nval1 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT)1017		nval1 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;1018	nval2 = ucontrol->value.integer.value[1];1019	if (nval2 > SNDRV_SB_CSP_QSOUND_MAX_RIGHT)1020		nval2 = SNDRV_SB_CSP_QSOUND_MAX_RIGHT;1021	spin_lock_irqsave(&p->q_lock, flags);1022	change = p->qpos_left != nval1 || p->qpos_right != nval2;1023	p->qpos_left = nval1;1024	p->qpos_right = nval2;1025	p->qpos_changed = change;1026	spin_unlock_irqrestore(&p->q_lock, flags);1027	return change;1028}1029 1030static const struct snd_kcontrol_new snd_sb_qsound_switch = {1031	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,1032	.name = "3D Control - Switch",1033	.info = snd_sb_qsound_switch_info,1034	.get = snd_sb_qsound_switch_get,1035	.put = snd_sb_qsound_switch_put1036};1037 1038static const struct snd_kcontrol_new snd_sb_qsound_space = {1039	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,1040	.name = "3D Control - Space",1041	.info = snd_sb_qsound_space_info,1042	.get = snd_sb_qsound_space_get,1043	.put = snd_sb_qsound_space_put1044};1045 1046static int snd_sb_qsound_build(struct snd_sb_csp * p)1047{1048	struct snd_card *card;1049	struct snd_kcontrol *kctl;1050	int err;1051 1052	if (snd_BUG_ON(!p))1053		return -EINVAL;1054 1055	card = p->chip->card;1056	p->qpos_left = p->qpos_right = SNDRV_SB_CSP_QSOUND_MAX_RIGHT / 2;1057	p->qpos_changed = 0;1058 1059	spin_lock_init(&p->q_lock);1060 1061	kctl = snd_ctl_new1(&snd_sb_qsound_switch, p);1062	err = snd_ctl_add(card, kctl);1063	if (err < 0)1064		goto __error;1065	p->qsound_switch = kctl;1066	kctl = snd_ctl_new1(&snd_sb_qsound_space, p);1067	err = snd_ctl_add(card, kctl);1068	if (err < 0)1069		goto __error;1070	p->qsound_space = kctl;1071 1072	return 0;1073 1074     __error:1075	snd_sb_qsound_destroy(p);1076	return err;1077}1078 1079static void snd_sb_qsound_destroy(struct snd_sb_csp * p)1080{1081	struct snd_card *card;1082	unsigned long flags;1083 1084	if (snd_BUG_ON(!p))1085		return;1086 1087	card = p->chip->card;	1088	1089	snd_ctl_remove(card, p->qsound_switch);1090	p->qsound_switch = NULL;1091	snd_ctl_remove(card, p->qsound_space);1092	p->qsound_space = NULL;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 routine1103 */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 interface1128 */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);1190