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