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        mod_timer(&rec->timer, jiffies + 1);
 211
 212        /* update period */
 213        if (rec->period_pos >= (int)rec->period_size) {
 214                rec->period_pos %= rec->period_size;
 215                spin_unlock(&rec->timer_lock);
 216                snd_pcm_period_elapsed(rec->substream);
 217                return;
 218        }
 219        spin_unlock(&rec->timer_lock);
 220}
 221
 222
 223/*
 224 * open pcm
 225 * creating an instance here
 226 */
 227static int emu8k_pcm_open(struct snd_pcm_substream *subs)
 228{
 229        struct snd_emu8000 *emu = snd_pcm_substream_chip(subs);
 230        struct snd_emu8k_pcm *rec;
 231        struct snd_pcm_runtime *runtime = subs->runtime;
 232
 233        rec = kzalloc(sizeof(*rec), GFP_KERNEL);
 234        if (! rec)
 235                return -ENOMEM;
 236
 237        rec->emu = emu;
 238        rec->substream = subs;
 239        runtime->private_data = rec;
 240
 241        spin_lock_init(&rec->timer_lock);
 242        setup_timer(&rec->timer, emu8k_pcm_timer_func, (unsigned long)rec);
 243
 244        runtime->hw = emu8k_pcm_hw;
 245        runtime->hw.buffer_bytes_max = emu->mem_size - LOOP_BLANK_SIZE * 3;
 246        runtime->hw.period_bytes_max = runtime->hw.buffer_bytes_max / 2;
 247
 248        /* use timer to update periods.. (specified in msec) */
 249        snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
 250                                     (1000000 + HZ - 1) / HZ, UINT_MAX);
 251
 252        return 0;
 253}
 254
 255static int emu8k_pcm_close(struct snd_pcm_substream *subs)
 256{
 257        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 258        kfree(rec);
 259        subs->runtime->private_data = NULL;
 260        return 0;
 261}
 262
 263/*
 264 * calculate pitch target
 265 */
 266static int calc_pitch_target(int pitch)
 267{
 268        int ptarget = 1 << (pitch >> 12);
 269        if (pitch & 0x800) ptarget += (ptarget * 0x102e) / 0x2710;
 270        if (pitch & 0x400) ptarget += (ptarget * 0x764) / 0x2710;
 271        if (pitch & 0x200) ptarget += (ptarget * 0x389) / 0x2710;
 272        ptarget += (ptarget >> 1);
 273        if (ptarget > 0xffff) ptarget = 0xffff;
 274        return ptarget;
 275}
 276
 277/*
 278 * set up the voice
 279 */
 280static void setup_voice(struct snd_emu8k_pcm *rec, int ch)
 281{
 282        struct snd_emu8000 *hw = rec->emu;
 283        unsigned int temp;
 284
 285        /* channel to be silent and idle */
 286        EMU8000_DCYSUSV_WRITE(hw, ch, 0x0080);
 287        EMU8000_VTFT_WRITE(hw, ch, 0x0000FFFF);
 288        EMU8000_CVCF_WRITE(hw, ch, 0x0000FFFF);
 289        EMU8000_PTRX_WRITE(hw, ch, 0);
 290        EMU8000_CPF_WRITE(hw, ch, 0);
 291
 292        /* pitch offset */
 293        EMU8000_IP_WRITE(hw, ch, rec->pitch);
 294        /* set envelope parameters */
 295        EMU8000_ENVVAL_WRITE(hw, ch, 0x8000);
 296        EMU8000_ATKHLD_WRITE(hw, ch, 0x7f7f);
 297        EMU8000_DCYSUS_WRITE(hw, ch, 0x7f7f);
 298        EMU8000_ENVVOL_WRITE(hw, ch, 0x8000);
 299        EMU8000_ATKHLDV_WRITE(hw, ch, 0x7f7f);
 300        /* decay/sustain parameter for volume envelope is used
 301           for triggerg the voice */
 302        /* modulation envelope heights */
 303        EMU8000_PEFE_WRITE(hw, ch, 0x0);
 304        /* lfo1/2 delay */
 305        EMU8000_LFO1VAL_WRITE(hw, ch, 0x8000);
 306        EMU8000_LFO2VAL_WRITE(hw, ch, 0x8000);
 307        /* lfo1 pitch & cutoff shift */
 308        EMU8000_FMMOD_WRITE(hw, ch, 0);
 309        /* lfo1 volume & freq */
 310        EMU8000_TREMFRQ_WRITE(hw, ch, 0);
 311        /* lfo2 pitch & freq */
 312        EMU8000_FM2FRQ2_WRITE(hw, ch, 0);
 313        /* pan & loop start */
 314        temp = rec->panning[ch];
 315        temp = (temp <<24) | ((unsigned int)rec->loop_start[ch] - 1);
 316        EMU8000_PSST_WRITE(hw, ch, temp);
 317        /* chorus & loop end (chorus 8bit, MSB) */
 318        temp = 0; // chorus
 319        temp = (temp << 24) | ((unsigned int)rec->loop_start[ch] + rec->buf_size - 1);
 320        EMU8000_CSL_WRITE(hw, ch, temp);
 321        /* Q & current address (Q 4bit value, MSB) */
 322        temp = 0; // filterQ
 323        temp = (temp << 28) | ((unsigned int)rec->loop_start[ch] - 1);
 324        EMU8000_CCCA_WRITE(hw, ch, temp);
 325        /* clear unknown registers */
 326        EMU8000_00A0_WRITE(hw, ch, 0);
 327        EMU8000_0080_WRITE(hw, ch, 0);
 328}
 329
 330/*
 331 * trigger the voice
 332 */
 333static void start_voice(struct snd_emu8k_pcm *rec, int ch)
 334{
 335        unsigned long flags;
 336        struct snd_emu8000 *hw = rec->emu;
 337        unsigned int temp, aux;
 338        int pt = calc_pitch_target(rec->pitch);
 339
 340        /* cutoff and volume */
 341        EMU8000_IFATN_WRITE(hw, ch, 0xff00);
 342        EMU8000_VTFT_WRITE(hw, ch, 0xffff);
 343        EMU8000_CVCF_WRITE(hw, ch, 0xffff);
 344        /* trigger envelope */
 345        EMU8000_DCYSUSV_WRITE(hw, ch, 0x7f7f);
 346        /* set reverb and pitch target */
 347        temp = 0; // reverb
 348        if (rec->panning[ch] == 0)
 349                aux = 0xff;
 350        else
 351                aux = (-rec->panning[ch]) & 0xff;
 352        temp = (temp << 8) | (pt << 16) | aux;
 353        EMU8000_PTRX_WRITE(hw, ch, temp);
 354        EMU8000_CPF_WRITE(hw, ch, pt << 16);
 355
 356        /* start timer */
 357        spin_lock_irqsave(&rec->timer_lock, flags);
 358        if (! rec->timer_running) {
 359                mod_timer(&rec->timer, jiffies + 1);
 360                rec->timer_running = 1;
 361        }
 362        spin_unlock_irqrestore(&rec->timer_lock, flags);
 363}
 364
 365/*
 366 * stop the voice immediately
 367 */
 368static void stop_voice(struct snd_emu8k_pcm *rec, int ch)
 369{
 370        unsigned long flags;
 371        struct snd_emu8000 *hw = rec->emu;
 372
 373        EMU8000_DCYSUSV_WRITE(hw, ch, 0x807F);
 374
 375        /* stop timer */
 376        spin_lock_irqsave(&rec->timer_lock, flags);
 377        if (rec->timer_running) {
 378                del_timer(&rec->timer);
 379                rec->timer_running = 0;
 380        }
 381        spin_unlock_irqrestore(&rec->timer_lock, flags);
 382}
 383
 384static int emu8k_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
 385{
 386        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 387        int ch;
 388
 389        switch (cmd) {
 390        case SNDRV_PCM_TRIGGER_START:
 391                for (ch = 0; ch < rec->voices; ch++)
 392                        start_voice(rec, ch);
 393                rec->running = 1;
 394                break;
 395        case SNDRV_PCM_TRIGGER_STOP:
 396                rec->running = 0;
 397                for (ch = 0; ch < rec->voices; ch++)
 398                        stop_voice(rec, ch);
 399                break;
 400        default:
 401                return -EINVAL;
 402        }
 403        return 0;
 404}
 405
 406
 407/*
 408 * copy / silence ops
 409 */
 410
 411/*
 412 * this macro should be inserted in the copy/silence loops
 413 * to reduce the latency.  without this, the system will hang up
 414 * during the whole loop.
 415 */
 416#define CHECK_SCHEDULER() \
 417do { \
 418        cond_resched();\
 419        if (signal_pending(current))\
 420                return -EAGAIN;\
 421} while (0)
 422
 423
 424#ifdef USE_NONINTERLEAVE
 425/* copy one channel block */
 426static int emu8k_transfer_block(struct snd_emu8000 *emu, int offset, unsigned short *buf, int count)
 427{
 428        EMU8000_SMALW_WRITE(emu, offset);
 429        while (count > 0) {
 430                unsigned short sval;
 431                CHECK_SCHEDULER();
 432                if (get_user(sval, buf))
 433                        return -EFAULT;
 434                EMU8000_SMLD_WRITE(emu, sval);
 435                buf++;
 436                count--;
 437        }
 438        return 0;
 439}
 440
 441static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
 442                          int voice,
 443                          snd_pcm_uframes_t pos,
 444                          void *src,
 445                          snd_pcm_uframes_t count)
 446{
 447        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 448        struct snd_emu8000 *emu = rec->emu;
 449
 450        snd_emu8000_write_wait(emu, 1);
 451        if (voice == -1) {
 452                unsigned short *buf = src;
 453                int i, err;
 454                count /= rec->voices;
 455                for (i = 0; i < rec->voices; i++) {
 456                        err = emu8k_transfer_block(emu, pos + rec->loop_start[i], buf, count);
 457                        if (err < 0)
 458                                return err;
 459                        buf += count;
 460                }
 461                return 0;
 462        } else {
 463                return emu8k_transfer_block(emu, pos + rec->loop_start[voice], src, count);
 464        }
 465}
 466
 467/* make a channel block silence */
 468static int emu8k_silence_block(struct snd_emu8000 *emu, int offset, int count)
 469{
 470        EMU8000_SMALW_WRITE(emu, offset);
 471        while (count > 0) {
 472                CHECK_SCHEDULER();
 473                EMU8000_SMLD_WRITE(emu, 0);
 474                count--;
 475        }
 476        return 0;
 477}
 478
 479static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
 480                             int voice,
 481                             snd_pcm_uframes_t pos,
 482                             snd_pcm_uframes_t count)
 483{
 484        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 485        struct snd_emu8000 *emu = rec->emu;
 486
 487        snd_emu8000_write_wait(emu, 1);
 488        if (voice == -1 && rec->voices == 1)
 489                voice = 0;
 490        if (voice == -1) {
 491                int err;
 492                err = emu8k_silence_block(emu, pos + rec->loop_start[0], count / 2);
 493                if (err < 0)
 494                        return err;
 495                return emu8k_silence_block(emu, pos + rec->loop_start[1], count / 2);
 496        } else {
 497                return emu8k_silence_block(emu, pos + rec->loop_start[voice], count);
 498        }
 499}
 500
 501#else /* interleave */
 502
 503/*
 504 * copy the interleaved data can be done easily by using
 505 * DMA "left" and "right" channels on emu8k engine.
 506 */
 507static int emu8k_pcm_copy(struct snd_pcm_substream *subs,
 508                          int voice,
 509                          snd_pcm_uframes_t pos,
 510                          void __user *src,
 511                          snd_pcm_uframes_t count)
 512{
 513        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 514        struct snd_emu8000 *emu = rec->emu;
 515        unsigned short __user *buf = src;
 516
 517        snd_emu8000_write_wait(emu, 1);
 518        EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]);
 519        if (rec->voices > 1)
 520                EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]);
 521
 522        while (count-- > 0) {
 523                unsigned short sval;
 524                CHECK_SCHEDULER();
 525                if (get_user(sval, buf))
 526                        return -EFAULT;
 527                EMU8000_SMLD_WRITE(emu, sval);
 528                buf++;
 529                if (rec->voices > 1) {
 530                        CHECK_SCHEDULER();
 531                        if (get_user(sval, buf))
 532                                return -EFAULT;
 533                        EMU8000_SMRD_WRITE(emu, sval);
 534                        buf++;
 535                }
 536        }
 537        return 0;
 538}
 539
 540static int emu8k_pcm_silence(struct snd_pcm_substream *subs,
 541                             int voice,
 542                             snd_pcm_uframes_t pos,
 543                             snd_pcm_uframes_t count)
 544{
 545        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 546        struct snd_emu8000 *emu = rec->emu;
 547
 548        snd_emu8000_write_wait(emu, 1);
 549        EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos);
 550        if (rec->voices > 1)
 551                EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos);
 552        while (count-- > 0) {
 553                CHECK_SCHEDULER();
 554                EMU8000_SMLD_WRITE(emu, 0);
 555                if (rec->voices > 1) {
 556                        CHECK_SCHEDULER();
 557                        EMU8000_SMRD_WRITE(emu, 0);
 558                }
 559        }
 560        return 0;
 561}
 562#endif
 563
 564
 565/*
 566 * allocate a memory block
 567 */
 568static int emu8k_pcm_hw_params(struct snd_pcm_substream *subs,
 569                               struct snd_pcm_hw_params *hw_params)
 570{
 571        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 572
 573        if (rec->block) {
 574                /* reallocation - release the old block */
 575                snd_util_mem_free(rec->emu->memhdr, rec->block);
 576                rec->block = NULL;
 577        }
 578
 579        rec->allocated_bytes = params_buffer_bytes(hw_params) + LOOP_BLANK_SIZE * 4;
 580        rec->block = snd_util_mem_alloc(rec->emu->memhdr, rec->allocated_bytes);
 581        if (! rec->block)
 582                return -ENOMEM;
 583        rec->offset = EMU8000_DRAM_OFFSET + (rec->block->offset >> 1); /* in word */
 584        /* at least dma_bytes must be set for non-interleaved mode */
 585        subs->dma_buffer.bytes = params_buffer_bytes(hw_params);
 586
 587        return 0;
 588}
 589
 590/*
 591 * free the memory block
 592 */
 593static int emu8k_pcm_hw_free(struct snd_pcm_substream *subs)
 594{
 595        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 596
 597        if (rec->block) {
 598                int ch;
 599                for (ch = 0; ch < rec->voices; ch++)
 600                        stop_voice(rec, ch); // to be sure
 601                if (rec->dram_opened)
 602                        emu8k_close_dram(rec->emu);
 603                snd_util_mem_free(rec->emu->memhdr, rec->block);
 604                rec->block = NULL;
 605        }
 606        return 0;
 607}
 608
 609/*
 610 */
 611static int emu8k_pcm_prepare(struct snd_pcm_substream *subs)
 612{
 613        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 614
 615        rec->pitch = 0xe000 + calc_rate_offset(subs->runtime->rate);
 616        rec->last_ptr = 0;
 617        rec->period_pos = 0;
 618
 619        rec->buf_size = subs->runtime->buffer_size;
 620        rec->period_size = subs->runtime->period_size;
 621        rec->voices = subs->runtime->channels;
 622        rec->loop_start[0] = rec->offset + LOOP_BLANK_SIZE;
 623        if (rec->voices > 1)
 624                rec->loop_start[1] = rec->loop_start[0] + rec->buf_size + LOOP_BLANK_SIZE;
 625        if (rec->voices > 1) {
 626                rec->panning[0] = 0xff;
 627                rec->panning[1] = 0x00;
 628        } else
 629                rec->panning[0] = 0x80;
 630
 631        if (! rec->dram_opened) {
 632                int err, i, ch;
 633
 634                snd_emux_terminate_all(rec->emu->emu);
 635                if ((err = emu8k_open_dram_for_pcm(rec->emu, rec->voices)) != 0)
 636                        return err;
 637                rec->dram_opened = 1;
 638
 639                /* clear loop blanks */
 640                snd_emu8000_write_wait(rec->emu, 0);
 641                EMU8000_SMALW_WRITE(rec->emu, rec->offset);
 642                for (i = 0; i < LOOP_BLANK_SIZE; i++)
 643                        EMU8000_SMLD_WRITE(rec->emu, 0);
 644                for (ch = 0; ch < rec->voices; ch++) {
 645                        EMU8000_SMALW_WRITE(rec->emu, rec->loop_start[ch] + rec->buf_size);
 646                        for (i = 0; i < LOOP_BLANK_SIZE; i++)
 647                                EMU8000_SMLD_WRITE(rec->emu, 0);
 648                }
 649        }
 650
 651        setup_voice(rec, 0);
 652        if (rec->voices > 1)
 653                setup_voice(rec, 1);
 654        return 0;
 655}
 656
 657static snd_pcm_uframes_t emu8k_pcm_pointer(struct snd_pcm_substream *subs)
 658{
 659        struct snd_emu8k_pcm *rec = subs->runtime->private_data;
 660        if (rec->running)
 661                return emu8k_get_curpos(rec, 0);
 662        return 0;
 663}
 664
 665
 666static struct snd_pcm_ops emu8k_pcm_ops = {
 667        .open =         emu8k_pcm_open,
 668        .close =        emu8k_pcm_close,
 669        .ioctl =        snd_pcm_lib_ioctl,
 670        .hw_params =    emu8k_pcm_hw_params,
 671        .hw_free =      emu8k_pcm_hw_free,
 672        .prepare =      emu8k_pcm_prepare,
 673        .trigger =      emu8k_pcm_trigger,
 674        .pointer =      emu8k_pcm_pointer,
 675        .copy =         emu8k_pcm_copy,
 676        .silence =      emu8k_pcm_silence,
 677};
 678
 679
 680static void snd_emu8000_pcm_free(struct snd_pcm *pcm)
 681{
 682        struct snd_emu8000 *emu = pcm->private_data;
 683        emu->pcm = NULL;
 684}
 685
 686int snd_emu8000_pcm_new(struct snd_card *card, struct snd_emu8000 *emu, int index)
 687{
 688        struct snd_pcm *pcm;
 689        int err;
 690
 691        if ((err = snd_pcm_new(card, "Emu8000 PCM", index, 1, 0, &pcm)) < 0)
 692                return err;
 693        pcm->private_data = emu;
 694        pcm->private_free = snd_emu8000_pcm_free;
 695        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &emu8k_pcm_ops);
 696        emu->pcm = pcm;
 697
 698        snd_device_register(card, pcm);
 699
 700        return 0;
 701}
 702