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 27 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Uros Bizjak <uros@kss-loka.si>"); 28 MODULE_DESCRIPTION("Routines for control of 8-bit SoundBlaster cards and clones"); 29 MODULE_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 35 static const struct snd_ratnum clock = { 36 .num = SB8_CLOCK, 37 .den_min = 1, 38 .den_max = 256, 39 .den_step = 1, 40 }; 41 42 static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clock = { 43 .nrats = 1, 44 .rats = &clock, 45 }; 46 47 static 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 62 static 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 79 static 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 90 static 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 192 static 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 228 static 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 317 static 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 355 irqreturn_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 385 static 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 401 static 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 421 static 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 440 static 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 463 static 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 526 static 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 547 static 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 555 static 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 563 int 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 588 EXPORT_SYMBOL(snd_sb8dsp_pcm); 589 EXPORT_SYMBOL(snd_sb8dsp_interrupt); 590 /* sb8_midi.c */ 591 EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt); 592 EXPORT_SYMBOL(snd_sb8dsp_midi); 593
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.