static inline u8 snd_als4_cr_read(struct snd_sb *chip, enum als4k_cr_t reg) { /* NOTE: assumes chip->mixer_lock to be locked externally already! */ return snd_sbmixer_read(chip, reg | 0xc0); }
static int snd_sb8_hw_constraint_channels_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); if (r->min > SB8_RATE(22050) || r->max <= SB8_RATE(11025)) { struct snd_interval t = { .min = 1, .max = 1 }; return snd_interval_refine(hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS), &t); } return 0; } static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) { unsigned long flags; struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int mixreg, rate, size, count; unsigned char format; unsigned char stereo = runtime->channels > 1; int dma; rate = runtime->rate; switch (chip->hardware) { case SB_HW_JAZZ16: if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { if (chip->mode & SB_MODE_CAPTURE_16) return -EBUSY; else chip->mode |= SB_MODE_PLAYBACK_16; } chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; break; case SB_HW_PRO: if (runtime->channels > 1) { if (snd_BUG_ON(rate != SB8_RATE(11025) && rate != SB8_RATE(22050))) return -EINVAL; chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; break; } /* fallthru */ case SB_HW_201: if (rate > 23000) { chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; break; } /* fallthru */ case SB_HW_20: chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; break; case SB_HW_10: chip->playback_format = SB_DSP_OUTPUT; break; default: return -EINVAL; } if (chip->mode & SB_MODE_PLAYBACK_16) { format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; dma = chip->dma16; } else { format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; chip->mode |= SB_MODE_PLAYBACK_8; dma = chip->dma8; } size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); spin_lock_irqsave(&chip->reg_lock, flags); snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); if (chip->hardware == SB_HW_JAZZ16) snd_sbdsp_command(chip, format); else if (stereo) { /* set playback stereo mode */ spin_lock(&chip->mixer_lock); mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02); spin_unlock(&chip->mixer_lock); /* Soundblaster hardware programming reference guide, 3-23 */ snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); runtime->dma_area[0] = 0x80; snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); /* force interrupt */ snd_sbdsp_command(chip, SB_DSP_OUTPUT); snd_sbdsp_command(chip, 0); snd_sbdsp_command(chip, 0); } snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); if (stereo) { snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); spin_lock(&chip->mixer_lock); /* save output filter status and turn it off */ mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT); snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20); spin_unlock(&chip->mixer_lock); /* just use force_mode16 for temporary storate... */ chip->force_mode16 = mixreg; } else { snd_sbdsp_command(chip, 256 - runtime->rate_den); } if (chip->playback_format != SB_DSP_OUTPUT) { if (chip->mode & SB_MODE_PLAYBACK_16) count /= 2; count--; snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); snd_sbdsp_command(chip, count & 0xff); snd_sbdsp_command(chip, count >> 8); } spin_unlock_irqrestore(&chip->reg_lock, flags); snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); return 0; }