123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705 |
- /*********************************************************************
- *
- * 2002/06/30 Karsten Wiese:
- * removed kernel-version dependencies.
- * ripped from linux kernel 2.4.18 (OSS Implementation) by me.
- * In the OSS Version, this file is compiled to a separate MODULE,
- * that is used by the pinnacle and the classic driver.
- * since there is no classic driver for alsa yet (i dont have a classic
- * & writing one blindfold is difficult) this file's object is statically
- * linked into the pinnacle-driver-module for now. look for the string
- * "uncomment this to make this a module again"
- * to do guess what.
- *
- * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
- *
- * msnd.c - Driver Base
- *
- * Turtle Beach MultiSound Sound Card Driver for Linux
- *
- * Copyright (C) 1998 Andrew Veliath
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ********************************************************************/
- #include <linux/kernel.h>
- #include <linux/types.h>
- #include <linux/interrupt.h>
- #include <linux/io.h>
- #include <linux/fs.h>
- #include <linux/delay.h>
- #include <linux/module.h>
- #include <sound/core.h>
- #include <sound/initval.h>
- #include <sound/pcm.h>
- #include <sound/pcm_params.h>
- #include "msnd.h"
- #define LOGNAME "msnd"
- void snd_msnd_init_queue(void *base, int start, int size)
- {
- writew(PCTODSP_BASED(start), base + JQS_wStart);
- writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
- writew(0, base + JQS_wHead);
- writew(0, base + JQS_wTail);
- }
- EXPORT_SYMBOL(snd_msnd_init_queue);
- static int snd_msnd_wait_TXDE(struct snd_msnd *dev)
- {
- unsigned int io = dev->io;
- int timeout = 1000;
- while (timeout-- > 0)
- if (inb(io + HP_ISR) & HPISR_TXDE)
- return 0;
- return -EIO;
- }
- static int snd_msnd_wait_HC0(struct snd_msnd *dev)
- {
- unsigned int io = dev->io;
- int timeout = 1000;
- while (timeout-- > 0)
- if (!(inb(io + HP_CVR) & HPCVR_HC))
- return 0;
- return -EIO;
- }
- int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
- {
- unsigned long flags;
- spin_lock_irqsave(&dev->lock, flags);
- if (snd_msnd_wait_HC0(dev) == 0) {
- outb(cmd, dev->io + HP_CVR);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n");
- return -EIO;
- }
- EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
- int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
- unsigned char mid, unsigned char low)
- {
- unsigned int io = dev->io;
- if (snd_msnd_wait_TXDE(dev) == 0) {
- outb(high, io + HP_TXH);
- outb(mid, io + HP_TXM);
- outb(low, io + HP_TXL);
- return 0;
- }
- snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n");
- return -EIO;
- }
- EXPORT_SYMBOL(snd_msnd_send_word);
- int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
- {
- int i;
- if (len % 3 != 0) {
- snd_printk(KERN_ERR LOGNAME
- ": Upload host data not multiple of 3!\n");
- return -EINVAL;
- }
- for (i = 0; i < len; i += 3)
- if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]))
- return -EIO;
- inb(dev->io + HP_RXL);
- inb(dev->io + HP_CVR);
- return 0;
- }
- EXPORT_SYMBOL(snd_msnd_upload_host);
- int snd_msnd_enable_irq(struct snd_msnd *dev)
- {
- unsigned long flags;
- if (dev->irq_ref++)
- return 0;
- snd_printdd(LOGNAME ": Enabling IRQ\n");
- spin_lock_irqsave(&dev->lock, flags);
- if (snd_msnd_wait_TXDE(dev) == 0) {
- outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
- if (dev->type == msndClassic)
- outb(dev->irqid, dev->io + HP_IRQM);
- outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
- outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
- enable_irq(dev->irq);
- snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
- dev->dspq_buff_size);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n");
- return -EIO;
- }
- EXPORT_SYMBOL(snd_msnd_enable_irq);
- int snd_msnd_disable_irq(struct snd_msnd *dev)
- {
- unsigned long flags;
- if (--dev->irq_ref > 0)
- return 0;
- if (dev->irq_ref < 0)
- snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
- dev->irq_ref);
- snd_printdd(LOGNAME ": Disabling IRQ\n");
- spin_lock_irqsave(&dev->lock, flags);
- if (snd_msnd_wait_TXDE(dev) == 0) {
- outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
- if (dev->type == msndClassic)
- outb(HPIRQ_NONE, dev->io + HP_IRQM);
- disable_irq(dev->irq);
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
- snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
- return -EIO;
- }
- EXPORT_SYMBOL(snd_msnd_disable_irq);
- static inline long get_play_delay_jiffies(struct snd_msnd *chip, long size)
- {
- long tmp = (size * HZ * chip->play_sample_size) / 8;
- return tmp / (chip->play_sample_rate * chip->play_channels);
- }
- static void snd_msnd_dsp_write_flush(struct snd_msnd *chip)
- {
- if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags))
- return;
- set_bit(F_WRITEFLUSH, &chip->flags);
- /* interruptible_sleep_on_timeout(
- &chip->writeflush,
- get_play_delay_jiffies(&chip, chip->DAPF.len));*/
- clear_bit(F_WRITEFLUSH, &chip->flags);
- if (!signal_pending(current))
- schedule_timeout_interruptible(
- get_play_delay_jiffies(chip, chip->play_period_bytes));
- clear_bit(F_WRITING, &chip->flags);
- }
- void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
- {
- if ((file ? file->f_mode : chip->mode) & FMODE_READ) {
- clear_bit(F_READING, &chip->flags);
- snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
- snd_msnd_disable_irq(chip);
- if (file) {
- snd_printd(KERN_INFO LOGNAME
- ": Stopping read for %p\n", file);
- chip->mode &= ~FMODE_READ;
- }
- clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
- }
- if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) {
- if (test_bit(F_WRITING, &chip->flags)) {
- snd_msnd_dsp_write_flush(chip);
- snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
- }
- snd_msnd_disable_irq(chip);
- if (file) {
- snd_printd(KERN_INFO
- LOGNAME ": Stopping write for %p\n", file);
- chip->mode &= ~FMODE_WRITE;
- }
- clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
- }
- }
- EXPORT_SYMBOL(snd_msnd_dsp_halt);
- int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
- {
- int /*size, n,*/ timeout = 3;
- u16 wTmp;
- /* void *DAQD; */
- /* Increment the tail and check for queue wrap */
- wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
- if (wTmp > readw(chip->DARQ + JQS_wSize))
- wTmp = 0;
- while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--)
- udelay(1);
- if (chip->capturePeriods == 2) {
- void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
- bank * DAQDS__size + DAQDS_wStart;
- unsigned short offset = 0x3000 + chip->capturePeriodBytes;
- if (readw(pDAQ) != PCTODSP_BASED(0x3000))
- offset = 0x3000;
- writew(PCTODSP_BASED(offset), pDAQ);
- }
- writew(wTmp, chip->DARQ + JQS_wTail);
- #if 0
- /* Get our digital audio queue struct */
- DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF;
- /* Get length of data */
- size = readw(DAQD + DAQDS_wSize);
- /* Read data from the head (unprotected bank 1 access okay
- since this is only called inside an interrupt) */
- outb(HPBLKSEL_1, chip->io + HP_BLKS);
- n = msnd_fifo_write(&chip->DARF,
- (char *)(chip->base + bank * DAR_BUFF_SIZE),
- size, 0);
- if (n <= 0) {
- outb(HPBLKSEL_0, chip->io + HP_BLKS);
- return n;
- }
- outb(HPBLKSEL_0, chip->io + HP_BLKS);
- #endif
- return 1;
- }
- EXPORT_SYMBOL(snd_msnd_DARQ);
- int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
- {
- u16 DAPQ_tail;
- int protect = start, nbanks = 0;
- void *DAQD;
- static int play_banks_submitted;
- /* unsigned long flags;
- spin_lock_irqsave(&chip->lock, flags); not necessary */
- DAPQ_tail = readw(chip->DAPQ + JQS_wTail);
- while (DAPQ_tail != readw(chip->DAPQ + JQS_wHead) || start) {
- int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
- if (start) {
- start = 0;
- play_banks_submitted = 0;
- }
- /* Get our digital audio queue struct */
- DAQD = bank_num * DAQDS__size + chip->mappedbase +
- DAPQ_DATA_BUFF;
- /* Write size of this bank */
- writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
- if (play_banks_submitted < 3)
- ++play_banks_submitted;
- else if (chip->playPeriods == 2) {
- unsigned short offset = chip->play_period_bytes;
- if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
- offset = 0;
- writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart);
- }
- ++nbanks;
- /* Then advance the tail */
- /*
- if (protect)
- snd_printd(KERN_INFO "B %X %lX\n",
- bank_num, xtime.tv_usec);
- */
- DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
- writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
- /* Tell the DSP to play the bank */
- snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START);
- if (protect)
- if (2 == bank_num)
- break;
- }
- /*
- if (protect)
- snd_printd(KERN_INFO "%lX\n", xtime.tv_usec);
- */
- /* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
- return nbanks;
- }
- EXPORT_SYMBOL(snd_msnd_DAPQ);
- static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
- unsigned int pcm_periods,
- unsigned int pcm_count)
- {
- int n;
- void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
- chip->last_playbank = -1;
- chip->playLimit = pcm_count * (pcm_periods - 1);
- chip->playPeriods = pcm_periods;
- writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
- writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
- chip->play_period_bytes = pcm_count;
- for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
- writew(PCTODSP_BASED((u32)(pcm_count * n)),
- pDAQ + DAQDS_wStart);
- writew(0, pDAQ + DAQDS_wSize);
- writew(1, pDAQ + DAQDS_wFormat);
- writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
- writew(chip->play_channels, pDAQ + DAQDS_wChannels);
- writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
- writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
- writew(n, pDAQ + DAQDS_wFlags);
- }
- }
- static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
- unsigned int pcm_periods,
- unsigned int pcm_count)
- {
- int n;
- void *pDAQ;
- /* unsigned long flags; */
- /* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
- chip->last_recbank = 2;
- chip->captureLimit = pcm_count * (pcm_periods - 1);
- chip->capturePeriods = pcm_periods;
- writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
- writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size),
- chip->DARQ + JQS_wTail);
- #if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
- spin_lock_irqsave(&chip->lock, flags);
- outb(HPBLKSEL_1, chip->io + HP_BLKS);
- memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
- outb(HPBLKSEL_0, chip->io + HP_BLKS);
- spin_unlock_irqrestore(&chip->lock, flags);
- #endif
- chip->capturePeriodBytes = pcm_count;
- snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
- pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
- for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
- u32 tmp = pcm_count * n;
- writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart);
- writew(pcm_count, pDAQ + DAQDS_wSize);
- writew(1, pDAQ + DAQDS_wFormat);
- writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
- writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
- writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
- writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
- writew(n, pDAQ + DAQDS_wFlags);
- }
- }
- static struct snd_pcm_hardware snd_msnd_playback = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_BATCH,
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = 0x3000,
- .period_bytes_min = 0x40,
- .period_bytes_max = 0x1800,
- .periods_min = 2,
- .periods_max = 3,
- .fifo_size = 0,
- };
- static struct snd_pcm_hardware snd_msnd_capture = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_BATCH,
- .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_8000_48000,
- .rate_min = 8000,
- .rate_max = 48000,
- .channels_min = 1,
- .channels_max = 2,
- .buffer_bytes_max = 0x3000,
- .period_bytes_min = 0x40,
- .period_bytes_max = 0x1800,
- .periods_min = 2,
- .periods_max = 3,
- .fifo_size = 0,
- };
- static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
- {
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
- clear_bit(F_WRITING, &chip->flags);
- snd_msnd_enable_irq(chip);
- runtime->dma_area = chip->mappedbase;
- runtime->dma_bytes = 0x3000;
- chip->playback_substream = substream;
- runtime->hw = snd_msnd_playback;
- return 0;
- }
- static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
- {
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- snd_msnd_disable_irq(chip);
- clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
- return 0;
- }
- static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
- {
- int i;
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
- chip->play_sample_size = snd_pcm_format_width(params_format(params));
- chip->play_channels = params_channels(params);
- chip->play_sample_rate = params_rate(params);
- for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
- writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
- writew(chip->play_channels, pDAQ + DAQDS_wChannels);
- writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
- }
- /* dont do this here:
- * snd_msnd_calibrate_adc(chip->play_sample_rate);
- */
- return 0;
- }
- static int snd_msnd_playback_prepare(struct snd_pcm_substream *substream)
- {
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
- unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
- unsigned int pcm_periods = pcm_size / pcm_count;
- snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
- chip->playDMAPos = 0;
- return 0;
- }
- static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream,
- int cmd)
- {
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- int result = 0;
- if (cmd == SNDRV_PCM_TRIGGER_START) {
- snd_printdd("snd_msnd_playback_trigger(START)\n");
- chip->banksPlayed = 0;
- set_bit(F_WRITING, &chip->flags);
- snd_msnd_DAPQ(chip, 1);
- } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- snd_printdd("snd_msnd_playback_trigger(STop)\n");
- /* interrupt diagnostic, comment this out later */
- clear_bit(F_WRITING, &chip->flags);
- snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
- } else {
- snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
- result = -EINVAL;
- }
- snd_printdd("snd_msnd_playback_trigger() ENDE\n");
- return result;
- }
- static snd_pcm_uframes_t
- snd_msnd_playback_pointer(struct snd_pcm_substream *substream)
- {
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- return bytes_to_frames(substream->runtime, chip->playDMAPos);
- }
- static struct snd_pcm_ops snd_msnd_playback_ops = {
- .open = snd_msnd_playback_open,
- .close = snd_msnd_playback_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_msnd_playback_hw_params,
- .prepare = snd_msnd_playback_prepare,
- .trigger = snd_msnd_playback_trigger,
- .pointer = snd_msnd_playback_pointer,
- };
- static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
- {
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- set_bit(F_AUDIO_READ_INUSE, &chip->flags);
- snd_msnd_enable_irq(chip);
- runtime->dma_area = chip->mappedbase + 0x3000;
- runtime->dma_bytes = 0x3000;
- memset(runtime->dma_area, 0, runtime->dma_bytes);
- chip->capture_substream = substream;
- runtime->hw = snd_msnd_capture;
- return 0;
- }
- static int snd_msnd_capture_close(struct snd_pcm_substream *substream)
- {
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- snd_msnd_disable_irq(chip);
- clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
- return 0;
- }
- static int snd_msnd_capture_prepare(struct snd_pcm_substream *substream)
- {
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
- unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
- unsigned int pcm_periods = pcm_size / pcm_count;
- snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count);
- chip->captureDMAPos = 0;
- return 0;
- }
- static int snd_msnd_capture_trigger(struct snd_pcm_substream *substream,
- int cmd)
- {
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- if (cmd == SNDRV_PCM_TRIGGER_START) {
- chip->last_recbank = -1;
- set_bit(F_READING, &chip->flags);
- if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0)
- return 0;
- clear_bit(F_READING, &chip->flags);
- } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
- clear_bit(F_READING, &chip->flags);
- snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
- return 0;
- }
- return -EINVAL;
- }
- static snd_pcm_uframes_t
- snd_msnd_capture_pointer(struct snd_pcm_substream *substream)
- {
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- return bytes_to_frames(runtime, chip->captureDMAPos);
- }
- static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
- {
- int i;
- struct snd_msnd *chip = snd_pcm_substream_chip(substream);
- void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
- chip->capture_sample_size = snd_pcm_format_width(params_format(params));
- chip->capture_channels = params_channels(params);
- chip->capture_sample_rate = params_rate(params);
- for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
- writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
- writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
- writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
- }
- return 0;
- }
- static struct snd_pcm_ops snd_msnd_capture_ops = {
- .open = snd_msnd_capture_open,
- .close = snd_msnd_capture_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_msnd_capture_hw_params,
- .prepare = snd_msnd_capture_prepare,
- .trigger = snd_msnd_capture_trigger,
- .pointer = snd_msnd_capture_pointer,
- };
- int snd_msnd_pcm(struct snd_card *card, int device)
- {
- struct snd_msnd *chip = card->private_data;
- struct snd_pcm *pcm;
- int err;
- err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm);
- if (err < 0)
- return err;
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
- pcm->private_data = chip;
- strcpy(pcm->name, "Hurricane");
- return 0;
- }
- EXPORT_SYMBOL(snd_msnd_pcm);
- MODULE_DESCRIPTION("Common routines for Turtle Beach Multisound drivers");
- MODULE_LICENSE("GPL");
|