Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0004  *                   Uros Bizjak <uros@kss-loka.si>
0005  *
0006  *  Routines for control of 8-bit SoundBlaster cards and clones
0007  *  Please note: I don't have access to old SB8 soundcards.
0008  *
0009  * --
0010  *
0011  * Thu Apr 29 20:36:17 BST 1999 George David Morrison <gdm@gedamo.demon.co.uk>
0012  *   DSP can't respond to commands whilst in "high speed" mode. Caused 
0013  *   glitching during playback. Fixed.
0014  *
0015  * Wed Jul 12 22:02:55 CEST 2000 Uros Bizjak <uros@kss-loka.si>
0016  *   Cleaned up and rewrote lowlevel routines.
0017  */
0018 
0019 #include <linux/io.h>
0020 #include <asm/dma.h>
0021 #include <linux/init.h>
0022 #include <linux/time.h>
0023 #include <linux/module.h>
0024 #include <sound/core.h>
0025 #include <sound/sb.h>
0026 
0027 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Uros Bizjak <uros@kss-loka.si>");
0028 MODULE_DESCRIPTION("Routines for control of 8-bit SoundBlaster cards and clones");
0029 MODULE_LICENSE("GPL");
0030 
0031 #define SB8_CLOCK   1000000
0032 #define SB8_DEN(v)  ((SB8_CLOCK + (v) / 2) / (v))
0033 #define SB8_RATE(v) (SB8_CLOCK / SB8_DEN(v))
0034 
0035 static const struct snd_ratnum clock = {
0036     .num = SB8_CLOCK,
0037     .den_min = 1,
0038     .den_max = 256,
0039     .den_step = 1,
0040 };
0041 
0042 static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clock = {
0043     .nrats = 1,
0044     .rats = &clock,
0045 };
0046 
0047 static const struct snd_ratnum stereo_clocks[] = {
0048     {
0049         .num = SB8_CLOCK,
0050         .den_min = SB8_DEN(22050),
0051         .den_max = SB8_DEN(22050),
0052         .den_step = 1,
0053     },
0054     {
0055         .num = SB8_CLOCK,
0056         .den_min = SB8_DEN(11025),
0057         .den_max = SB8_DEN(11025),
0058         .den_step = 1,
0059     }
0060 };
0061 
0062 static int snd_sb8_hw_constraint_rate_channels(struct snd_pcm_hw_params *params,
0063                            struct snd_pcm_hw_rule *rule)
0064 {
0065     struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
0066     if (c->min > 1) {
0067         unsigned int num = 0, den = 0;
0068         int err = snd_interval_ratnum(hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE),
0069                       2, stereo_clocks, &num, &den);
0070         if (err >= 0 && den) {
0071             params->rate_num = num;
0072             params->rate_den = den;
0073         }
0074         return err;
0075     }
0076     return 0;
0077 }
0078 
0079 static int snd_sb8_hw_constraint_channels_rate(struct snd_pcm_hw_params *params,
0080                            struct snd_pcm_hw_rule *rule)
0081 {
0082     struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
0083     if (r->min > SB8_RATE(22050) || r->max <= SB8_RATE(11025)) {
0084         struct snd_interval t = { .min = 1, .max = 1 };
0085         return snd_interval_refine(hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS), &t);
0086     }
0087     return 0;
0088 }
0089 
0090 static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
0091 {
0092     unsigned long flags;
0093     struct snd_sb *chip = snd_pcm_substream_chip(substream);
0094     struct snd_pcm_runtime *runtime = substream->runtime;
0095     unsigned int mixreg, rate, size, count;
0096     unsigned char format;
0097     unsigned char stereo = runtime->channels > 1;
0098     int dma;
0099 
0100     rate = runtime->rate;
0101     switch (chip->hardware) {
0102     case SB_HW_JAZZ16:
0103         if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
0104             if (chip->mode & SB_MODE_CAPTURE_16)
0105                 return -EBUSY;
0106             else
0107                 chip->mode |= SB_MODE_PLAYBACK_16;
0108         }
0109         chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
0110         break;
0111     case SB_HW_PRO:
0112         if (runtime->channels > 1) {
0113             if (snd_BUG_ON(rate != SB8_RATE(11025) &&
0114                        rate != SB8_RATE(22050)))
0115                 return -EINVAL;
0116             chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
0117             break;
0118         }
0119         fallthrough;
0120     case SB_HW_201:
0121         if (rate > 23000) {
0122             chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
0123             break;
0124         }
0125         fallthrough;
0126     case SB_HW_20:
0127         chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
0128         break;
0129     case SB_HW_10:
0130         chip->playback_format = SB_DSP_OUTPUT;
0131         break;
0132     default:
0133         return -EINVAL;
0134     }
0135     if (chip->mode & SB_MODE_PLAYBACK_16) {
0136         format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
0137         dma = chip->dma16;
0138     } else {
0139         format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
0140         chip->mode |= SB_MODE_PLAYBACK_8;
0141         dma = chip->dma8;
0142     }
0143     size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
0144     count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
0145     spin_lock_irqsave(&chip->reg_lock, flags);
0146     snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
0147     if (chip->hardware == SB_HW_JAZZ16)
0148         snd_sbdsp_command(chip, format);
0149     else if (stereo) {
0150         /* set playback stereo mode */
0151         spin_lock(&chip->mixer_lock);
0152         mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
0153         snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02);
0154         spin_unlock(&chip->mixer_lock);
0155 
0156         /* Soundblaster hardware programming reference guide, 3-23 */
0157         snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
0158         runtime->dma_area[0] = 0x80;
0159         snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
0160         /* force interrupt */
0161         snd_sbdsp_command(chip, SB_DSP_OUTPUT);
0162         snd_sbdsp_command(chip, 0);
0163         snd_sbdsp_command(chip, 0);
0164     }
0165     snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
0166     if (stereo) {
0167         snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
0168         spin_lock(&chip->mixer_lock);
0169         /* save output filter status and turn it off */
0170         mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT);
0171         snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20);
0172         spin_unlock(&chip->mixer_lock);
0173         /* just use force_mode16 for temporary storate... */
0174         chip->force_mode16 = mixreg;
0175     } else {
0176         snd_sbdsp_command(chip, 256 - runtime->rate_den);
0177     }
0178     if (chip->playback_format != SB_DSP_OUTPUT) {
0179         if (chip->mode & SB_MODE_PLAYBACK_16)
0180             count /= 2;
0181         count--;
0182         snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
0183         snd_sbdsp_command(chip, count & 0xff);
0184         snd_sbdsp_command(chip, count >> 8);
0185     }
0186     spin_unlock_irqrestore(&chip->reg_lock, flags);
0187     snd_dma_program(dma, runtime->dma_addr,
0188             size, DMA_MODE_WRITE | DMA_AUTOINIT);
0189     return 0;
0190 }
0191 
0192 static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,
0193                     int cmd)
0194 {
0195     unsigned long flags;
0196     struct snd_sb *chip = snd_pcm_substream_chip(substream);
0197     unsigned int count;
0198 
0199     spin_lock_irqsave(&chip->reg_lock, flags);
0200     switch (cmd) {
0201     case SNDRV_PCM_TRIGGER_START:
0202         snd_sbdsp_command(chip, chip->playback_format);
0203         if (chip->playback_format == SB_DSP_OUTPUT) {
0204             count = chip->p_period_size - 1;
0205             snd_sbdsp_command(chip, count & 0xff);
0206             snd_sbdsp_command(chip, count >> 8);
0207         }
0208         break;
0209     case SNDRV_PCM_TRIGGER_STOP:
0210         if (chip->playback_format == SB_DSP_HI_OUTPUT_AUTO) {
0211             struct snd_pcm_runtime *runtime = substream->runtime;
0212             snd_sbdsp_reset(chip);
0213             if (runtime->channels > 1) {
0214                 spin_lock(&chip->mixer_lock);
0215                 /* restore output filter and set hardware to mono mode */ 
0216                 snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02);
0217                 spin_unlock(&chip->mixer_lock);
0218             }
0219         } else {
0220             snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
0221         }
0222         snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
0223     }
0224     spin_unlock_irqrestore(&chip->reg_lock, flags);
0225     return 0;
0226 }
0227 
0228 static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
0229 {
0230     unsigned long flags;
0231     struct snd_sb *chip = snd_pcm_substream_chip(substream);
0232     struct snd_pcm_runtime *runtime = substream->runtime;
0233     unsigned int mixreg, rate, size, count;
0234     unsigned char format;
0235     unsigned char stereo = runtime->channels > 1;
0236     int dma;
0237 
0238     rate = runtime->rate;
0239     switch (chip->hardware) {
0240     case SB_HW_JAZZ16:
0241         if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
0242             if (chip->mode & SB_MODE_PLAYBACK_16)
0243                 return -EBUSY;
0244             else
0245                 chip->mode |= SB_MODE_CAPTURE_16;
0246         }
0247         chip->capture_format = SB_DSP_LO_INPUT_AUTO;
0248         break;
0249     case SB_HW_PRO:
0250         if (runtime->channels > 1) {
0251             if (snd_BUG_ON(rate != SB8_RATE(11025) &&
0252                        rate != SB8_RATE(22050)))
0253                 return -EINVAL;
0254             chip->capture_format = SB_DSP_HI_INPUT_AUTO;
0255             break;
0256         }
0257         chip->capture_format = (rate > 23000) ? SB_DSP_HI_INPUT_AUTO : SB_DSP_LO_INPUT_AUTO;
0258         break;
0259     case SB_HW_201:
0260         if (rate > 13000) {
0261             chip->capture_format = SB_DSP_HI_INPUT_AUTO;
0262             break;
0263         }
0264         fallthrough;
0265     case SB_HW_20:
0266         chip->capture_format = SB_DSP_LO_INPUT_AUTO;
0267         break;
0268     case SB_HW_10:
0269         chip->capture_format = SB_DSP_INPUT;
0270         break;
0271     default:
0272         return -EINVAL;
0273     }
0274     if (chip->mode & SB_MODE_CAPTURE_16) {
0275         format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
0276         dma = chip->dma16;
0277     } else {
0278         format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
0279         chip->mode |= SB_MODE_CAPTURE_8;
0280         dma = chip->dma8;
0281     }
0282     size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
0283     count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
0284     spin_lock_irqsave(&chip->reg_lock, flags);
0285     snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
0286     if (chip->hardware == SB_HW_JAZZ16)
0287         snd_sbdsp_command(chip, format);
0288     else if (stereo)
0289         snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
0290     snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
0291     if (stereo) {
0292         snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
0293         spin_lock(&chip->mixer_lock);
0294         /* save input filter status and turn it off */
0295         mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT);
0296         snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20);
0297         spin_unlock(&chip->mixer_lock);
0298         /* just use force_mode16 for temporary storate... */
0299         chip->force_mode16 = mixreg;
0300     } else {
0301         snd_sbdsp_command(chip, 256 - runtime->rate_den);
0302     }
0303     if (chip->capture_format != SB_DSP_INPUT) {
0304         if (chip->mode & SB_MODE_PLAYBACK_16)
0305             count /= 2;
0306         count--;
0307         snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
0308         snd_sbdsp_command(chip, count & 0xff);
0309         snd_sbdsp_command(chip, count >> 8);
0310     }
0311     spin_unlock_irqrestore(&chip->reg_lock, flags);
0312     snd_dma_program(dma, runtime->dma_addr,
0313             size, DMA_MODE_READ | DMA_AUTOINIT);
0314     return 0;
0315 }
0316 
0317 static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
0318                    int cmd)
0319 {
0320     unsigned long flags;
0321     struct snd_sb *chip = snd_pcm_substream_chip(substream);
0322     unsigned int count;
0323 
0324     spin_lock_irqsave(&chip->reg_lock, flags);
0325     switch (cmd) {
0326     case SNDRV_PCM_TRIGGER_START:
0327         snd_sbdsp_command(chip, chip->capture_format);
0328         if (chip->capture_format == SB_DSP_INPUT) {
0329             count = chip->c_period_size - 1;
0330             snd_sbdsp_command(chip, count & 0xff);
0331             snd_sbdsp_command(chip, count >> 8);
0332         }
0333         break;
0334     case SNDRV_PCM_TRIGGER_STOP:
0335         if (chip->capture_format == SB_DSP_HI_INPUT_AUTO) {
0336             struct snd_pcm_runtime *runtime = substream->runtime;
0337             snd_sbdsp_reset(chip);
0338             if (runtime->channels > 1) {
0339                 /* restore input filter status */
0340                 spin_lock(&chip->mixer_lock);
0341                 snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16);
0342                 spin_unlock(&chip->mixer_lock);
0343                 /* set hardware to mono mode */
0344                 snd_sbdsp_command(chip, SB_DSP_MONO_8BIT);
0345             }
0346         } else {
0347             snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
0348         }
0349         snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
0350     }
0351     spin_unlock_irqrestore(&chip->reg_lock, flags);
0352     return 0;
0353 }
0354 
0355 irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
0356 {
0357     struct snd_pcm_substream *substream;
0358 
0359     snd_sb_ack_8bit(chip);
0360     switch (chip->mode) {
0361     case SB_MODE_PLAYBACK_16:   /* ok.. playback is active */
0362         if (chip->hardware != SB_HW_JAZZ16)
0363             break;
0364         fallthrough;
0365     case SB_MODE_PLAYBACK_8:
0366         substream = chip->playback_substream;
0367         if (chip->playback_format == SB_DSP_OUTPUT)
0368                 snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
0369         snd_pcm_period_elapsed(substream);
0370         break;
0371     case SB_MODE_CAPTURE_16:
0372         if (chip->hardware != SB_HW_JAZZ16)
0373             break;
0374         fallthrough;
0375     case SB_MODE_CAPTURE_8:
0376         substream = chip->capture_substream;
0377         if (chip->capture_format == SB_DSP_INPUT)
0378                 snd_sb8_capture_trigger(substream, SNDRV_PCM_TRIGGER_START);
0379         snd_pcm_period_elapsed(substream);
0380         break;
0381     }
0382     return IRQ_HANDLED;
0383 }
0384 
0385 static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *substream)
0386 {
0387     struct snd_sb *chip = snd_pcm_substream_chip(substream);
0388     size_t ptr;
0389     int dma;
0390 
0391     if (chip->mode & SB_MODE_PLAYBACK_8)
0392         dma = chip->dma8;
0393     else if (chip->mode & SB_MODE_PLAYBACK_16)
0394         dma = chip->dma16;
0395     else
0396         return 0;
0397     ptr = snd_dma_pointer(dma, chip->p_dma_size);
0398     return bytes_to_frames(substream->runtime, ptr);
0399 }
0400 
0401 static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *substream)
0402 {
0403     struct snd_sb *chip = snd_pcm_substream_chip(substream);
0404     size_t ptr;
0405     int dma;
0406 
0407     if (chip->mode & SB_MODE_CAPTURE_8)
0408         dma = chip->dma8;
0409     else if (chip->mode & SB_MODE_CAPTURE_16)
0410         dma = chip->dma16;
0411     else
0412         return 0;
0413     ptr = snd_dma_pointer(dma, chip->c_dma_size);
0414     return bytes_to_frames(substream->runtime, ptr);
0415 }
0416 
0417 /*
0418 
0419  */
0420 
0421 static const struct snd_pcm_hardware snd_sb8_playback =
0422 {
0423     .info =         (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
0424                  SNDRV_PCM_INFO_MMAP_VALID),
0425     .formats =       SNDRV_PCM_FMTBIT_U8,
0426     .rates =        (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |
0427                  SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050),
0428     .rate_min =     4000,
0429     .rate_max =     23000,
0430     .channels_min =     1,
0431     .channels_max =     1,
0432     .buffer_bytes_max = 65536,
0433     .period_bytes_min = 64,
0434     .period_bytes_max = 65536,
0435     .periods_min =      1,
0436     .periods_max =      1024,
0437     .fifo_size =        0,
0438 };
0439 
0440 static const struct snd_pcm_hardware snd_sb8_capture =
0441 {
0442     .info =         (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
0443                  SNDRV_PCM_INFO_MMAP_VALID),
0444     .formats =      SNDRV_PCM_FMTBIT_U8,
0445     .rates =        (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |
0446                  SNDRV_PCM_RATE_11025),
0447     .rate_min =     4000,
0448     .rate_max =     13000,
0449     .channels_min =     1,
0450     .channels_max =     1,
0451     .buffer_bytes_max = 65536,
0452     .period_bytes_min = 64,
0453     .period_bytes_max = 65536,
0454     .periods_min =      1,
0455     .periods_max =      1024,
0456     .fifo_size =        0,
0457 };
0458 
0459 /*
0460  *
0461  */
0462  
0463 static int snd_sb8_open(struct snd_pcm_substream *substream)
0464 {
0465     struct snd_sb *chip = snd_pcm_substream_chip(substream);
0466     struct snd_pcm_runtime *runtime = substream->runtime;
0467     unsigned long flags;
0468 
0469     spin_lock_irqsave(&chip->open_lock, flags);
0470     if (chip->open) {
0471         spin_unlock_irqrestore(&chip->open_lock, flags);
0472         return -EAGAIN;
0473     }
0474     chip->open |= SB_OPEN_PCM;
0475     spin_unlock_irqrestore(&chip->open_lock, flags);
0476     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0477         chip->playback_substream = substream;
0478         runtime->hw = snd_sb8_playback;
0479     } else {
0480         chip->capture_substream = substream;
0481         runtime->hw = snd_sb8_capture;
0482     }
0483     switch (chip->hardware) {
0484     case SB_HW_JAZZ16:
0485         if (chip->dma16 == 5 || chip->dma16 == 7)
0486             runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
0487         runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000;
0488         runtime->hw.rate_min = 4000;
0489         runtime->hw.rate_max = 50000;
0490         runtime->hw.channels_max = 2;
0491         break;
0492     case SB_HW_PRO:
0493         runtime->hw.rate_max = 44100;
0494         runtime->hw.channels_max = 2;
0495         snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
0496                     snd_sb8_hw_constraint_rate_channels, NULL,
0497                     SNDRV_PCM_HW_PARAM_CHANNELS,
0498                     SNDRV_PCM_HW_PARAM_RATE, -1);
0499         snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
0500                      snd_sb8_hw_constraint_channels_rate, NULL,
0501                      SNDRV_PCM_HW_PARAM_RATE, -1);
0502         break;
0503     case SB_HW_201:
0504         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0505             runtime->hw.rate_max = 44100;
0506         } else {
0507             runtime->hw.rate_max = 15000;
0508         }
0509         break;
0510     default:
0511         break;
0512     }
0513     snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
0514                       &hw_constraints_clock);
0515     if (chip->dma8 > 3 || chip->dma16 >= 0) {
0516         snd_pcm_hw_constraint_step(runtime, 0,
0517                        SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2);
0518         snd_pcm_hw_constraint_step(runtime, 0,
0519                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2);
0520         runtime->hw.buffer_bytes_max = 128 * 1024 * 1024;
0521         runtime->hw.period_bytes_max = 128 * 1024 * 1024;
0522     }
0523     return 0;   
0524 }
0525 
0526 static int snd_sb8_close(struct snd_pcm_substream *substream)
0527 {
0528     unsigned long flags;
0529     struct snd_sb *chip = snd_pcm_substream_chip(substream);
0530 
0531     chip->playback_substream = NULL;
0532     chip->capture_substream = NULL;
0533     spin_lock_irqsave(&chip->open_lock, flags);
0534     chip->open &= ~SB_OPEN_PCM;
0535     if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
0536         chip->mode &= ~SB_MODE_PLAYBACK;
0537     else
0538         chip->mode &= ~SB_MODE_CAPTURE;
0539     spin_unlock_irqrestore(&chip->open_lock, flags);
0540     return 0;
0541 }
0542 
0543 /*
0544  *  Initialization part
0545  */
0546  
0547 static const struct snd_pcm_ops snd_sb8_playback_ops = {
0548     .open =         snd_sb8_open,
0549     .close =        snd_sb8_close,
0550     .prepare =      snd_sb8_playback_prepare,
0551     .trigger =      snd_sb8_playback_trigger,
0552     .pointer =      snd_sb8_playback_pointer,
0553 };
0554 
0555 static const struct snd_pcm_ops snd_sb8_capture_ops = {
0556     .open =         snd_sb8_open,
0557     .close =        snd_sb8_close,
0558     .prepare =      snd_sb8_capture_prepare,
0559     .trigger =      snd_sb8_capture_trigger,
0560     .pointer =      snd_sb8_capture_pointer,
0561 };
0562 
0563 int snd_sb8dsp_pcm(struct snd_sb *chip, int device)
0564 {
0565     struct snd_card *card = chip->card;
0566     struct snd_pcm *pcm;
0567     int err;
0568     size_t max_prealloc = 64 * 1024;
0569 
0570     err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm);
0571     if (err < 0)
0572         return err;
0573     sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
0574     pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
0575     pcm->private_data = chip;
0576 
0577     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
0578     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
0579 
0580     if (chip->dma8 > 3 || chip->dma16 >= 0)
0581         max_prealloc = 128 * 1024;
0582     snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
0583                        card->dev, 64*1024, max_prealloc);
0584 
0585     return 0;
0586 }
0587 
0588 EXPORT_SYMBOL(snd_sb8dsp_pcm);
0589 EXPORT_SYMBOL(snd_sb8dsp_interrupt);
0590   /* sb8_midi.c */
0591 EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt);
0592 EXPORT_SYMBOL(snd_sb8dsp_midi);