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