linux/sound/isa/sb/sb8_main.c
<<
>>
Prefs
   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);
 593