brintos

brintos / linux-shallow public Read only

0
0
Text · 18.6 KiB · 69c5154 Raw
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