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