1 /* 2 * pcm emulation on emu8000 wavetable 3 * 4 * Copyright (C) 2002 Takashi Iwai <tiwai@suse.de> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 #include "emu8000_local.h" 22 #include <linux/init.h> 23 #include <sound/initval.h> 24 #include <sound/pcm.h> 25 26 /* 27 * define the following if you want to use this pcm with non-interleaved mode 28 */ 29 /* #define USE_NONINTERLEAVE */ 30 31 /* NOTE: for using the non-interleaved mode with alsa-lib, you have to set 32 * mmap_emulation flag to 1 in your .asoundrc, such like 33 * 34 * pcm.emu8k { 35 * type plug 36 * slave.pcm { 37 * type hw 38 * card 0 39 * device 1 40 * mmap_emulation 1 41 * } 42 * } 43 * 44 * besides, for the time being, the non-interleaved mode doesn't work well on 45 * alsa-lib... 46 */ 47 48 49 typedef struct snd_emu8k_pcm emu8k_pcm_t; 50 51 struct snd_emu8k_pcm { 52 emu8000_t *emu; 53 snd_pcm_substream_t *substream; 54 55 unsigned int allocated_bytes; 56 snd_util_memblk_t *block; 57 unsigned int offset; 58 unsigned int buf_size; 59 unsigned int period_size; 60 unsigned int loop_start[2]; 61 unsigned int pitch; 62 int panning[2]; 63 int last_ptr; 64 int period_pos; 65 int voices; 66 unsigned int dram_opened: 1; 67 unsigned int running: 1; 68 unsigned int timer_running: 1; 69 struct timer_list timer; 70 spinlock_t timer_lock; 71 }; 72 73 #define LOOP_BLANK_SIZE 8 74 75 76 /* 77 * open up channels for the simultaneous data transfer and playback 78 */ 79 static int 80 emu8k_open_dram_for_pcm(emu8000_t *emu, int channels) 81 { 82 int i; 83 84 /* reserve up to 2 voices for playback */ 85 snd_emux_lock_voice(emu->emu, 0); 86 if (channels > 1) 87 snd_emux_lock_voice(emu->emu, 1); 88 89 /* reserve 28 voices for loading */ 90 for (i = channels + 1; i < EMU8000_DRAM_VOICES; i++) { 91 unsigned int mode = EMU8000_RAM_WRITE; 92 snd_emux_lock_voice(emu->emu, i); 93 #ifndef USE_NONINTERLEAVE 94 if (channels > 1 && (i & 1) != 0) 95 mode |= EMU8000_RAM_RIGHT; 96 #endif 97 snd_emu8000_dma_chan(emu, i, mode); 98 } 99 100 /* assign voice 31 and 32 to ROM */ 101 EMU8000_VTFT_WRITE(emu, 30, 0); 102 EMU8000_PSST_WRITE(emu, 30, 0x1d8); 103 EMU8000_CSL_WRITE(emu, 30, 0x1e0); 104 EMU8000_CCCA_WRITE(emu, 30, 0x1d8); 105 EMU8000_VTFT_WRITE(emu, 31, 0); 106 EMU8000_PSST_WRITE(emu, 31, 0x1d8); 107 EMU8000_CSL_WRITE(emu, 31, 0x1e0); 108 EMU8000_CCCA_WRITE(emu, 31, 0x1d8); 109 110 return 0; 111 } 112 113 /* 114 */ 115 static void 116 snd_emu8000_write_wait(emu8000_t *emu, int can_schedule) 117 { 118 while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) { 119 if (can_schedule) { 120 set_current_state(TASK_INTERRUPTIBLE); 121 schedule_timeout(1); 122 if (signal_pending(current)) 123 break; 124 } 125 } 126 } 127 128 /* 129 * close all channels 130 */ 131 static void 132 emu8k_close_dram(emu8000_t *emu) 133 { 134 int i; 135 136 for (i = 0; i < 2; i++) 137 snd_emux_unlock_voice(emu->emu, i); 138 for (; i < EMU8000_DRAM_VOICES; i++) { 139 snd_emu8000_dma_chan(emu, i, EMU8000_RAM_CLOSE); 140 snd_emux_unlock_voice(emu->emu, i); 141 } 142 } 143 144 /* 145 * convert Hz to AWE32 rate offset (see emux/soundfont.c) 146 */ 147 148 #define OFFSET_SAMPLERATE 1011119 /* base = 44100 */ 149 #define SAMPLERATE_RATIO 4096 150 151 static int calc_rate_offset(int hz) 152 { 153 return snd_sf_linear_to_log(hz, OFFSET_SAMPLERATE, SAMPLERATE_RATIO); 154 } 155 156 157 /* 158 */ 159 160 static snd_pcm_hardware_t emu8k_pcm_hw = { 161 #ifdef USE_NONINTERLEAVE 162 .info = SNDRV_PCM_INFO_NONINTERLEAVED, 163 #else 164 .info = SNDRV_PCM_INFO_INTERLEAVED, 165 #endif 166 .formats = SNDRV_PCM_FMTBIT_S16_LE, 167 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, 168 .rate_min = 4000, 169 .rate_max = 48000, 170 .channels_min = 1, 171 .channels_max = 2, 172 .buffer_bytes_max = (128*1024), 173 .period_bytes_min = 1024, 174 .period_bytes_max = (128*1024), 175 .periods_min = 2, 176 .periods_max = 1024, 177 .fifo_size = 0, 178 179 }; 180 181 /* 182 * get the current position at the given channel from CCCA register 183 */ 184 static inline int emu8k_get_curpos(emu8k_pcm_t *rec, int ch) 185 { 186 int val = EMU8000_CCCA_READ(rec->emu, ch) & 0xfffffff; 187 val -= rec->loop_start[ch] - 1; 188 return val; 189 } 190 191 192 /* 193 * timer interrupt handler 194 * check the current position and update the period if necessary. 195 */ 196 static void emu8k_pcm_timer_func(unsigned long data) 197 { 198 emu8k_pcm_t *rec = (emu8k_pcm_t *)data; 199 int ptr, delta; 200 201 spin_lock(&rec->timer_lock); 202 /* update the current pointer */ 203 ptr = emu8k_get_curpos(rec, 0); 204 if (ptr < rec->last_ptr) 205 delta = ptr + rec->buf_size - rec->last_ptr; 206 else 207 delta = ptr - rec->last_ptr; 208 rec->period_pos += delta; 209 rec->last_ptr = ptr; 210 211 /* reprogram timer */ 212 rec->timer.expires = jiffies + 1; 213 add_timer(&rec->timer); 214 215 /* update period */ 216 if (rec->period_pos >= (int)rec->period_size) { 217 rec->period_pos %= rec->period_size; 218 spin_unlock(&rec->timer_lock); 219 snd_pcm_period_elapsed(rec->substream); 220 return; 221 } 222 spin_unlock(&rec->timer_lock); 223 } 224 225 226 /* 227 * open pcm 228 * creating an instance here 229 */ 230 static int emu8k_pcm_open(snd_pcm_substream_t *subs) 231 { 232 emu8000_t *emu = snd_pcm_substream_chip(subs); 233 emu8k_pcm_t *rec; 234 snd_pcm_runtime_t *runtime = subs->runtime; 235 236 rec = kcalloc(1, sizeof(*rec), GFP_KERNEL); 237 if (! rec) 238 return -ENOMEM; 239 240 rec->emu = emu; 241 rec->substream = subs; 242 runtime->private_data = rec; 243 244 spin_lock_init(&rec->timer_lock); 245 init_timer(&rec->timer); 246 rec->timer.function = emu8k_pcm_timer_func; 247 rec->timer.data = (unsigned long)rec; 248 249 runtime->hw = emu8k_pcm_hw; 250 runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3; 251 runtime->hw.period_bytes_max = runtime->hw.buffer_bytes_max / 2; 252 253 /* use timer to update periods.. (specified in msec) */ 254 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 255 (1000000 + HZ - 1) / HZ, UINT_MAX); 256 257 return 0; 258 } 259 260 static int emu8k_pcm_close(snd_pcm_substream_t *subs) 261 { 262 emu8k_pcm_t *rec = subs->runtime->private_data; 263 kfree(rec); 264 subs->runtime->private_data = NULL; 265 return 0; 266 } 267 268 /* 269 * calculate pitch target 270 */ 271 static int calc_pitch_target(int pitch) 272 { 273 int ptarget = 1 << (pitch >> 12); 274 if (pitch & 0x800) ptarget += (ptarget * 0x102e) / 0x2710; 275 if (pitch & 0x400) ptarget += (ptarget * 0x764) / 0x2710; 276 if (pitch & 0x200) ptarget += (ptarget * 0x389) / 0x2710; 277 ptarget += (ptarget >> 1); 278 if (ptarget > 0xffff) ptarget = 0xffff; 279 return ptarget; 280 } 281 282 /* 283 * set up the voice 284 */ 285 static void setup_voice(emu8k_pcm_t *rec, int ch) 286 { 287 emu8000_t *hw = rec->emu; 288 unsigned int temp; 289 290 /* channel to be silent and idle */ 291 EMU8000_DCYSUSV_WRITE(hw, ch, 0x0080); 292 EMU8000_VTFT_WRITE(hw, ch, 0x0000FFFF); 293 EMU8000_CVCF_WRITE(hw, ch, 0x0000FFFF); 294 EMU8000_PTRX_WRITE(hw, ch, 0); 295 EMU8000_CPF_WRITE(hw, ch, 0); 296 297 /* pitch offset */ 298 EMU8000_IP_WRITE(hw, ch, rec->pitch); 299 /* set envelope parameters */ 300 EMU8000_ENVVAL_WRITE(hw, ch, 0x8000); 301 EMU8000_ATKHLD_WRITE(hw, ch, 0x7f7f); 302 EMU8000_DCYSUS_WRITE(hw, ch, 0x7f7f); 303 EMU8000_ENVVOL_WRITE(hw, ch, 0x8000); 304 EMU8000_ATKHLDV_WRITE(hw, ch, 0x7f7f); 305 /* decay/sustain parameter for volume envelope is used 306 for triggerg the voice */ 307 /* modulation envelope heights */ 308 EMU8000_PEFE_WRITE(hw, ch, 0x0); 309 /* lfo1/2 delay */ 310 EMU8000_LFO1VAL_WRITE(hw, ch, 0x8000); 311 EMU8000_LFO2VAL_WRITE(hw, ch, 0x8000); 312 /* lfo1 pitch & cutoff shift */ 313 EMU8000_FMMOD_WRITE(hw, ch, 0); 314 /* lfo1 volume & freq */ 315 EMU8000_TREMFRQ_WRITE(hw, ch, 0); 316 /* lfo2 pitch & freq */ 317 EMU8000_FM2FRQ2_WRITE(hw, ch, 0); 318 /* pan & loop start */ 319 temp = rec->panning[ch]; 320 temp = (temp <<24) | ((unsigned int)rec->loop_start[ch] - 1); 321 EMU8000_PSST_WRITE(hw, ch, temp); 322 /* chorus & loop end (chorus 8bit, MSB) */ 323 temp = 0; // chorus 324 temp = (temp << 24) | ((unsigned int)rec->loop_start[ch] + rec->buf_size - 1); 325 EMU8000_CSL_WRITE(hw, ch, temp); 326 /* Q & current address (Q 4bit value, MSB) */ 327 temp = 0; // filterQ 328 temp = (temp << 28) | ((unsigned int)rec->loop_start[ch] - 1); 329 EMU8000_CCCA_WRITE(hw, ch, temp); 330 /* clear unknown registers */ 331 EMU8000_00A0_WRITE(hw, ch, 0); 332 EMU8000_0080_WRITE(hw, ch, 0); 333 } 334 335 /* 336 * trigger the voice 337 */ 338 static void start_voice(emu8k_pcm_t *rec, int ch) 339 { 340 unsigned long flags; 341 emu8000_t *hw = rec->emu; 342 unsigned int temp, aux; 343 int pt = calc_pitch_target(rec->pitch); 344 345 /* cutoff and volume */ 346 EMU8000_IFATN_WRITE(hw, ch, 0xff00); 347 EMU8000_VTFT_WRITE(hw, ch, 0xffff); 348 EMU8000_CVCF_WRITE(hw, ch, 0xffff); 349 /* trigger envelope */ 350 EMU8000_DCYSUSV_WRITE(hw, ch, 0x7f7f); 351 /* set reverb and pitch target */ 352 temp = 0; // reverb 353 if (rec->panning[ch] == 0) 354 aux = 0xff; 355 else 356 aux = (-rec->panning[ch]) & 0xff; 357 temp = (temp << 8) | (pt << 16) | aux; 358 EMU8000_PTRX_WRITE(hw, ch, temp); 359 EMU8000_CPF_WRITE(hw, ch, pt << 16); 360 361 /* start timer */ 362 spin_lock_irqsave(&rec->timer_lock, flags); 363 if (! rec->timer_running) { 364 rec->timer.expires = jiffies + 1; 365 add_timer(&rec->timer); 366 rec->timer_running = 1; 367 } 368 spin_unlock_irqrestore(&rec->timer_lock, flags); 369 } 370 371 /* 372 * stop the voice immediately 373 */ 374 static void stop_voice(emu8k_pcm_t *rec, int ch) 375 { 376 unsigned long flags; 377 emu8000_t *hw = rec->emu; 378 379 EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F); 380 381 /* stop timer */ 382 spin_lock_irqsave(&rec->timer_lock, flags); 383 if (rec->timer_running) { 384 del_timer(&rec->timer); 385 rec->timer_running = 0; 386 } 387 spin_unlock_irqrestore(&rec->timer_lock, flags); 388 } 389 390 static int emu8k_pcm_trigger(snd_pcm_substream_t *subs, int cmd) 391 { 392 emu8k_pcm_t *rec = subs->runtime->private_data; 393 int ch; 394 395 switch (cmd) { 396 case SNDRV_PCM_TRIGGER_START: 397 for (ch = 0; ch < rec->voices; ch++) 398 start_voice(rec, ch); 399 rec->running = 1; 400 break; 401 case SNDRV_PCM_TRIGGER_STOP: 402 rec->running = 0; 403 for (ch = 0; ch < rec->voices; ch++) 404 stop_voice(rec, ch); 405 break; 406 default: 407 return -EINVAL; 408 } 409 return 0; 410 } 411 412 413 /* 414 * copy / silence ops 415 */ 416 417 /* 418 * this macro should be inserted in the copy/silence loops 419 * to reduce the latency. without this, the system will hang up 420 * during the whole loop. 421 */ 422 #define CHECK_SCHEDULER() \ 423 do { \ 424 cond_resched();\ 425 if (signal_pending(current))\ 426 return -EAGAIN;\ 427 } while (0) 428 429 430 #ifdef USE_NONINTERLEAVE 431 /* copy one channel block */ 432 static int emu8k_transfer_block(emu8000_t *emu, int offset, unsigned short *buf, int count) 433 { 434 EMU8000_SMALW_WRITE(emu, offset); 435 while (count > 0) { 436 unsigned short sval; 437 CHECK_SCHEDULER(); 438 get_user(sval, buf); 439 EMU8000_SMLD_WRITE(emu, sval); 440 buf++; 441 count--; 442 } 443 return 0; 444 } 445 446 static int emu8k_pcm_copy(snd_pcm_substream_t *subs, 447 int voice, 448 snd_pcm_uframes_t pos, 449 void *src, 450 snd_pcm_uframes_t count) 451 { 452 emu8k_pcm_t *rec = subs->runtime->private_data; 453 emu8000_t *emu = rec->emu; 454 455 snd_emu8000_write_wait(emu, 1); 456 if (voice == -1) { 457 unsigned short *buf = src; 458 int i, err; 459 count /= rec->voices; 460 for (i = 0; i < rec->voices; i++) { 461 err = emu8k_transfer_block(emu, pos + rec->loop_start[i], buf, count); 462 if (err < 0) 463 return err; 464 buf += count; 465 } 466 return 0; 467 } else { 468 return emu8k_transfer_block(emu, pos + rec->loop_start[voice], src, count); 469 } 470 } 471 472 /* make a channel block silence */ 473 static int emu8k_silence_block(emu8000_t *emu, int offset, int count) 474 { 475 EMU8000_SMALW_WRITE(emu, offset); 476 while (count > 0) { 477 CHECK_SCHEDULER(); 478 EMU8000_SMLD_WRITE(emu, 0); 479 count--; 480 } 481 return 0; 482 } 483 484 static int emu8k_pcm_silence(snd_pcm_substream_t *subs, 485 int voice, 486 snd_pcm_uframes_t pos, 487 snd_pcm_uframes_t count) 488 { 489 emu8k_pcm_t *rec = subs->runtime->private_data; 490 emu8000_t *emu = rec->emu; 491 492 snd_emu8000_write_wait(emu, 1); 493 if (voice == -1 && rec->voices == 1) 494 voice = 0; 495 if (voice == -1) { 496 int err; 497 err = emu8k_silence_block(emu, pos + rec->loop_start[0], count / 2); 498 if (err < 0) 499 return err; 500 return emu8k_silence_block(emu, pos + rec->loop_start[1], count / 2); 501 } else { 502 return emu8k_silence_block(emu, pos + rec->loop_start[voice], count); 503 } 504 } 505 506 #else /* interleave */ 507 508 /* 509 * copy the interleaved data can be done easily by using 510 * DMA "left" and "right" channels on emu8k engine. 511 */ 512 static int emu8k_pcm_copy(snd_pcm_substream_t *subs, 513 int voice, 514 snd_pcm_uframes_t pos, 515 void __user *src, 516 snd_pcm_uframes_t count) 517 { 518 emu8k_pcm_t *rec = subs->runtime->private_data; 519 emu8000_t *emu = rec->emu; 520 unsigned short __user *buf = src; 521 522 snd_emu8000_write_wait(emu, 1); 523 EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]); 524 if (rec->voices > 1) 525 EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]); 526 527 while (count-- > 0) { 528 unsigned short sval; 529 CHECK_SCHEDULER(); 530 get_user(sval, buf); 531 EMU8000_SMLD_WRITE(emu, sval); 532 buf++; 533 if (rec->voices > 1) { 534 CHECK_SCHEDULER(); 535 get_user(sval, buf); 536 EMU8000_SMRD_WRITE(emu, sval); 537 buf++; 538 } 539 } 540 return 0; 541 } 542 543 static int emu8k_pcm_silence(snd_pcm_substream_t *subs, 544 int voice, 545 snd_pcm_uframes_t pos, 546 snd_pcm_uframes_t count) 547 { 548 emu8k_pcm_t *rec = subs->runtime->private_data; 549 emu8000_t *emu = rec->emu; 550 551 snd_emu8000_write_wait(emu, 1); 552 EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos); 553 if (rec->voices > 1) 554 EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos); 555 while (count-- > 0) { 556 CHECK_SCHEDULER(); 557 EMU8000_SMLD_WRITE(emu, 0); 558 if (rec->voices > 1) { 559 CHECK_SCHEDULER(); 560 EMU8000_SMRD_WRITE(emu, 0); 561 } 562 } 563 return 0; 564 } 565 #endif 566 567 568 /* 569 * allocate a memory block 570 */ 571 static int emu8k_pcm_hw_params(snd_pcm_substream_t *subs, 572 snd_pcm_hw_params_t *hw_params) 573 { 574 emu8k_pcm_t *rec = subs->runtime->private_data; 575 576 if (rec->block) { 577 /* reallocation - release the old block */ 578 snd_util_mem_free(rec->emu->memhdr, rec->block); 579 rec->block = NULL; 580 } 581 582 rec->allocated_bytes = params_buffer_bytes(hw_params) + LOOP_BLANK_SIZE * 4; 583 rec->block = snd_util_mem_alloc(rec->emu->memhdr, rec->allocated_bytes); 584 if (! rec->block) 585 return -ENOMEM; 586 rec->offset = EMU8000_DRAM_OFFSET + (rec->block->offset >> 1); /* in word */ 587 /* at least dma_bytes must be set for non-interleaved mode */ 588 subs->dma_buffer.bytes = params_buffer_bytes(hw_params); 589 590 return 0; 591 } 592 593 /* 594 * free the memory block 595 */ 596 static int emu8k_pcm_hw_free(snd_pcm_substream_t *subs) 597 { 598 emu8k_pcm_t *rec = subs->runtime->private_data; 599 600 if (rec->block) { 601 int ch; 602 for (ch = 0; ch < rec->voices; ch++) 603 stop_voice(rec, ch); // to be sure 604 if (rec->dram_opened) 605 emu8k_close_dram(rec->emu); 606 snd_util_mem_free(rec->emu->memhdr, rec->block); 607 rec->block = NULL; 608 } 609 return 0; 610 } 611 612 /* 613 */ 614 static int emu8k_pcm_prepare(snd_pcm_substream_t *subs) 615 { 616 emu8k_pcm_t *rec = subs->runtime->private_data; 617 618 rec->pitch = 0xe000 + calc_rate_offset(subs->runtime->rate); 619 rec->last_ptr = 0; 620 rec->period_pos = 0; 621 622 rec->buf_size = subs->runtime->buffer_size; 623 rec->period_size = subs->runtime->period_size; 624 rec->voices = subs->runtime->channels; 625 rec->loop_start[0] = rec->offset + LOOP_BLANK_SIZE; 626 if (rec->voices > 1) 627 rec->loop_start[1] = rec->loop_start[0] + rec->buf_size + LOOP_BLANK_SIZE; 628 if (rec->voices > 1) { 629 rec->panning[0] = 0xff; 630 rec->panning[1] = 0x00; 631 } else 632 rec->panning[0] = 0x80; 633 634 if (! rec->dram_opened) { 635 int err, i, ch; 636 637 snd_emux_terminate_all(rec->emu->emu); 638 if ((err = emu8k_open_dram_for_pcm(rec->emu, rec->voices)) != 0) 639 return err; 640 rec->dram_opened = 1; 641 642 /* clear loop blanks */ 643 snd_emu8000_write_wait(rec->emu, 0); 644 EMU8000_SMALW_WRITE(rec->emu, rec->offset); 645 for (i = 0; i < LOOP_BLANK_SIZE; i++) 646 EMU8000_SMLD_WRITE(rec->emu, 0); 647 for (ch = 0; ch < rec->voices; ch++) { 648 EMU8000_SMALW_WRITE(rec->emu, rec->loop_start[ch] + rec->buf_size); 649 for (i = 0; i < LOOP_BLANK_SIZE; i++) 650 EMU8000_SMLD_WRITE(rec->emu, 0); 651 } 652 } 653 654 setup_voice(rec, 0); 655 if (rec->voices > 1) 656 setup_voice(rec, 1); 657 return 0; 658 } 659 660 static snd_pcm_uframes_t emu8k_pcm_pointer(snd_pcm_substream_t *subs) 661 { 662 emu8k_pcm_t *rec = subs->runtime->private_data; 663 if (rec->running) 664 return emu8k_get_curpos(rec, 0); 665 return 0; 666 } 667 668 669 static snd_pcm_ops_t emu8k_pcm_ops = { 670 .open = emu8k_pcm_open, 671 .close = emu8k_pcm_close, 672 .ioctl = snd_pcm_lib_ioctl, 673 .hw_params = emu8k_pcm_hw_params, 674 .hw_free = emu8k_pcm_hw_free, 675 .prepare = emu8k_pcm_prepare, 676 .trigger = emu8k_pcm_trigger, 677 .pointer = emu8k_pcm_pointer, 678 .copy = emu8k_pcm_copy, 679 .silence = emu8k_pcm_silence, 680 }; 681 682 683 static void snd_emu8000_pcm_free(snd_pcm_t *pcm) 684 { 685 emu8000_t *emu = pcm->private_data; 686 emu->pcm = NULL; 687 } 688 689 int snd_emu8000_pcm_new(snd_card_t *card, emu8000_t *emu, int index) 690 { 691 snd_pcm_t *pcm; 692 int err; 693 694 if ((err = snd_pcm_new(card, "Emu8000 PCM", index, 1, 0, &pcm)) < 0) 695 return err; 696 pcm->private_data = emu; 697 pcm->private_free = snd_emu8000_pcm_free; 698 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &emu8k_pcm_ops); 699 emu->pcm = pcm; 700 701 snd_device_register(card, pcm); 702 703 return 0; 704 } 705