linux/sound/isa/msnd/msnd.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * 2002/06/30 Karsten Wiese:
   4 *      removed kernel-version dependencies.
   5 *      ripped from linux kernel 2.4.18 (OSS Implementation) by me.
   6 *      In the OSS Version, this file is compiled to a separate MODULE,
   7 *      that is used by the pinnacle and the classic driver.
   8 *      since there is no classic driver for alsa yet (i dont have a classic
   9 *      & writing one blindfold is difficult) this file's object is statically
  10 *      linked into the pinnacle-driver-module for now. look for the string
  11 *              "uncomment this to make this a module again"
  12 *      to do guess what.
  13 *
  14 * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
  15 *
  16 * msnd.c - Driver Base
  17 *
  18 * Turtle Beach MultiSound Sound Card Driver for Linux
  19 *
  20 * Copyright (C) 1998 Andrew Veliath
  21 *
  22 * This program is free software; you can redistribute it and/or modify
  23 * it under the terms of the GNU General Public License as published by
  24 * the Free Software Foundation; either version 2 of the License, or
  25 * (at your option) any later version.
  26 *
  27 * This program is distributed in the hope that it will be useful,
  28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  30 * GNU General Public License for more details.
  31 *
  32 * You should have received a copy of the GNU General Public License
  33 * along with this program; if not, write to the Free Software
  34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  35 *
  36 ********************************************************************/
  37
  38#include <linux/kernel.h>
  39#include <linux/sched/signal.h>
  40#include <linux/types.h>
  41#include <linux/interrupt.h>
  42#include <linux/io.h>
  43#include <linux/fs.h>
  44#include <linux/delay.h>
  45#include <linux/module.h>
  46
  47#include <sound/core.h>
  48#include <sound/initval.h>
  49#include <sound/pcm.h>
  50#include <sound/pcm_params.h>
  51
  52#include "msnd.h"
  53
  54#define LOGNAME                 "msnd"
  55
  56
  57void snd_msnd_init_queue(void *base, int start, int size)
  58{
  59        writew(PCTODSP_BASED(start), base + JQS_wStart);
  60        writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
  61        writew(0, base + JQS_wHead);
  62        writew(0, base + JQS_wTail);
  63}
  64EXPORT_SYMBOL(snd_msnd_init_queue);
  65
  66static int snd_msnd_wait_TXDE(struct snd_msnd *dev)
  67{
  68        unsigned int io = dev->io;
  69        int timeout = 1000;
  70
  71        while (timeout-- > 0)
  72                if (inb(io + HP_ISR) & HPISR_TXDE)
  73                        return 0;
  74
  75        return -EIO;
  76}
  77
  78static int snd_msnd_wait_HC0(struct snd_msnd *dev)
  79{
  80        unsigned int io = dev->io;
  81        int timeout = 1000;
  82
  83        while (timeout-- > 0)
  84                if (!(inb(io + HP_CVR) & HPCVR_HC))
  85                        return 0;
  86
  87        return -EIO;
  88}
  89
  90int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
  91{
  92        unsigned long flags;
  93
  94        spin_lock_irqsave(&dev->lock, flags);
  95        if (snd_msnd_wait_HC0(dev) == 0) {
  96                outb(cmd, dev->io + HP_CVR);
  97                spin_unlock_irqrestore(&dev->lock, flags);
  98                return 0;
  99        }
 100        spin_unlock_irqrestore(&dev->lock, flags);
 101
 102        snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n");
 103
 104        return -EIO;
 105}
 106EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
 107
 108int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
 109                   unsigned char mid, unsigned char low)
 110{
 111        unsigned int io = dev->io;
 112
 113        if (snd_msnd_wait_TXDE(dev) == 0) {
 114                outb(high, io + HP_TXH);
 115                outb(mid, io + HP_TXM);
 116                outb(low, io + HP_TXL);
 117                return 0;
 118        }
 119
 120        snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n");
 121
 122        return -EIO;
 123}
 124EXPORT_SYMBOL(snd_msnd_send_word);
 125
 126int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
 127{
 128        int i;
 129
 130        if (len % 3 != 0) {
 131                snd_printk(KERN_ERR LOGNAME
 132                           ": Upload host data not multiple of 3!\n");
 133                return -EINVAL;
 134        }
 135
 136        for (i = 0; i < len; i += 3)
 137                if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]))
 138                        return -EIO;
 139
 140        inb(dev->io + HP_RXL);
 141        inb(dev->io + HP_CVR);
 142
 143        return 0;
 144}
 145EXPORT_SYMBOL(snd_msnd_upload_host);
 146
 147int snd_msnd_enable_irq(struct snd_msnd *dev)
 148{
 149        unsigned long flags;
 150
 151        if (dev->irq_ref++)
 152                return 0;
 153
 154        snd_printdd(LOGNAME ": Enabling IRQ\n");
 155
 156        spin_lock_irqsave(&dev->lock, flags);
 157        if (snd_msnd_wait_TXDE(dev) == 0) {
 158                outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
 159                if (dev->type == msndClassic)
 160                        outb(dev->irqid, dev->io + HP_IRQM);
 161
 162                outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
 163                outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
 164                enable_irq(dev->irq);
 165                snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
 166                                    dev->dspq_buff_size);
 167                spin_unlock_irqrestore(&dev->lock, flags);
 168                return 0;
 169        }
 170        spin_unlock_irqrestore(&dev->lock, flags);
 171
 172        snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n");
 173
 174        return -EIO;
 175}
 176EXPORT_SYMBOL(snd_msnd_enable_irq);
 177
 178int snd_msnd_disable_irq(struct snd_msnd *dev)
 179{
 180        unsigned long flags;
 181
 182        if (--dev->irq_ref > 0)
 183                return 0;
 184
 185        if (dev->irq_ref < 0)
 186                snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
 187                           dev->irq_ref);
 188
 189        snd_printdd(LOGNAME ": Disabling IRQ\n");
 190
 191        spin_lock_irqsave(&dev->lock, flags);
 192        if (snd_msnd_wait_TXDE(dev) == 0) {
 193                outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
 194                if (dev->type == msndClassic)
 195                        outb(HPIRQ_NONE, dev->io + HP_IRQM);
 196                disable_irq(dev->irq);
 197                spin_unlock_irqrestore(&dev->lock, flags);
 198                return 0;
 199        }
 200        spin_unlock_irqrestore(&dev->lock, flags);
 201
 202        snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
 203
 204        return -EIO;
 205}
 206EXPORT_SYMBOL(snd_msnd_disable_irq);
 207
 208static inline long get_play_delay_jiffies(struct snd_msnd *chip, long size)
 209{
 210        long tmp = (size * HZ * chip->play_sample_size) / 8;
 211        return tmp / (chip->play_sample_rate * chip->play_channels);
 212}
 213
 214static void snd_msnd_dsp_write_flush(struct snd_msnd *chip)
 215{
 216        if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags))
 217                return;
 218        set_bit(F_WRITEFLUSH, &chip->flags);
 219/*      interruptible_sleep_on_timeout(
 220                &chip->writeflush,
 221                get_play_delay_jiffies(&chip, chip->DAPF.len));*/
 222        clear_bit(F_WRITEFLUSH, &chip->flags);
 223        if (!signal_pending(current))
 224                schedule_timeout_interruptible(
 225                        get_play_delay_jiffies(chip, chip->play_period_bytes));
 226        clear_bit(F_WRITING, &chip->flags);
 227}
 228
 229void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
 230{
 231        if ((file ? file->f_mode : chip->mode) & FMODE_READ) {
 232                clear_bit(F_READING, &chip->flags);
 233                snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
 234                snd_msnd_disable_irq(chip);
 235                if (file) {
 236                        snd_printd(KERN_INFO LOGNAME
 237                                   ": Stopping read for %p\n", file);
 238                        chip->mode &= ~FMODE_READ;
 239                }
 240                clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
 241        }
 242        if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) {
 243                if (test_bit(F_WRITING, &chip->flags)) {
 244                        snd_msnd_dsp_write_flush(chip);
 245                        snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
 246                }
 247                snd_msnd_disable_irq(chip);
 248                if (file) {
 249                        snd_printd(KERN_INFO
 250                                   LOGNAME ": Stopping write for %p\n", file);
 251                        chip->mode &= ~FMODE_WRITE;
 252                }
 253                clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
 254        }
 255}
 256EXPORT_SYMBOL(snd_msnd_dsp_halt);
 257
 258
 259int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
 260{
 261        int /*size, n,*/ timeout = 3;
 262        u16 wTmp;
 263        /* void *DAQD; */
 264
 265        /* Increment the tail and check for queue wrap */
 266        wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
 267        if (wTmp > readw(chip->DARQ + JQS_wSize))
 268                wTmp = 0;
 269        while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--)
 270                udelay(1);
 271
 272        if (chip->capturePeriods == 2) {
 273                void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
 274                             bank * DAQDS__size + DAQDS_wStart;
 275                unsigned short offset = 0x3000 + chip->capturePeriodBytes;
 276
 277                if (readw(pDAQ) != PCTODSP_BASED(0x3000))
 278                        offset = 0x3000;
 279                writew(PCTODSP_BASED(offset), pDAQ);
 280        }
 281
 282        writew(wTmp, chip->DARQ + JQS_wTail);
 283
 284#if 0
 285        /* Get our digital audio queue struct */
 286        DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF;
 287
 288        /* Get length of data */
 289        size = readw(DAQD + DAQDS_wSize);
 290
 291        /* Read data from the head (unprotected bank 1 access okay
 292           since this is only called inside an interrupt) */
 293        outb(HPBLKSEL_1, chip->io + HP_BLKS);
 294        n = msnd_fifo_write(&chip->DARF,
 295                            (char *)(chip->base + bank * DAR_BUFF_SIZE),
 296                            size, 0);
 297        if (n <= 0) {
 298                outb(HPBLKSEL_0, chip->io + HP_BLKS);
 299                return n;
 300        }
 301        outb(HPBLKSEL_0, chip->io + HP_BLKS);
 302#endif
 303
 304        return 1;
 305}
 306EXPORT_SYMBOL(snd_msnd_DARQ);
 307
 308int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
 309{
 310        u16     DAPQ_tail;
 311        int     protect = start, nbanks = 0;
 312        void    *DAQD;
 313        static int play_banks_submitted;
 314        /* unsigned long flags;
 315        spin_lock_irqsave(&chip->lock, flags); not necessary */
 316
 317        DAPQ_tail = readw(chip->DAPQ + JQS_wTail);
 318        while (DAPQ_tail != readw(chip->DAPQ + JQS_wHead) || start) {
 319                int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
 320
 321                if (start) {
 322                        start = 0;
 323                        play_banks_submitted = 0;
 324                }
 325
 326                /* Get our digital audio queue struct */
 327                DAQD = bank_num * DAQDS__size + chip->mappedbase +
 328                        DAPQ_DATA_BUFF;
 329
 330                /* Write size of this bank */
 331                writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
 332                if (play_banks_submitted < 3)
 333                        ++play_banks_submitted;
 334                else if (chip->playPeriods == 2) {
 335                        unsigned short offset = chip->play_period_bytes;
 336
 337                        if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
 338                                offset = 0;
 339
 340                        writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart);
 341                }
 342                ++nbanks;
 343
 344                /* Then advance the tail */
 345                /*
 346                if (protect)
 347                        snd_printd(KERN_INFO "B %X %lX\n",
 348                                   bank_num, xtime.tv_usec);
 349                */
 350
 351                DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
 352                writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
 353                /* Tell the DSP to play the bank */
 354                snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START);
 355                if (protect)
 356                        if (2 == bank_num)
 357                                break;
 358        }
 359        /*
 360        if (protect)
 361                snd_printd(KERN_INFO "%lX\n", xtime.tv_usec);
 362        */
 363        /* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
 364        return nbanks;
 365}
 366EXPORT_SYMBOL(snd_msnd_DAPQ);
 367
 368static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
 369                                      unsigned int pcm_periods,
 370                                      unsigned int pcm_count)
 371{
 372        int     n;
 373        void    *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
 374
 375        chip->last_playbank = -1;
 376        chip->playLimit = pcm_count * (pcm_periods - 1);
 377        chip->playPeriods = pcm_periods;
 378        writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
 379        writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
 380
 381        chip->play_period_bytes = pcm_count;
 382
 383        for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
 384                writew(PCTODSP_BASED((u32)(pcm_count * n)),
 385                        pDAQ + DAQDS_wStart);
 386                writew(0, pDAQ + DAQDS_wSize);
 387                writew(1, pDAQ + DAQDS_wFormat);
 388                writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
 389                writew(chip->play_channels, pDAQ + DAQDS_wChannels);
 390                writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
 391                writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
 392                writew(n, pDAQ + DAQDS_wFlags);
 393        }
 394}
 395
 396static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
 397                                         unsigned int pcm_periods,
 398                                         unsigned int pcm_count)
 399{
 400        int             n;
 401        void            *pDAQ;
 402        /* unsigned long        flags; */
 403
 404        /* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
 405
 406        chip->last_recbank = 2;
 407        chip->captureLimit = pcm_count * (pcm_periods - 1);
 408        chip->capturePeriods = pcm_periods;
 409        writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
 410        writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size),
 411                chip->DARQ + JQS_wTail);
 412
 413#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
 414        spin_lock_irqsave(&chip->lock, flags);
 415        outb(HPBLKSEL_1, chip->io + HP_BLKS);
 416        memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
 417        outb(HPBLKSEL_0, chip->io + HP_BLKS);
 418        spin_unlock_irqrestore(&chip->lock, flags);
 419#endif
 420
 421        chip->capturePeriodBytes = pcm_count;
 422        snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
 423
 424        pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
 425
 426        for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
 427                u32 tmp = pcm_count * n;
 428
 429                writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart);
 430                writew(pcm_count, pDAQ + DAQDS_wSize);
 431                writew(1, pDAQ + DAQDS_wFormat);
 432                writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
 433                writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
 434                writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
 435                writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
 436                writew(n, pDAQ + DAQDS_wFlags);
 437        }
 438}
 439
 440static const struct snd_pcm_hardware snd_msnd_playback = {
 441        .info =                 SNDRV_PCM_INFO_MMAP |
 442                                SNDRV_PCM_INFO_INTERLEAVED |
 443                                SNDRV_PCM_INFO_MMAP_VALID |
 444                                SNDRV_PCM_INFO_BATCH,
 445        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
 446        .rates =                SNDRV_PCM_RATE_8000_48000,
 447        .rate_min =             8000,
 448        .rate_max =             48000,
 449        .channels_min =         1,
 450        .channels_max =         2,
 451        .buffer_bytes_max =     0x3000,
 452        .period_bytes_min =     0x40,
 453        .period_bytes_max =     0x1800,
 454        .periods_min =          2,
 455        .periods_max =          3,
 456        .fifo_size =            0,
 457};
 458
 459static const struct snd_pcm_hardware snd_msnd_capture = {
 460        .info =                 SNDRV_PCM_INFO_MMAP |
 461                                SNDRV_PCM_INFO_INTERLEAVED |
 462                                SNDRV_PCM_INFO_MMAP_VALID |
 463                                SNDRV_PCM_INFO_BATCH,
 464        .formats =              SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
 465        .rates =                SNDRV_PCM_RATE_8000_48000,
 466        .rate_min =             8000,
 467        .rate_max =             48000,
 468        .channels_min =         1,
 469        .channels_max =         2,
 470        .buffer_bytes_max =     0x3000,
 471        .period_bytes_min =     0x40,
 472        .period_bytes_max =     0x1800,
 473        .periods_min =          2,
 474        .periods_max =          3,
 475        .fifo_size =            0,
 476};
 477
 478
 479static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
 480{
 481        struct snd_pcm_runtime *runtime = substream->runtime;
 482        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 483
 484        set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
 485        clear_bit(F_WRITING, &chip->flags);
 486        snd_msnd_enable_irq(chip);
 487
 488        runtime->dma_area = chip->mappedbase;
 489        runtime->dma_bytes = 0x3000;
 490
 491        chip->playback_substream = substream;
 492        runtime->hw = snd_msnd_playback;
 493        return 0;
 494}
 495
 496static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
 497{
 498        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 499
 500        snd_msnd_disable_irq(chip);
 501        clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
 502        return 0;
 503}
 504
 505
 506static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream,
 507                                        struct snd_pcm_hw_params *params)
 508{
 509        int     i;
 510        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 511        void    *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
 512
 513        chip->play_sample_size = snd_pcm_format_width(params_format(params));
 514        chip->play_channels = params_channels(params);
 515        chip->play_sample_rate = params_rate(params);
 516
 517        for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
 518                writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
 519                writew(chip->play_channels, pDAQ + DAQDS_wChannels);
 520                writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
 521        }
 522        /* dont do this here:
 523         * snd_msnd_calibrate_adc(chip->play_sample_rate);
 524         */
 525
 526        return 0;
 527}
 528
 529static int snd_msnd_playback_prepare(struct snd_pcm_substream *substream)
 530{
 531        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 532        unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
 533        unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
 534        unsigned int pcm_periods = pcm_size / pcm_count;
 535
 536        snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
 537        chip->playDMAPos = 0;
 538        return 0;
 539}
 540
 541static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream,
 542                                     int cmd)
 543{
 544        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 545        int     result = 0;
 546
 547        if (cmd == SNDRV_PCM_TRIGGER_START) {
 548                snd_printdd("snd_msnd_playback_trigger(START)\n");
 549                chip->banksPlayed = 0;
 550                set_bit(F_WRITING, &chip->flags);
 551                snd_msnd_DAPQ(chip, 1);
 552        } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
 553                snd_printdd("snd_msnd_playback_trigger(STop)\n");
 554                /* interrupt diagnostic, comment this out later */
 555                clear_bit(F_WRITING, &chip->flags);
 556                snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
 557        } else {
 558                snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
 559                result = -EINVAL;
 560        }
 561
 562        snd_printdd("snd_msnd_playback_trigger() ENDE\n");
 563        return result;
 564}
 565
 566static snd_pcm_uframes_t
 567snd_msnd_playback_pointer(struct snd_pcm_substream *substream)
 568{
 569        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 570
 571        return bytes_to_frames(substream->runtime, chip->playDMAPos);
 572}
 573
 574
 575static const struct snd_pcm_ops snd_msnd_playback_ops = {
 576        .open =         snd_msnd_playback_open,
 577        .close =        snd_msnd_playback_close,
 578        .ioctl =        snd_pcm_lib_ioctl,
 579        .hw_params =    snd_msnd_playback_hw_params,
 580        .prepare =      snd_msnd_playback_prepare,
 581        .trigger =      snd_msnd_playback_trigger,
 582        .pointer =      snd_msnd_playback_pointer,
 583};
 584
 585static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
 586{
 587        struct snd_pcm_runtime *runtime = substream->runtime;
 588        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 589
 590        set_bit(F_AUDIO_READ_INUSE, &chip->flags);
 591        snd_msnd_enable_irq(chip);
 592        runtime->dma_area = chip->mappedbase + 0x3000;
 593        runtime->dma_bytes = 0x3000;
 594        memset(runtime->dma_area, 0, runtime->dma_bytes);
 595        chip->capture_substream = substream;
 596        runtime->hw = snd_msnd_capture;
 597        return 0;
 598}
 599
 600static int snd_msnd_capture_close(struct snd_pcm_substream *substream)
 601{
 602        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 603
 604        snd_msnd_disable_irq(chip);
 605        clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
 606        return 0;
 607}
 608
 609static int snd_msnd_capture_prepare(struct snd_pcm_substream *substream)
 610{
 611        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 612        unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
 613        unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
 614        unsigned int pcm_periods = pcm_size / pcm_count;
 615
 616        snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count);
 617        chip->captureDMAPos = 0;
 618        return 0;
 619}
 620
 621static int snd_msnd_capture_trigger(struct snd_pcm_substream *substream,
 622                                    int cmd)
 623{
 624        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 625
 626        if (cmd == SNDRV_PCM_TRIGGER_START) {
 627                chip->last_recbank = -1;
 628                set_bit(F_READING, &chip->flags);
 629                if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0)
 630                        return 0;
 631
 632                clear_bit(F_READING, &chip->flags);
 633        } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
 634                clear_bit(F_READING, &chip->flags);
 635                snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
 636                return 0;
 637        }
 638        return -EINVAL;
 639}
 640
 641
 642static snd_pcm_uframes_t
 643snd_msnd_capture_pointer(struct snd_pcm_substream *substream)
 644{
 645        struct snd_pcm_runtime *runtime = substream->runtime;
 646        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 647
 648        return bytes_to_frames(runtime, chip->captureDMAPos);
 649}
 650
 651
 652static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream,
 653                                        struct snd_pcm_hw_params *params)
 654{
 655        int             i;
 656        struct snd_msnd *chip = snd_pcm_substream_chip(substream);
 657        void            *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
 658
 659        chip->capture_sample_size = snd_pcm_format_width(params_format(params));
 660        chip->capture_channels = params_channels(params);
 661        chip->capture_sample_rate = params_rate(params);
 662
 663        for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
 664                writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
 665                writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
 666                writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
 667        }
 668        return 0;
 669}
 670
 671
 672static const struct snd_pcm_ops snd_msnd_capture_ops = {
 673        .open =         snd_msnd_capture_open,
 674        .close =        snd_msnd_capture_close,
 675        .ioctl =        snd_pcm_lib_ioctl,
 676        .hw_params =    snd_msnd_capture_hw_params,
 677        .prepare =      snd_msnd_capture_prepare,
 678        .trigger =      snd_msnd_capture_trigger,
 679        .pointer =      snd_msnd_capture_pointer,
 680};
 681
 682
 683int snd_msnd_pcm(struct snd_card *card, int device)
 684{
 685        struct snd_msnd *chip = card->private_data;
 686        struct snd_pcm  *pcm;
 687        int err;
 688
 689        err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm);
 690        if (err < 0)
 691                return err;
 692
 693        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops);
 694        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
 695
 696        pcm->private_data = chip;
 697        strcpy(pcm->name, "Hurricane");
 698
 699        return 0;
 700}
 701EXPORT_SYMBOL(snd_msnd_pcm);
 702
 703MODULE_DESCRIPTION("Common routines for Turtle Beach Multisound drivers");
 704MODULE_LICENSE("GPL");
 705
 706