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 struct snd_sb *chip = snd_pcm_substream_chip(substream); 93 struct snd_pcm_runtime *runtime = substream->runtime; 94 unsigned int mixreg, rate, size, count; 95 unsigned char format; 96 unsigned char stereo = runtime->channels > 1; 97 int dma; 98 99 rate = runtime->rate; 100 switch (chip->hardware) { 101 case SB_HW_JAZZ16: 102 if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { 103 if (chip->mode & SB_MODE_CAPTURE_16) 104 return -EBUSY; 105 else 106 chip->mode |= SB_MODE_PLAYBACK_16; 107 } 108 chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; 109 break; 110 case SB_HW_PRO: 111 if (runtime->channels > 1) { 112 if (snd_BUG_ON(rate != SB8_RATE(11025) && 113 rate != SB8_RATE(22050))) 114 return -EINVAL; 115 chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; 116 break; 117 } 118 fallthrough; 119 case SB_HW_201: 120 if (rate > 23000) { 121 chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; 122 break; 123 } 124 fallthrough; 125 case SB_HW_20: 126 chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; 127 break; 128 case SB_HW_10: 129 chip->playback_format = SB_DSP_OUTPUT; 130 break; 131 default: 132 return -EINVAL; 133 } 134 if (chip->mode & SB_MODE_PLAYBACK_16) { 135 format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; 136 dma = chip->dma16; 137 } else { 138 format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; 139 chip->mode |= SB_MODE_PLAYBACK_8; 140 dma = chip->dma8; 141 } 142 size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); 143 count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); 144 scoped_guard(spinlock_irqsave, &chip->reg_lock) { 145 snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); 146 if (chip->hardware == SB_HW_JAZZ16) 147 snd_sbdsp_command(chip, format); 148 else if (stereo) { 149 /* set playback stereo mode */ 150 scoped_guard(spinlock, &chip->mixer_lock) { 151 mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); 152 snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02); 153 } 154 155 /* Soundblaster hardware programming reference guide, 3-23 */ 156 snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); 157 runtime->dma_area[0] = 0x80; 158 snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); 159 /* force interrupt */ 160 snd_sbdsp_command(chip, SB_DSP_OUTPUT); 161 snd_sbdsp_command(chip, 0); 162 snd_sbdsp_command(chip, 0); 163 } 164 snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); 165 if (stereo) { 166 snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); 167 scoped_guard(spinlock, &chip->mixer_lock) { 168 /* save output filter status and turn it off */ 169 mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT); 170 snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20); 171 } 172 /* just use force_mode16 for temporary storate... */ 173 chip->force_mode16 = mixreg; 174 } else { 175 snd_sbdsp_command(chip, 256 - runtime->rate_den); 176 } 177 if (chip->playback_format != SB_DSP_OUTPUT) { 178 if (chip->mode & SB_MODE_PLAYBACK_16) 179 count /= 2; 180 count--; 181 snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); 182 snd_sbdsp_command(chip, count & 0xff); 183 snd_sbdsp_command(chip, count >> 8); 184 } 185 } 186 snd_dma_program(dma, runtime->dma_addr, 187 size, DMA_MODE_WRITE | DMA_AUTOINIT); 188 return 0; 189 } 190 191 static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, 192 int cmd) 193 { 194 struct snd_sb *chip = snd_pcm_substream_chip(substream); 195 unsigned int count; 196 197 guard(spinlock_irqsave)(&chip->reg_lock); 198 switch (cmd) { 199 case SNDRV_PCM_TRIGGER_START: 200 snd_sbdsp_command(chip, chip->playback_format); 201 if (chip->playback_format == SB_DSP_OUTPUT) { 202 count = chip->p_period_size - 1; 203 snd_sbdsp_command(chip, count & 0xff); 204 snd_sbdsp_command(chip, count >> 8); 205 } 206 break; 207 case SNDRV_PCM_TRIGGER_STOP: 208 if (chip->playback_format == SB_DSP_HI_OUTPUT_AUTO) { 209 struct snd_pcm_runtime *runtime = substream->runtime; 210 snd_sbdsp_reset(chip); 211 if (runtime->channels > 1) { 212 guard(spinlock)(&chip->mixer_lock); 213 /* restore output filter and set hardware to mono mode */ 214 snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02); 215 } 216 } else { 217 snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); 218 } 219 snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); 220 } 221 return 0; 222 } 223 224 static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) 225 { 226 struct snd_sb *chip = snd_pcm_substream_chip(substream); 227 struct snd_pcm_runtime *runtime = substream->runtime; 228 unsigned int mixreg, rate, size, count; 229 unsigned char format; 230 unsigned char stereo = runtime->channels > 1; 231 int dma; 232 233 rate = runtime->rate; 234 switch (chip->hardware) { 235 case SB_HW_JAZZ16: 236 if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { 237 if (chip->mode & SB_MODE_PLAYBACK_16) 238 return -EBUSY; 239 else 240 chip->mode |= SB_MODE_CAPTURE_16; 241 } 242 chip->capture_format = SB_DSP_LO_INPUT_AUTO; 243 break; 244 case SB_HW_PRO: 245 if (runtime->channels > 1) { 246 if (snd_BUG_ON(rate != SB8_RATE(11025) && 247 rate != SB8_RATE(22050))) 248 return -EINVAL; 249 chip->capture_format = SB_DSP_HI_INPUT_AUTO; 250 break; 251 } 252 chip->capture_format = (rate > 23000) ? SB_DSP_HI_INPUT_AUTO : SB_DSP_LO_INPUT_AUTO; 253 break; 254 case SB_HW_201: 255 if (rate > 13000) { 256 chip->capture_format = SB_DSP_HI_INPUT_AUTO; 257 break; 258 } 259 fallthrough; 260 case SB_HW_20: 261 chip->capture_format = SB_DSP_LO_INPUT_AUTO; 262 break; 263 case SB_HW_10: 264 chip->capture_format = SB_DSP_INPUT; 265 break; 266 default: 267 return -EINVAL; 268 } 269 if (chip->mode & SB_MODE_CAPTURE_16) { 270 format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; 271 dma = chip->dma16; 272 } else { 273 format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; 274 chip->mode |= SB_MODE_CAPTURE_8; 275 dma = chip->dma8; 276 } 277 size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); 278 count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); 279 scoped_guard(spinlock_irqsave, &chip->reg_lock) { 280 snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); 281 if (chip->hardware == SB_HW_JAZZ16) 282 snd_sbdsp_command(chip, format); 283 else if (stereo) 284 snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); 285 snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); 286 if (stereo) { 287 snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); 288 scoped_guard(spinlock, &chip->mixer_lock) { 289 /* save input filter status and turn it off */ 290 mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT); 291 snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20); 292 } 293 /* just use force_mode16 for temporary storate... */ 294 chip->force_mode16 = mixreg; 295 } else { 296 snd_sbdsp_command(chip, 256 - runtime->rate_den); 297 } 298 if (chip->capture_format != SB_DSP_INPUT) { 299 if (chip->mode & SB_MODE_PLAYBACK_16) 300 count /= 2; 301 count--; 302 snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); 303 snd_sbdsp_command(chip, count & 0xff); 304 snd_sbdsp_command(chip, count >> 8); 305 } 306 } 307 snd_dma_program(dma, runtime->dma_addr, 308 size, DMA_MODE_READ | DMA_AUTOINIT); 309 return 0; 310 } 311 312 static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, 313 int cmd) 314 { 315 struct snd_sb *chip = snd_pcm_substream_chip(substream); 316 unsigned int count; 317 318 guard(spinlock_irqsave)(&chip->reg_lock); 319 switch (cmd) { 320 case SNDRV_PCM_TRIGGER_START: 321 snd_sbdsp_command(chip, chip->capture_format); 322 if (chip->capture_format == SB_DSP_INPUT) { 323 count = chip->c_period_size - 1; 324 snd_sbdsp_command(chip, count & 0xff); 325 snd_sbdsp_command(chip, count >> 8); 326 } 327 break; 328 case SNDRV_PCM_TRIGGER_STOP: 329 if (chip->capture_format == SB_DSP_HI_INPUT_AUTO) { 330 struct snd_pcm_runtime *runtime = substream->runtime; 331 snd_sbdsp_reset(chip); 332 if (runtime->channels > 1) { 333 /* restore input filter status */ 334 scoped_guard(spinlock, &chip->mixer_lock) { 335 snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16); 336 } 337 /* set hardware to mono mode */ 338 snd_sbdsp_command(chip, SB_DSP_MONO_8BIT); 339 } 340 } else { 341 snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); 342 } 343 snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); 344 } 345 return 0; 346 } 347 348 irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) 349 { 350 struct snd_pcm_substream *substream; 351 352 snd_sb_ack_8bit(chip); 353 switch (chip->mode) { 354 case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ 355 if (chip->hardware != SB_HW_JAZZ16) 356 break; 357 fallthrough; 358 case SB_MODE_PLAYBACK_8: 359 substream = chip->playback_substream; 360 if (chip->playback_format == SB_DSP_OUTPUT) 361 snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START); 362 snd_pcm_period_elapsed(substream); 363 break; 364 case SB_MODE_CAPTURE_16: 365 if (chip->hardware != SB_HW_JAZZ16) 366 break; 367 fallthrough; 368 case SB_MODE_CAPTURE_8: 369 substream = chip->capture_substream; 370 if (chip->capture_format == SB_DSP_INPUT) 371 snd_sb8_capture_trigger(substream, SNDRV_PCM_TRIGGER_START); 372 snd_pcm_period_elapsed(substream); 373 break; 374 } 375 return IRQ_HANDLED; 376 } 377 378 static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *substream) 379 { 380 struct snd_sb *chip = snd_pcm_substream_chip(substream); 381 size_t ptr; 382 int dma; 383 384 if (chip->mode & SB_MODE_PLAYBACK_8) 385 dma = chip->dma8; 386 else if (chip->mode & SB_MODE_PLAYBACK_16) 387 dma = chip->dma16; 388 else 389 return 0; 390 ptr = snd_dma_pointer(dma, chip->p_dma_size); 391 return bytes_to_frames(substream->runtime, ptr); 392 } 393 394 static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *substream) 395 { 396 struct snd_sb *chip = snd_pcm_substream_chip(substream); 397 size_t ptr; 398 int dma; 399 400 if (chip->mode & SB_MODE_CAPTURE_8) 401 dma = chip->dma8; 402 else if (chip->mode & SB_MODE_CAPTURE_16) 403 dma = chip->dma16; 404 else 405 return 0; 406 ptr = snd_dma_pointer(dma, chip->c_dma_size); 407 return bytes_to_frames(substream->runtime, ptr); 408 } 409 410 /* 411 412 */ 413 414 static const struct snd_pcm_hardware snd_sb8_playback = 415 { 416 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 417 SNDRV_PCM_INFO_MMAP_VALID), 418 .formats = SNDRV_PCM_FMTBIT_U8, 419 .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 | 420 SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050), 421 .rate_min = 4000, 422 .rate_max = 23000, 423 .channels_min = 1, 424 .channels_max = 1, 425 .buffer_bytes_max = 65536, 426 .period_bytes_min = 64, 427 .period_bytes_max = 65536, 428 .periods_min = 1, 429 .periods_max = 1024, 430 .fifo_size = 0, 431 }; 432 433 static const struct snd_pcm_hardware snd_sb8_capture = 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), 440 .rate_min = 4000, 441 .rate_max = 13000, 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 452 /* 453 * 454 */ 455 456 static int snd_sb8_open(struct snd_pcm_substream *substream) 457 { 458 struct snd_sb *chip = snd_pcm_substream_chip(substream); 459 struct snd_pcm_runtime *runtime = substream->runtime; 460 461 scoped_guard(spinlock_irqsave, &chip->open_lock) { 462 if (chip->open) 463 return -EAGAIN; 464 chip->open |= SB_OPEN_PCM; 465 } 466 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 467 chip->playback_substream = substream; 468 runtime->hw = snd_sb8_playback; 469 } else { 470 chip->capture_substream = substream; 471 runtime->hw = snd_sb8_capture; 472 } 473 switch (chip->hardware) { 474 case SB_HW_JAZZ16: 475 if (chip->dma16 == 5 || chip->dma16 == 7) 476 runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; 477 runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000; 478 runtime->hw.rate_min = 4000; 479 runtime->hw.rate_max = 50000; 480 runtime->hw.channels_max = 2; 481 break; 482 case SB_HW_PRO: 483 runtime->hw.rate_max = 44100; 484 runtime->hw.channels_max = 2; 485 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 486 snd_sb8_hw_constraint_rate_channels, NULL, 487 SNDRV_PCM_HW_PARAM_CHANNELS, 488 SNDRV_PCM_HW_PARAM_RATE, -1); 489 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 490 snd_sb8_hw_constraint_channels_rate, NULL, 491 SNDRV_PCM_HW_PARAM_RATE, -1); 492 break; 493 case SB_HW_201: 494 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 495 runtime->hw.rate_max = 44100; 496 } else { 497 runtime->hw.rate_max = 15000; 498 } 499 break; 500 default: 501 break; 502 } 503 snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 504 &hw_constraints_clock); 505 if (chip->dma8 > 3 || chip->dma16 >= 0) { 506 snd_pcm_hw_constraint_step(runtime, 0, 507 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2); 508 snd_pcm_hw_constraint_step(runtime, 0, 509 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2); 510 runtime->hw.buffer_bytes_max = 128 * 1024 * 1024; 511 runtime->hw.period_bytes_max = 128 * 1024 * 1024; 512 } 513 return 0; 514 } 515 516 static int snd_sb8_close(struct snd_pcm_substream *substream) 517 { 518 struct snd_sb *chip = snd_pcm_substream_chip(substream); 519 520 chip->playback_substream = NULL; 521 chip->capture_substream = NULL; 522 guard(spinlock_irqsave)(&chip->open_lock); 523 chip->open &= ~SB_OPEN_PCM; 524 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 525 chip->mode &= ~SB_MODE_PLAYBACK; 526 else 527 chip->mode &= ~SB_MODE_CAPTURE; 528 return 0; 529 } 530 531 /* 532 * Initialization part 533 */ 534 535 static const struct snd_pcm_ops snd_sb8_playback_ops = { 536 .open = snd_sb8_open, 537 .close = snd_sb8_close, 538 .prepare = snd_sb8_playback_prepare, 539 .trigger = snd_sb8_playback_trigger, 540 .pointer = snd_sb8_playback_pointer, 541 }; 542 543 static const struct snd_pcm_ops snd_sb8_capture_ops = { 544 .open = snd_sb8_open, 545 .close = snd_sb8_close, 546 .prepare = snd_sb8_capture_prepare, 547 .trigger = snd_sb8_capture_trigger, 548 .pointer = snd_sb8_capture_pointer, 549 }; 550 551 int snd_sb8dsp_pcm(struct snd_sb *chip, int device) 552 { 553 struct snd_card *card = chip->card; 554 struct snd_pcm *pcm; 555 int err; 556 size_t max_prealloc = 64 * 1024; 557 558 err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm); 559 if (err < 0) 560 return err; 561 sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); 562 pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; 563 pcm->private_data = chip; 564 565 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); 566 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); 567 568 if (chip->dma8 > 3 || chip->dma16 >= 0) 569 max_prealloc = 128 * 1024; 570 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 571 card->dev, 64*1024, max_prealloc); 572 573 return 0; 574 } 575 576 EXPORT_SYMBOL(snd_sb8dsp_pcm); 577 EXPORT_SYMBOL(snd_sb8dsp_interrupt); 578 /* sb8_midi.c */ 579 EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt); 580 EXPORT_SYMBOL(snd_sb8dsp_midi); 581