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