File Index
Files and directories
Sign in
FILE

msnd.c

File preview with syntax highlighting.

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