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