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

sb8_main.c (17103B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      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 clones
      7 *  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	1000000
     32#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			else
    107				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			else
    245				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	else
    396		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	else
    412		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	else
    538		chip->mode &= ~SB_MODE_CAPTURE;
    539	spin_unlock_irqrestore(&chip->open_lock, flags);
    540	return 0;
    541}
    542
    543/*
    544 *  Initialization part
    545 */
    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);