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                /* fall through */
 120        case SB_HW_201:
 121                if (rate > 23000) {
 122                        chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
 123                        break;
 124                }
 125                /* fall through */
 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_hw_params(struct snd_pcm_substream *substream,
 229                             struct snd_pcm_hw_params *hw_params)
 230{
 231        return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
 232}
 233
 234static int snd_sb8_hw_free(struct snd_pcm_substream *substream)
 235{
 236        snd_pcm_lib_free_pages(substream);
 237        return 0;
 238}
 239
 240static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
 241{
 242        unsigned long flags;
 243        struct snd_sb *chip = snd_pcm_substream_chip(substream);
 244        struct snd_pcm_runtime *runtime = substream->runtime;
 245        unsigned int mixreg, rate, size, count;
 246        unsigned char format;
 247        unsigned char stereo = runtime->channels > 1;
 248        int dma;
 249
 250        rate = runtime->rate;
 251        switch (chip->hardware) {
 252        case SB_HW_JAZZ16:
 253                if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
 254                        if (chip->mode & SB_MODE_PLAYBACK_16)
 255                                return -EBUSY;
 256                        else
 257                                chip->mode |= SB_MODE_CAPTURE_16;
 258                }
 259                chip->capture_format = SB_DSP_LO_INPUT_AUTO;
 260                break;
 261        case SB_HW_PRO:
 262                if (runtime->channels > 1) {
 263                        if (snd_BUG_ON(rate != SB8_RATE(11025) &&
 264                                       rate != SB8_RATE(22050)))
 265                                return -EINVAL;
 266                        chip->capture_format = SB_DSP_HI_INPUT_AUTO;
 267                        break;
 268                }
 269                chip->capture_format = (rate > 23000) ? SB_DSP_HI_INPUT_AUTO : SB_DSP_LO_INPUT_AUTO;
 270                break;
 271        case SB_HW_201:
 272                if (rate > 13000) {
 273                        chip->capture_format = SB_DSP_HI_INPUT_AUTO;
 274                        break;
 275                }
 276                /* fall through */
 277        case SB_HW_20:
 278                chip->capture_format = SB_DSP_LO_INPUT_AUTO;
 279                break;
 280        case SB_HW_10:
 281                chip->capture_format = SB_DSP_INPUT;
 282                break;
 283        default:
 284                return -EINVAL;
 285        }
 286        if (chip->mode & SB_MODE_CAPTURE_16) {
 287                format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
 288                dma = chip->dma16;
 289        } else {
 290                format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
 291                chip->mode |= SB_MODE_CAPTURE_8;
 292                dma = chip->dma8;
 293        }
 294        size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
 295        count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
 296        spin_lock_irqsave(&chip->reg_lock, flags);
 297        snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
 298        if (chip->hardware == SB_HW_JAZZ16)
 299                snd_sbdsp_command(chip, format);
 300        else if (stereo)
 301                snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
 302        snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
 303        if (stereo) {
 304                snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
 305                spin_lock(&chip->mixer_lock);
 306                /* save input filter status and turn it off */
 307                mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT);
 308                snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20);
 309                spin_unlock(&chip->mixer_lock);
 310                /* just use force_mode16 for temporary storate... */
 311                chip->force_mode16 = mixreg;
 312        } else {
 313                snd_sbdsp_command(chip, 256 - runtime->rate_den);
 314        }
 315        if (chip->capture_format != SB_DSP_INPUT) {
 316                if (chip->mode & SB_MODE_PLAYBACK_16)
 317                        count /= 2;
 318                count--;
 319                snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
 320                snd_sbdsp_command(chip, count & 0xff);
 321                snd_sbdsp_command(chip, count >> 8);
 322        }
 323        spin_unlock_irqrestore(&chip->reg_lock, flags);
 324        snd_dma_program(dma, runtime->dma_addr,
 325                        size, DMA_MODE_READ | DMA_AUTOINIT);
 326        return 0;
 327}
 328
 329static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
 330                                   int cmd)
 331{
 332        unsigned long flags;
 333        struct snd_sb *chip = snd_pcm_substream_chip(substream);
 334        unsigned int count;
 335
 336        spin_lock_irqsave(&chip->reg_lock, flags);
 337        switch (cmd) {
 338        case SNDRV_PCM_TRIGGER_START:
 339                snd_sbdsp_command(chip, chip->capture_format);
 340                if (chip->capture_format == SB_DSP_INPUT) {
 341                        count = chip->c_period_size - 1;
 342                        snd_sbdsp_command(chip, count & 0xff);
 343                        snd_sbdsp_command(chip, count >> 8);
 344                }
 345                break;
 346        case SNDRV_PCM_TRIGGER_STOP:
 347                if (chip->capture_format == SB_DSP_HI_INPUT_AUTO) {
 348                        struct snd_pcm_runtime *runtime = substream->runtime;
 349                        snd_sbdsp_reset(chip);
 350                        if (runtime->channels > 1) {
 351                                /* restore input filter status */
 352                                spin_lock(&chip->mixer_lock);
 353                                snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16);
 354                                spin_unlock(&chip->mixer_lock);
 355                                /* set hardware to mono mode */
 356                                snd_sbdsp_command(chip, SB_DSP_MONO_8BIT);
 357                        }
 358                } else {
 359                        snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
 360                }
 361                snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
 362        }
 363        spin_unlock_irqrestore(&chip->reg_lock, flags);
 364        return 0;
 365}
 366
 367irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
 368{
 369        struct snd_pcm_substream *substream;
 370
 371        snd_sb_ack_8bit(chip);
 372        switch (chip->mode) {
 373        case SB_MODE_PLAYBACK_16:       /* ok.. playback is active */
 374                if (chip->hardware != SB_HW_JAZZ16)
 375                        break;
 376                /* fall through */
 377        case SB_MODE_PLAYBACK_8:
 378                substream = chip->playback_substream;
 379                if (chip->playback_format == SB_DSP_OUTPUT)
 380                        snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
 381                snd_pcm_period_elapsed(substream);
 382                break;
 383        case SB_MODE_CAPTURE_16:
 384                if (chip->hardware != SB_HW_JAZZ16)
 385                        break;
 386                /* fall through */
 387        case SB_MODE_CAPTURE_8:
 388                substream = chip->capture_substream;
 389                if (chip->capture_format == SB_DSP_INPUT)
 390                        snd_sb8_capture_trigger(substream, SNDRV_PCM_TRIGGER_START);
 391                snd_pcm_period_elapsed(substream);
 392                break;
 393        }
 394        return IRQ_HANDLED;
 395}
 396
 397static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *substream)
 398{
 399        struct snd_sb *chip = snd_pcm_substream_chip(substream);
 400        size_t ptr;
 401        int dma;
 402
 403        if (chip->mode & SB_MODE_PLAYBACK_8)
 404                dma = chip->dma8;
 405        else if (chip->mode & SB_MODE_PLAYBACK_16)
 406                dma = chip->dma16;
 407        else
 408                return 0;
 409        ptr = snd_dma_pointer(dma, chip->p_dma_size);
 410        return bytes_to_frames(substream->runtime, ptr);
 411}
 412
 413static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *substream)
 414{
 415        struct snd_sb *chip = snd_pcm_substream_chip(substream);
 416        size_t ptr;
 417        int dma;
 418
 419        if (chip->mode & SB_MODE_CAPTURE_8)
 420                dma = chip->dma8;
 421        else if (chip->mode & SB_MODE_CAPTURE_16)
 422                dma = chip->dma16;
 423        else
 424                return 0;
 425        ptr = snd_dma_pointer(dma, chip->c_dma_size);
 426        return bytes_to_frames(substream->runtime, ptr);
 427}
 428
 429/*
 430
 431 */
 432
 433static const struct snd_pcm_hardware snd_sb8_playback =
 434{
 435        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 436                                 SNDRV_PCM_INFO_MMAP_VALID),
 437        .formats =               SNDRV_PCM_FMTBIT_U8,
 438        .rates =                (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |
 439                                 SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050),
 440        .rate_min =             4000,
 441        .rate_max =             23000,
 442        .channels_min =         1,
 443        .channels_max =         1,
 444        .buffer_bytes_max =     65536,
 445        .period_bytes_min =     64,
 446        .period_bytes_max =     65536,
 447        .periods_min =          1,
 448        .periods_max =          1024,
 449        .fifo_size =            0,
 450};
 451
 452static const struct snd_pcm_hardware snd_sb8_capture =
 453{
 454        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 455                                 SNDRV_PCM_INFO_MMAP_VALID),
 456        .formats =              SNDRV_PCM_FMTBIT_U8,
 457        .rates =                (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |
 458                                 SNDRV_PCM_RATE_11025),
 459        .rate_min =             4000,
 460        .rate_max =             13000,
 461        .channels_min =         1,
 462        .channels_max =         1,
 463        .buffer_bytes_max =     65536,
 464        .period_bytes_min =     64,
 465        .period_bytes_max =     65536,
 466        .periods_min =          1,
 467        .periods_max =          1024,
 468        .fifo_size =            0,
 469};
 470
 471/*
 472 *
 473 */
 474 
 475static int snd_sb8_open(struct snd_pcm_substream *substream)
 476{
 477        struct snd_sb *chip = snd_pcm_substream_chip(substream);
 478        struct snd_pcm_runtime *runtime = substream->runtime;
 479        unsigned long flags;
 480
 481        spin_lock_irqsave(&chip->open_lock, flags);
 482        if (chip->open) {
 483                spin_unlock_irqrestore(&chip->open_lock, flags);
 484                return -EAGAIN;
 485        }
 486        chip->open |= SB_OPEN_PCM;
 487        spin_unlock_irqrestore(&chip->open_lock, flags);
 488        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 489                chip->playback_substream = substream;
 490                runtime->hw = snd_sb8_playback;
 491        } else {
 492                chip->capture_substream = substream;
 493                runtime->hw = snd_sb8_capture;
 494        }
 495        switch (chip->hardware) {
 496        case SB_HW_JAZZ16:
 497                if (chip->dma16 == 5 || chip->dma16 == 7)
 498                        runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
 499                runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000;
 500                runtime->hw.rate_min = 4000;
 501                runtime->hw.rate_max = 50000;
 502                runtime->hw.channels_max = 2;
 503                break;
 504        case SB_HW_PRO:
 505                runtime->hw.rate_max = 44100;
 506                runtime->hw.channels_max = 2;
 507                snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 508                                    snd_sb8_hw_constraint_rate_channels, NULL,
 509                                    SNDRV_PCM_HW_PARAM_CHANNELS,
 510                                    SNDRV_PCM_HW_PARAM_RATE, -1);
 511                snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 512                                     snd_sb8_hw_constraint_channels_rate, NULL,
 513                                     SNDRV_PCM_HW_PARAM_RATE, -1);
 514                break;
 515        case SB_HW_201:
 516                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 517                        runtime->hw.rate_max = 44100;
 518                } else {
 519                        runtime->hw.rate_max = 15000;
 520                }
 521        default:
 522                break;
 523        }
 524        snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 525                                      &hw_constraints_clock);
 526        if (chip->dma8 > 3 || chip->dma16 >= 0) {
 527                snd_pcm_hw_constraint_step(runtime, 0,
 528                                           SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2);
 529                snd_pcm_hw_constraint_step(runtime, 0,
 530                                           SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2);
 531                runtime->hw.buffer_bytes_max = 128 * 1024 * 1024;
 532                runtime->hw.period_bytes_max = 128 * 1024 * 1024;
 533        }
 534        return 0;       
 535}
 536
 537static int snd_sb8_close(struct snd_pcm_substream *substream)
 538{
 539        unsigned long flags;
 540        struct snd_sb *chip = snd_pcm_substream_chip(substream);
 541
 542        chip->playback_substream = NULL;
 543        chip->capture_substream = NULL;
 544        spin_lock_irqsave(&chip->open_lock, flags);
 545        chip->open &= ~SB_OPEN_PCM;
 546        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 547                chip->mode &= ~SB_MODE_PLAYBACK;
 548        else
 549                chip->mode &= ~SB_MODE_CAPTURE;
 550        spin_unlock_irqrestore(&chip->open_lock, flags);
 551        return 0;
 552}
 553
 554/*
 555 *  Initialization part
 556 */
 557 
 558static const struct snd_pcm_ops snd_sb8_playback_ops = {
 559        .open =                 snd_sb8_open,
 560        .close =                snd_sb8_close,
 561        .ioctl =                snd_pcm_lib_ioctl,
 562        .hw_params =            snd_sb8_hw_params,
 563        .hw_free =              snd_sb8_hw_free,
 564        .prepare =              snd_sb8_playback_prepare,
 565        .trigger =              snd_sb8_playback_trigger,
 566        .pointer =              snd_sb8_playback_pointer,
 567};
 568
 569static const struct snd_pcm_ops snd_sb8_capture_ops = {
 570        .open =                 snd_sb8_open,
 571        .close =                snd_sb8_close,
 572        .ioctl =                snd_pcm_lib_ioctl,
 573        .hw_params =            snd_sb8_hw_params,
 574        .hw_free =              snd_sb8_hw_free,
 575        .prepare =              snd_sb8_capture_prepare,
 576        .trigger =              snd_sb8_capture_trigger,
 577        .pointer =              snd_sb8_capture_pointer,
 578};
 579
 580int snd_sb8dsp_pcm(struct snd_sb *chip, int device)
 581{
 582        struct snd_card *card = chip->card;
 583        struct snd_pcm *pcm;
 584        int err;
 585        size_t max_prealloc = 64 * 1024;
 586
 587        if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0)
 588                return err;
 589        sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
 590        pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
 591        pcm->private_data = chip;
 592
 593        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
 594        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
 595
 596        if (chip->dma8 > 3 || chip->dma16 >= 0)
 597                max_prealloc = 128 * 1024;
 598        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
 599                                              card->dev,
 600                                              64*1024, max_prealloc);
 601
 602        return 0;
 603}
 604
 605EXPORT_SYMBOL(snd_sb8dsp_pcm);
 606EXPORT_SYMBOL(snd_sb8dsp_interrupt);
 607  /* sb8_midi.c */
 608EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt);
 609EXPORT_SYMBOL(snd_sb8dsp_midi);
 610