brintos

brintos / linux-shallow public Read only

0
0
Text · 16.7 KiB · 2ed176a Raw
593 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>4 *                   Uros Bizjak <uros@kss-loka.si>5 *6 *  Routines for control of 8-bit SoundBlaster cards and clones7 *  Please note: I don't have access to old SB8 soundcards.8 *9 * --10 *11 * Thu Apr 29 20:36:17 BST 1999 George David Morrison <gdm@gedamo.demon.co.uk>12 *   DSP can't respond to commands whilst in "high speed" mode. Caused 13 *   glitching during playback. Fixed.14 *15 * Wed Jul 12 22:02:55 CEST 2000 Uros Bizjak <uros@kss-loka.si>16 *   Cleaned up and rewrote lowlevel routines.17 */18 19#include <linux/io.h>20#include <asm/dma.h>21#include <linux/init.h>22#include <linux/time.h>23#include <linux/module.h>24#include <sound/core.h>25#include <sound/sb.h>26 27MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Uros Bizjak <uros@kss-loka.si>");28MODULE_DESCRIPTION("Routines for control of 8-bit SoundBlaster cards and clones");29MODULE_LICENSE("GPL");30 31#define SB8_CLOCK	100000032#define SB8_DEN(v)	((SB8_CLOCK + (v) / 2) / (v))33#define SB8_RATE(v)	(SB8_CLOCK / SB8_DEN(v))34 35static const struct snd_ratnum clock = {36	.num = SB8_CLOCK,37	.den_min = 1,38	.den_max = 256,39	.den_step = 1,40};41 42static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clock = {43	.nrats = 1,44	.rats = &clock,45};46 47static const struct snd_ratnum stereo_clocks[] = {48	{49		.num = SB8_CLOCK,50		.den_min = SB8_DEN(22050),51		.den_max = SB8_DEN(22050),52		.den_step = 1,53	},54	{55		.num = SB8_CLOCK,56		.den_min = SB8_DEN(11025),57		.den_max = SB8_DEN(11025),58		.den_step = 1,59	}60};61 62static int snd_sb8_hw_constraint_rate_channels(struct snd_pcm_hw_params *params,63					       struct snd_pcm_hw_rule *rule)64{65	struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);66	if (c->min > 1) {67	  	unsigned int num = 0, den = 0;68		int err = snd_interval_ratnum(hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE),69					  2, stereo_clocks, &num, &den);70		if (err >= 0 && den) {71			params->rate_num = num;72			params->rate_den = den;73		}74		return err;75	}76	return 0;77}78 79static int snd_sb8_hw_constraint_channels_rate(struct snd_pcm_hw_params *params,80					       struct snd_pcm_hw_rule *rule)81{82	struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);83	if (r->min > SB8_RATE(22050) || r->max <= SB8_RATE(11025)) {84		struct snd_interval t = { .min = 1, .max = 1 };85		return snd_interval_refine(hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS), &t);86	}87	return 0;88}89 90static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)91{92	unsigned long flags;93	struct snd_sb *chip = snd_pcm_substream_chip(substream);94	struct snd_pcm_runtime *runtime = substream->runtime;95	unsigned int mixreg, rate, size, count;96	unsigned char format;97	unsigned char stereo = runtime->channels > 1;98	int dma;99 100	rate = runtime->rate;101	switch (chip->hardware) {102	case SB_HW_JAZZ16:103		if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {104			if (chip->mode & SB_MODE_CAPTURE_16)105				return -EBUSY;106			else107				chip->mode |= SB_MODE_PLAYBACK_16;108		}109		chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;110		break;111	case SB_HW_PRO:112		if (runtime->channels > 1) {113			if (snd_BUG_ON(rate != SB8_RATE(11025) &&114				       rate != SB8_RATE(22050)))115				return -EINVAL;116			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;117			break;118		}119		fallthrough;120	case SB_HW_201:121		if (rate > 23000) {122			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;123			break;124		}125		fallthrough;126	case SB_HW_20:127		chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;128		break;129	case SB_HW_10:130		chip->playback_format = SB_DSP_OUTPUT;131		break;132	default:133		return -EINVAL;134	}135	if (chip->mode & SB_MODE_PLAYBACK_16) {136		format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;137		dma = chip->dma16;138	} else {139		format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;140		chip->mode |= SB_MODE_PLAYBACK_8;141		dma = chip->dma8;142	}143	size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);144	count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);145	spin_lock_irqsave(&chip->reg_lock, flags);146	snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);147	if (chip->hardware == SB_HW_JAZZ16)148		snd_sbdsp_command(chip, format);149	else if (stereo) {150		/* set playback stereo mode */151		spin_lock(&chip->mixer_lock);152		mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);153		snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02);154		spin_unlock(&chip->mixer_lock);155 156		/* Soundblaster hardware programming reference guide, 3-23 */157		snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);158		runtime->dma_area[0] = 0x80;159		snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);160		/* force interrupt */161		snd_sbdsp_command(chip, SB_DSP_OUTPUT);162		snd_sbdsp_command(chip, 0);163		snd_sbdsp_command(chip, 0);164	}165	snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);166	if (stereo) {167		snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);168		spin_lock(&chip->mixer_lock);169		/* save output filter status and turn it off */170		mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT);171		snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20);172		spin_unlock(&chip->mixer_lock);173		/* just use force_mode16 for temporary storate... */174		chip->force_mode16 = mixreg;175	} else {176		snd_sbdsp_command(chip, 256 - runtime->rate_den);177	}178	if (chip->playback_format != SB_DSP_OUTPUT) {179		if (chip->mode & SB_MODE_PLAYBACK_16)180			count /= 2;181		count--;182		snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);183		snd_sbdsp_command(chip, count & 0xff);184		snd_sbdsp_command(chip, count >> 8);185	}186	spin_unlock_irqrestore(&chip->reg_lock, flags);187	snd_dma_program(dma, runtime->dma_addr,188			size, DMA_MODE_WRITE | DMA_AUTOINIT);189	return 0;190}191 192static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,193				    int cmd)194{195	unsigned long flags;196	struct snd_sb *chip = snd_pcm_substream_chip(substream);197	unsigned int count;198 199	spin_lock_irqsave(&chip->reg_lock, flags);200	switch (cmd) {201	case SNDRV_PCM_TRIGGER_START:202		snd_sbdsp_command(chip, chip->playback_format);203		if (chip->playback_format == SB_DSP_OUTPUT) {204			count = chip->p_period_size - 1;205			snd_sbdsp_command(chip, count & 0xff);206			snd_sbdsp_command(chip, count >> 8);207		}208		break;209	case SNDRV_PCM_TRIGGER_STOP:210		if (chip->playback_format == SB_DSP_HI_OUTPUT_AUTO) {211			struct snd_pcm_runtime *runtime = substream->runtime;212			snd_sbdsp_reset(chip);213			if (runtime->channels > 1) {214				spin_lock(&chip->mixer_lock);215				/* restore output filter and set hardware to mono mode */ 216				snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02);217				spin_unlock(&chip->mixer_lock);218			}219		} else {220			snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);221		}222		snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);223	}224	spin_unlock_irqrestore(&chip->reg_lock, flags);225	return 0;226}227 228static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)229{230	unsigned long flags;231	struct snd_sb *chip = snd_pcm_substream_chip(substream);232	struct snd_pcm_runtime *runtime = substream->runtime;233	unsigned int mixreg, rate, size, count;234	unsigned char format;235	unsigned char stereo = runtime->channels > 1;236	int dma;237 238	rate = runtime->rate;239	switch (chip->hardware) {240	case SB_HW_JAZZ16:241		if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {242			if (chip->mode & SB_MODE_PLAYBACK_16)243				return -EBUSY;244			else245				chip->mode |= SB_MODE_CAPTURE_16;246		}247		chip->capture_format = SB_DSP_LO_INPUT_AUTO;248		break;249	case SB_HW_PRO:250		if (runtime->channels > 1) {251			if (snd_BUG_ON(rate != SB8_RATE(11025) &&252				       rate != SB8_RATE(22050)))253				return -EINVAL;254			chip->capture_format = SB_DSP_HI_INPUT_AUTO;255			break;256		}257		chip->capture_format = (rate > 23000) ? SB_DSP_HI_INPUT_AUTO : SB_DSP_LO_INPUT_AUTO;258		break;259	case SB_HW_201:260		if (rate > 13000) {261			chip->capture_format = SB_DSP_HI_INPUT_AUTO;262			break;263		}264		fallthrough;265	case SB_HW_20:266		chip->capture_format = SB_DSP_LO_INPUT_AUTO;267		break;268	case SB_HW_10:269		chip->capture_format = SB_DSP_INPUT;270		break;271	default:272		return -EINVAL;273	}274	if (chip->mode & SB_MODE_CAPTURE_16) {275		format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;276		dma = chip->dma16;277	} else {278		format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;279		chip->mode |= SB_MODE_CAPTURE_8;280		dma = chip->dma8;281	}282	size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);283	count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);284	spin_lock_irqsave(&chip->reg_lock, flags);285	snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);286	if (chip->hardware == SB_HW_JAZZ16)287		snd_sbdsp_command(chip, format);288	else if (stereo)289		snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);290	snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);291	if (stereo) {292		snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);293		spin_lock(&chip->mixer_lock);294		/* save input filter status and turn it off */295		mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT);296		snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20);297		spin_unlock(&chip->mixer_lock);298		/* just use force_mode16 for temporary storate... */299		chip->force_mode16 = mixreg;300	} else {301		snd_sbdsp_command(chip, 256 - runtime->rate_den);302	}303	if (chip->capture_format != SB_DSP_INPUT) {304		if (chip->mode & SB_MODE_PLAYBACK_16)305			count /= 2;306		count--;307		snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);308		snd_sbdsp_command(chip, count & 0xff);309		snd_sbdsp_command(chip, count >> 8);310	}311	spin_unlock_irqrestore(&chip->reg_lock, flags);312	snd_dma_program(dma, runtime->dma_addr,313			size, DMA_MODE_READ | DMA_AUTOINIT);314	return 0;315}316 317static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,318				   int cmd)319{320	unsigned long flags;321	struct snd_sb *chip = snd_pcm_substream_chip(substream);322	unsigned int count;323 324	spin_lock_irqsave(&chip->reg_lock, flags);325	switch (cmd) {326	case SNDRV_PCM_TRIGGER_START:327		snd_sbdsp_command(chip, chip->capture_format);328		if (chip->capture_format == SB_DSP_INPUT) {329			count = chip->c_period_size - 1;330			snd_sbdsp_command(chip, count & 0xff);331			snd_sbdsp_command(chip, count >> 8);332		}333		break;334	case SNDRV_PCM_TRIGGER_STOP:335		if (chip->capture_format == SB_DSP_HI_INPUT_AUTO) {336			struct snd_pcm_runtime *runtime = substream->runtime;337			snd_sbdsp_reset(chip);338			if (runtime->channels > 1) {339				/* restore input filter status */340				spin_lock(&chip->mixer_lock);341				snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16);342				spin_unlock(&chip->mixer_lock);343				/* set hardware to mono mode */344				snd_sbdsp_command(chip, SB_DSP_MONO_8BIT);345			}346		} else {347			snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);348		}349		snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);350	}351	spin_unlock_irqrestore(&chip->reg_lock, flags);352	return 0;353}354 355irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)356{357	struct snd_pcm_substream *substream;358 359	snd_sb_ack_8bit(chip);360	switch (chip->mode) {361	case SB_MODE_PLAYBACK_16:	/* ok.. playback is active */362		if (chip->hardware != SB_HW_JAZZ16)363			break;364		fallthrough;365	case SB_MODE_PLAYBACK_8:366		substream = chip->playback_substream;367		if (chip->playback_format == SB_DSP_OUTPUT)368		    	snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);369		snd_pcm_period_elapsed(substream);370		break;371	case SB_MODE_CAPTURE_16:372		if (chip->hardware != SB_HW_JAZZ16)373			break;374		fallthrough;375	case SB_MODE_CAPTURE_8:376		substream = chip->capture_substream;377		if (chip->capture_format == SB_DSP_INPUT)378		    	snd_sb8_capture_trigger(substream, SNDRV_PCM_TRIGGER_START);379		snd_pcm_period_elapsed(substream);380		break;381	}382	return IRQ_HANDLED;383}384 385static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *substream)386{387	struct snd_sb *chip = snd_pcm_substream_chip(substream);388	size_t ptr;389	int dma;390 391	if (chip->mode & SB_MODE_PLAYBACK_8)392		dma = chip->dma8;393	else if (chip->mode & SB_MODE_PLAYBACK_16)394		dma = chip->dma16;395	else396		return 0;397	ptr = snd_dma_pointer(dma, chip->p_dma_size);398	return bytes_to_frames(substream->runtime, ptr);399}400 401static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *substream)402{403	struct snd_sb *chip = snd_pcm_substream_chip(substream);404	size_t ptr;405	int dma;406 407	if (chip->mode & SB_MODE_CAPTURE_8)408		dma = chip->dma8;409	else if (chip->mode & SB_MODE_CAPTURE_16)410		dma = chip->dma16;411	else412		return 0;413	ptr = snd_dma_pointer(dma, chip->c_dma_size);414	return bytes_to_frames(substream->runtime, ptr);415}416 417/*418 419 */420 421static const struct snd_pcm_hardware snd_sb8_playback =422{423	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |424				 SNDRV_PCM_INFO_MMAP_VALID),425	.formats =		 SNDRV_PCM_FMTBIT_U8,426	.rates =		(SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |427				 SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050),428	.rate_min =		4000,429	.rate_max =		23000,430	.channels_min =		1,431	.channels_max =		1,432	.buffer_bytes_max =	65536,433	.period_bytes_min =	64,434	.period_bytes_max =	65536,435	.periods_min =		1,436	.periods_max =		1024,437	.fifo_size =		0,438};439 440static const struct snd_pcm_hardware snd_sb8_capture =441{442	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |443				 SNDRV_PCM_INFO_MMAP_VALID),444	.formats =		SNDRV_PCM_FMTBIT_U8,445	.rates =		(SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |446				 SNDRV_PCM_RATE_11025),447	.rate_min =		4000,448	.rate_max =		13000,449	.channels_min =		1,450	.channels_max =		1,451	.buffer_bytes_max =	65536,452	.period_bytes_min =	64,453	.period_bytes_max =	65536,454	.periods_min =		1,455	.periods_max =		1024,456	.fifo_size =		0,457};458 459/*460 *461 */462 463static int snd_sb8_open(struct snd_pcm_substream *substream)464{465	struct snd_sb *chip = snd_pcm_substream_chip(substream);466	struct snd_pcm_runtime *runtime = substream->runtime;467	unsigned long flags;468 469	spin_lock_irqsave(&chip->open_lock, flags);470	if (chip->open) {471		spin_unlock_irqrestore(&chip->open_lock, flags);472		return -EAGAIN;473	}474	chip->open |= SB_OPEN_PCM;475	spin_unlock_irqrestore(&chip->open_lock, flags);476	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {477		chip->playback_substream = substream;478		runtime->hw = snd_sb8_playback;479	} else {480		chip->capture_substream = substream;481		runtime->hw = snd_sb8_capture;482	}483	switch (chip->hardware) {484	case SB_HW_JAZZ16:485		if (chip->dma16 == 5 || chip->dma16 == 7)486			runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;487		runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000;488		runtime->hw.rate_min = 4000;489		runtime->hw.rate_max = 50000;490		runtime->hw.channels_max = 2;491		break;492	case SB_HW_PRO:493		runtime->hw.rate_max = 44100;494		runtime->hw.channels_max = 2;495		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,496				    snd_sb8_hw_constraint_rate_channels, NULL,497				    SNDRV_PCM_HW_PARAM_CHANNELS,498				    SNDRV_PCM_HW_PARAM_RATE, -1);499		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,500				     snd_sb8_hw_constraint_channels_rate, NULL,501				     SNDRV_PCM_HW_PARAM_RATE, -1);502		break;503	case SB_HW_201:504		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {505			runtime->hw.rate_max = 44100;506		} else {507			runtime->hw.rate_max = 15000;508		}509		break;510	default:511		break;512	}513	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,514				      &hw_constraints_clock);515	if (chip->dma8 > 3 || chip->dma16 >= 0) {516		snd_pcm_hw_constraint_step(runtime, 0,517					   SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2);518		snd_pcm_hw_constraint_step(runtime, 0,519					   SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2);520		runtime->hw.buffer_bytes_max = 128 * 1024 * 1024;521		runtime->hw.period_bytes_max = 128 * 1024 * 1024;522	}523	return 0;	524}525 526static int snd_sb8_close(struct snd_pcm_substream *substream)527{528	unsigned long flags;529	struct snd_sb *chip = snd_pcm_substream_chip(substream);530 531	chip->playback_substream = NULL;532	chip->capture_substream = NULL;533	spin_lock_irqsave(&chip->open_lock, flags);534	chip->open &= ~SB_OPEN_PCM;535	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)536		chip->mode &= ~SB_MODE_PLAYBACK;537	else538		chip->mode &= ~SB_MODE_CAPTURE;539	spin_unlock_irqrestore(&chip->open_lock, flags);540	return 0;541}542 543/*544 *  Initialization part545 */546 547static const struct snd_pcm_ops snd_sb8_playback_ops = {548	.open =			snd_sb8_open,549	.close =		snd_sb8_close,550	.prepare =		snd_sb8_playback_prepare,551	.trigger =		snd_sb8_playback_trigger,552	.pointer =		snd_sb8_playback_pointer,553};554 555static const struct snd_pcm_ops snd_sb8_capture_ops = {556	.open =			snd_sb8_open,557	.close =		snd_sb8_close,558	.prepare =		snd_sb8_capture_prepare,559	.trigger =		snd_sb8_capture_trigger,560	.pointer =		snd_sb8_capture_pointer,561};562 563int snd_sb8dsp_pcm(struct snd_sb *chip, int device)564{565	struct snd_card *card = chip->card;566	struct snd_pcm *pcm;567	int err;568	size_t max_prealloc = 64 * 1024;569 570	err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm);571	if (err < 0)572		return err;573	sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);574	pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;575	pcm->private_data = chip;576 577	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);578	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);579 580	if (chip->dma8 > 3 || chip->dma16 >= 0)581		max_prealloc = 128 * 1024;582	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,583				       card->dev, 64*1024, max_prealloc);584 585	return 0;586}587 588EXPORT_SYMBOL(snd_sb8dsp_pcm);589EXPORT_SYMBOL(snd_sb8dsp_interrupt);590  /* sb8_midi.c */591EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt);592EXPORT_SYMBOL(snd_sb8dsp_midi);593