xref: /OK3568_Linux_fs/kernel/sound/isa/msnd/msnd_pinnacle.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*********************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Linux multisound pinnacle/fiji driver for ALSA.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * 2002/06/30 Karsten Wiese:
7*4882a593Smuzhiyun  *	for now this is only used to build a pinnacle / fiji driver.
8*4882a593Smuzhiyun  *	the OSS parent of this code is designed to also support
9*4882a593Smuzhiyun  *	the multisound classic via the file msnd_classic.c.
10*4882a593Smuzhiyun  *	to make it easier for some brave heart to implemt classic
11*4882a593Smuzhiyun  *	support in alsa, i left all the MSND_CLASSIC tokens in this file.
12*4882a593Smuzhiyun  *	but for now this untested & undone.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * ripped from linux kernel 2.4.18 by Karsten Wiese.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * Turtle Beach MultiSound Sound Card Driver for Linux
19*4882a593Smuzhiyun  * msnd_pinnacle.c / msnd_classic.c
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * -- If MSND_CLASSIC is defined:
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  *     -> driver for Turtle Beach Classic/Monterey/Tahiti
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * -- Else
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  *     -> driver for Turtle Beach Pinnacle/Fiji
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * 12-3-2000  Modified IO port validation  Steve Sycamore
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * Copyright (C) 1998 Andrew Veliath
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  ********************************************************************/
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #include <linux/kernel.h>
36*4882a593Smuzhiyun #include <linux/module.h>
37*4882a593Smuzhiyun #include <linux/interrupt.h>
38*4882a593Smuzhiyun #include <linux/types.h>
39*4882a593Smuzhiyun #include <linux/delay.h>
40*4882a593Smuzhiyun #include <linux/ioport.h>
41*4882a593Smuzhiyun #include <linux/firmware.h>
42*4882a593Smuzhiyun #include <linux/isa.h>
43*4882a593Smuzhiyun #include <linux/isapnp.h>
44*4882a593Smuzhiyun #include <linux/irq.h>
45*4882a593Smuzhiyun #include <linux/io.h>
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #include <sound/core.h>
48*4882a593Smuzhiyun #include <sound/initval.h>
49*4882a593Smuzhiyun #include <sound/asound.h>
50*4882a593Smuzhiyun #include <sound/pcm.h>
51*4882a593Smuzhiyun #include <sound/mpu401.h>
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #ifdef MSND_CLASSIC
54*4882a593Smuzhiyun # ifndef __alpha__
55*4882a593Smuzhiyun #  define SLOWIO
56*4882a593Smuzhiyun # endif
57*4882a593Smuzhiyun #endif
58*4882a593Smuzhiyun #include "msnd.h"
59*4882a593Smuzhiyun #ifdef MSND_CLASSIC
60*4882a593Smuzhiyun #  include "msnd_classic.h"
61*4882a593Smuzhiyun #  define LOGNAME			"msnd_classic"
62*4882a593Smuzhiyun #  define DEV_NAME			"msnd-classic"
63*4882a593Smuzhiyun #else
64*4882a593Smuzhiyun #  include "msnd_pinnacle.h"
65*4882a593Smuzhiyun #  define LOGNAME			"snd_msnd_pinnacle"
66*4882a593Smuzhiyun #  define DEV_NAME			"msnd-pinnacle"
67*4882a593Smuzhiyun #endif
68*4882a593Smuzhiyun 
set_default_audio_parameters(struct snd_msnd * chip)69*4882a593Smuzhiyun static void set_default_audio_parameters(struct snd_msnd *chip)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	chip->play_sample_size = snd_pcm_format_width(DEFSAMPLESIZE);
72*4882a593Smuzhiyun 	chip->play_sample_rate = DEFSAMPLERATE;
73*4882a593Smuzhiyun 	chip->play_channels = DEFCHANNELS;
74*4882a593Smuzhiyun 	chip->capture_sample_size = snd_pcm_format_width(DEFSAMPLESIZE);
75*4882a593Smuzhiyun 	chip->capture_sample_rate = DEFSAMPLERATE;
76*4882a593Smuzhiyun 	chip->capture_channels = DEFCHANNELS;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
snd_msnd_eval_dsp_msg(struct snd_msnd * chip,u16 wMessage)79*4882a593Smuzhiyun static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	switch (HIBYTE(wMessage)) {
82*4882a593Smuzhiyun 	case HIMT_PLAY_DONE: {
83*4882a593Smuzhiyun 		if (chip->banksPlayed < 3)
84*4882a593Smuzhiyun 			snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
85*4882a593Smuzhiyun 				(unsigned)jiffies, LOBYTE(wMessage));
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 		if (chip->last_playbank == LOBYTE(wMessage)) {
88*4882a593Smuzhiyun 			snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
89*4882a593Smuzhiyun 			break;
90*4882a593Smuzhiyun 		}
91*4882a593Smuzhiyun 		chip->banksPlayed++;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 		if (test_bit(F_WRITING, &chip->flags))
94*4882a593Smuzhiyun 			snd_msnd_DAPQ(chip, 0);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 		chip->last_playbank = LOBYTE(wMessage);
97*4882a593Smuzhiyun 		chip->playDMAPos += chip->play_period_bytes;
98*4882a593Smuzhiyun 		if (chip->playDMAPos > chip->playLimit)
99*4882a593Smuzhiyun 			chip->playDMAPos = 0;
100*4882a593Smuzhiyun 		snd_pcm_period_elapsed(chip->playback_substream);
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 		break;
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun 	case HIMT_RECORD_DONE:
105*4882a593Smuzhiyun 		if (chip->last_recbank == LOBYTE(wMessage))
106*4882a593Smuzhiyun 			break;
107*4882a593Smuzhiyun 		chip->last_recbank = LOBYTE(wMessage);
108*4882a593Smuzhiyun 		chip->captureDMAPos += chip->capturePeriodBytes;
109*4882a593Smuzhiyun 		if (chip->captureDMAPos > (chip->captureLimit))
110*4882a593Smuzhiyun 			chip->captureDMAPos = 0;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 		if (test_bit(F_READING, &chip->flags))
113*4882a593Smuzhiyun 			snd_msnd_DARQ(chip, chip->last_recbank);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 		snd_pcm_period_elapsed(chip->capture_substream);
116*4882a593Smuzhiyun 		break;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	case HIMT_DSP:
119*4882a593Smuzhiyun 		switch (LOBYTE(wMessage)) {
120*4882a593Smuzhiyun #ifndef MSND_CLASSIC
121*4882a593Smuzhiyun 		case HIDSP_PLAY_UNDER:
122*4882a593Smuzhiyun #endif
123*4882a593Smuzhiyun 		case HIDSP_INT_PLAY_UNDER:
124*4882a593Smuzhiyun 			snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
125*4882a593Smuzhiyun 				chip->banksPlayed);
126*4882a593Smuzhiyun 			if (chip->banksPlayed > 2)
127*4882a593Smuzhiyun 				clear_bit(F_WRITING, &chip->flags);
128*4882a593Smuzhiyun 			break;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 		case HIDSP_INT_RECORD_OVER:
131*4882a593Smuzhiyun 			snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
132*4882a593Smuzhiyun 			clear_bit(F_READING, &chip->flags);
133*4882a593Smuzhiyun 			break;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 		default:
136*4882a593Smuzhiyun 			snd_printd(KERN_WARNING LOGNAME
137*4882a593Smuzhiyun 				   ": DSP message %d 0x%02x\n",
138*4882a593Smuzhiyun 				   LOBYTE(wMessage), LOBYTE(wMessage));
139*4882a593Smuzhiyun 			break;
140*4882a593Smuzhiyun 		}
141*4882a593Smuzhiyun 		break;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	case HIMT_MIDI_IN_UCHAR:
144*4882a593Smuzhiyun 		if (chip->msndmidi_mpu)
145*4882a593Smuzhiyun 			snd_msndmidi_input_read(chip->msndmidi_mpu);
146*4882a593Smuzhiyun 		break;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	default:
149*4882a593Smuzhiyun 		snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
150*4882a593Smuzhiyun 			   HIBYTE(wMessage), HIBYTE(wMessage));
151*4882a593Smuzhiyun 		break;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
snd_msnd_interrupt(int irq,void * dev_id)155*4882a593Smuzhiyun static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct snd_msnd *chip = dev_id;
158*4882a593Smuzhiyun 	void __iomem *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
159*4882a593Smuzhiyun 	u16 head, tail, size;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	/* Send ack to DSP */
162*4882a593Smuzhiyun 	/* inb(chip->io + HP_RXL); */
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* Evaluate queued DSP messages */
165*4882a593Smuzhiyun 	head = readw(chip->DSPQ + JQS_wHead);
166*4882a593Smuzhiyun 	tail = readw(chip->DSPQ + JQS_wTail);
167*4882a593Smuzhiyun 	size = readw(chip->DSPQ + JQS_wSize);
168*4882a593Smuzhiyun 	if (head > size || tail > size)
169*4882a593Smuzhiyun 		goto out;
170*4882a593Smuzhiyun 	while (head != tail) {
171*4882a593Smuzhiyun 		snd_msnd_eval_dsp_msg(chip, readw(pwDSPQData + 2 * head));
172*4882a593Smuzhiyun 		if (++head > size)
173*4882a593Smuzhiyun 			head = 0;
174*4882a593Smuzhiyun 		writew(head, chip->DSPQ + JQS_wHead);
175*4882a593Smuzhiyun 	}
176*4882a593Smuzhiyun  out:
177*4882a593Smuzhiyun 	/* Send ack to DSP */
178*4882a593Smuzhiyun 	inb(chip->io + HP_RXL);
179*4882a593Smuzhiyun 	return IRQ_HANDLED;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 
snd_msnd_reset_dsp(long io,unsigned char * info)183*4882a593Smuzhiyun static int snd_msnd_reset_dsp(long io, unsigned char *info)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	int timeout = 100;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	outb(HPDSPRESET_ON, io + HP_DSPR);
188*4882a593Smuzhiyun 	msleep(1);
189*4882a593Smuzhiyun #ifndef MSND_CLASSIC
190*4882a593Smuzhiyun 	if (info)
191*4882a593Smuzhiyun 		*info = inb(io + HP_INFO);
192*4882a593Smuzhiyun #endif
193*4882a593Smuzhiyun 	outb(HPDSPRESET_OFF, io + HP_DSPR);
194*4882a593Smuzhiyun 	msleep(1);
195*4882a593Smuzhiyun 	while (timeout-- > 0) {
196*4882a593Smuzhiyun 		if (inb(io + HP_CVR) == HP_CVR_DEF)
197*4882a593Smuzhiyun 			return 0;
198*4882a593Smuzhiyun 		msleep(1);
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 	snd_printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	return -EIO;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
snd_msnd_probe(struct snd_card * card)205*4882a593Smuzhiyun static int snd_msnd_probe(struct snd_card *card)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	struct snd_msnd *chip = card->private_data;
208*4882a593Smuzhiyun 	unsigned char info;
209*4882a593Smuzhiyun #ifndef MSND_CLASSIC
210*4882a593Smuzhiyun 	char *xv, *rev = NULL;
211*4882a593Smuzhiyun 	char *pin = "TB Pinnacle", *fiji = "TB Fiji";
212*4882a593Smuzhiyun 	char *pinfiji = "TB Pinnacle/Fiji";
213*4882a593Smuzhiyun #endif
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (!request_region(chip->io, DSP_NUMIO, "probing")) {
216*4882a593Smuzhiyun 		snd_printk(KERN_ERR LOGNAME ": I/O port conflict\n");
217*4882a593Smuzhiyun 		return -ENODEV;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	if (snd_msnd_reset_dsp(chip->io, &info) < 0) {
221*4882a593Smuzhiyun 		release_region(chip->io, DSP_NUMIO);
222*4882a593Smuzhiyun 		return -ENODEV;
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun #ifdef MSND_CLASSIC
226*4882a593Smuzhiyun 	strcpy(card->shortname, "Classic/Tahiti/Monterey");
227*4882a593Smuzhiyun 	strcpy(card->longname, "Turtle Beach Multisound");
228*4882a593Smuzhiyun 	printk(KERN_INFO LOGNAME ": %s, "
229*4882a593Smuzhiyun 	       "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
230*4882a593Smuzhiyun 	       card->shortname,
231*4882a593Smuzhiyun 	       chip->io, chip->io + DSP_NUMIO - 1,
232*4882a593Smuzhiyun 	       chip->irq,
233*4882a593Smuzhiyun 	       chip->base, chip->base + 0x7fff);
234*4882a593Smuzhiyun #else
235*4882a593Smuzhiyun 	switch (info >> 4) {
236*4882a593Smuzhiyun 	case 0xf:
237*4882a593Smuzhiyun 		xv = "<= 1.15";
238*4882a593Smuzhiyun 		break;
239*4882a593Smuzhiyun 	case 0x1:
240*4882a593Smuzhiyun 		xv = "1.18/1.2";
241*4882a593Smuzhiyun 		break;
242*4882a593Smuzhiyun 	case 0x2:
243*4882a593Smuzhiyun 		xv = "1.3";
244*4882a593Smuzhiyun 		break;
245*4882a593Smuzhiyun 	case 0x3:
246*4882a593Smuzhiyun 		xv = "1.4";
247*4882a593Smuzhiyun 		break;
248*4882a593Smuzhiyun 	default:
249*4882a593Smuzhiyun 		xv = "unknown";
250*4882a593Smuzhiyun 		break;
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	switch (info & 0x7) {
254*4882a593Smuzhiyun 	case 0x0:
255*4882a593Smuzhiyun 		rev = "I";
256*4882a593Smuzhiyun 		strcpy(card->shortname, pin);
257*4882a593Smuzhiyun 		break;
258*4882a593Smuzhiyun 	case 0x1:
259*4882a593Smuzhiyun 		rev = "F";
260*4882a593Smuzhiyun 		strcpy(card->shortname, pin);
261*4882a593Smuzhiyun 		break;
262*4882a593Smuzhiyun 	case 0x2:
263*4882a593Smuzhiyun 		rev = "G";
264*4882a593Smuzhiyun 		strcpy(card->shortname, pin);
265*4882a593Smuzhiyun 		break;
266*4882a593Smuzhiyun 	case 0x3:
267*4882a593Smuzhiyun 		rev = "H";
268*4882a593Smuzhiyun 		strcpy(card->shortname, pin);
269*4882a593Smuzhiyun 		break;
270*4882a593Smuzhiyun 	case 0x4:
271*4882a593Smuzhiyun 		rev = "E";
272*4882a593Smuzhiyun 		strcpy(card->shortname, fiji);
273*4882a593Smuzhiyun 		break;
274*4882a593Smuzhiyun 	case 0x5:
275*4882a593Smuzhiyun 		rev = "C";
276*4882a593Smuzhiyun 		strcpy(card->shortname, fiji);
277*4882a593Smuzhiyun 		break;
278*4882a593Smuzhiyun 	case 0x6:
279*4882a593Smuzhiyun 		rev = "D";
280*4882a593Smuzhiyun 		strcpy(card->shortname, fiji);
281*4882a593Smuzhiyun 		break;
282*4882a593Smuzhiyun 	case 0x7:
283*4882a593Smuzhiyun 		rev = "A-B (Fiji) or A-E (Pinnacle)";
284*4882a593Smuzhiyun 		strcpy(card->shortname, pinfiji);
285*4882a593Smuzhiyun 		break;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 	strcpy(card->longname, "Turtle Beach Multisound Pinnacle");
288*4882a593Smuzhiyun 	printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
289*4882a593Smuzhiyun 	       "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
290*4882a593Smuzhiyun 	       card->shortname,
291*4882a593Smuzhiyun 	       rev, xv,
292*4882a593Smuzhiyun 	       chip->io, chip->io + DSP_NUMIO - 1,
293*4882a593Smuzhiyun 	       chip->irq,
294*4882a593Smuzhiyun 	       chip->base, chip->base + 0x7fff);
295*4882a593Smuzhiyun #endif
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	release_region(chip->io, DSP_NUMIO);
298*4882a593Smuzhiyun 	return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
snd_msnd_init_sma(struct snd_msnd * chip)301*4882a593Smuzhiyun static int snd_msnd_init_sma(struct snd_msnd *chip)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	static int initted;
304*4882a593Smuzhiyun 	u16 mastVolLeft, mastVolRight;
305*4882a593Smuzhiyun 	unsigned long flags;
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun #ifdef MSND_CLASSIC
308*4882a593Smuzhiyun 	outb(chip->memid, chip->io + HP_MEMM);
309*4882a593Smuzhiyun #endif
310*4882a593Smuzhiyun 	outb(HPBLKSEL_0, chip->io + HP_BLKS);
311*4882a593Smuzhiyun 	/* Motorola 56k shared memory base */
312*4882a593Smuzhiyun 	chip->SMA = chip->mappedbase + SMA_STRUCT_START;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (initted) {
315*4882a593Smuzhiyun 		mastVolLeft = readw(chip->SMA + SMA_wCurrMastVolLeft);
316*4882a593Smuzhiyun 		mastVolRight = readw(chip->SMA + SMA_wCurrMastVolRight);
317*4882a593Smuzhiyun 	} else
318*4882a593Smuzhiyun 		mastVolLeft = mastVolRight = 0;
319*4882a593Smuzhiyun 	memset_io(chip->mappedbase, 0, 0x8000);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	/* Critical section: bank 1 access */
322*4882a593Smuzhiyun 	spin_lock_irqsave(&chip->lock, flags);
323*4882a593Smuzhiyun 	outb(HPBLKSEL_1, chip->io + HP_BLKS);
324*4882a593Smuzhiyun 	memset_io(chip->mappedbase, 0, 0x8000);
325*4882a593Smuzhiyun 	outb(HPBLKSEL_0, chip->io + HP_BLKS);
326*4882a593Smuzhiyun 	spin_unlock_irqrestore(&chip->lock, flags);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	/* Digital audio play queue */
329*4882a593Smuzhiyun 	chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;
330*4882a593Smuzhiyun 	snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* Digital audio record queue */
333*4882a593Smuzhiyun 	chip->DARQ = chip->mappedbase + DARQ_OFFSET;
334*4882a593Smuzhiyun 	snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	/* MIDI out queue */
337*4882a593Smuzhiyun 	chip->MODQ = chip->mappedbase + MODQ_OFFSET;
338*4882a593Smuzhiyun 	snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	/* MIDI in queue */
341*4882a593Smuzhiyun 	chip->MIDQ = chip->mappedbase + MIDQ_OFFSET;
342*4882a593Smuzhiyun 	snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	/* DSP -> host message queue */
345*4882a593Smuzhiyun 	chip->DSPQ = chip->mappedbase + DSPQ_OFFSET;
346*4882a593Smuzhiyun 	snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	/* Setup some DSP values */
349*4882a593Smuzhiyun #ifndef MSND_CLASSIC
350*4882a593Smuzhiyun 	writew(1, chip->SMA + SMA_wCurrPlayFormat);
351*4882a593Smuzhiyun 	writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);
352*4882a593Smuzhiyun 	writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);
353*4882a593Smuzhiyun 	writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);
354*4882a593Smuzhiyun #endif
355*4882a593Smuzhiyun 	writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);
356*4882a593Smuzhiyun 	writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);
357*4882a593Smuzhiyun 	writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);
358*4882a593Smuzhiyun #ifndef MSND_CLASSIC
359*4882a593Smuzhiyun 	writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);
360*4882a593Smuzhiyun 	writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);
361*4882a593Smuzhiyun #endif
362*4882a593Smuzhiyun 	writew(0x303, chip->SMA + SMA_wCurrInputTagBits);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	initted = 1;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	return 0;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 
upload_dsp_code(struct snd_card * card)370*4882a593Smuzhiyun static int upload_dsp_code(struct snd_card *card)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	struct snd_msnd *chip = card->private_data;
373*4882a593Smuzhiyun 	const struct firmware *init_fw = NULL, *perm_fw = NULL;
374*4882a593Smuzhiyun 	int err;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	outb(HPBLKSEL_0, chip->io + HP_BLKS);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	err = request_firmware(&init_fw, INITCODEFILE, card->dev);
379*4882a593Smuzhiyun 	if (err < 0) {
380*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
381*4882a593Smuzhiyun 		goto cleanup1;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 	err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
384*4882a593Smuzhiyun 	if (err < 0) {
385*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
386*4882a593Smuzhiyun 		goto cleanup;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
390*4882a593Smuzhiyun 	if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
391*4882a593Smuzhiyun 		printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
392*4882a593Smuzhiyun 		err = -ENODEV;
393*4882a593Smuzhiyun 		goto cleanup;
394*4882a593Smuzhiyun 	}
395*4882a593Smuzhiyun 	printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
396*4882a593Smuzhiyun 	err = 0;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun cleanup:
399*4882a593Smuzhiyun 	release_firmware(perm_fw);
400*4882a593Smuzhiyun cleanup1:
401*4882a593Smuzhiyun 	release_firmware(init_fw);
402*4882a593Smuzhiyun 	return err;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun #ifdef MSND_CLASSIC
reset_proteus(struct snd_msnd * chip)406*4882a593Smuzhiyun static void reset_proteus(struct snd_msnd *chip)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	outb(HPPRORESET_ON, chip->io + HP_PROR);
409*4882a593Smuzhiyun 	msleep(TIME_PRO_RESET);
410*4882a593Smuzhiyun 	outb(HPPRORESET_OFF, chip->io + HP_PROR);
411*4882a593Smuzhiyun 	msleep(TIME_PRO_RESET_DONE);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun #endif
414*4882a593Smuzhiyun 
snd_msnd_initialize(struct snd_card * card)415*4882a593Smuzhiyun static int snd_msnd_initialize(struct snd_card *card)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	struct snd_msnd *chip = card->private_data;
418*4882a593Smuzhiyun 	int err, timeout;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun #ifdef MSND_CLASSIC
421*4882a593Smuzhiyun 	outb(HPWAITSTATE_0, chip->io + HP_WAIT);
422*4882a593Smuzhiyun 	outb(HPBITMODE_16, chip->io + HP_BITM);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	reset_proteus(chip);
425*4882a593Smuzhiyun #endif
426*4882a593Smuzhiyun 	err = snd_msnd_init_sma(chip);
427*4882a593Smuzhiyun 	if (err < 0) {
428*4882a593Smuzhiyun 		printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
429*4882a593Smuzhiyun 		return err;
430*4882a593Smuzhiyun 	}
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	err = snd_msnd_reset_dsp(chip->io, NULL);
433*4882a593Smuzhiyun 	if (err < 0)
434*4882a593Smuzhiyun 		return err;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	err = upload_dsp_code(card);
437*4882a593Smuzhiyun 	if (err < 0) {
438*4882a593Smuzhiyun 		printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
439*4882a593Smuzhiyun 		return err;
440*4882a593Smuzhiyun 	}
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	timeout = 200;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	while (readw(chip->mappedbase)) {
445*4882a593Smuzhiyun 		msleep(1);
446*4882a593Smuzhiyun 		if (!timeout--) {
447*4882a593Smuzhiyun 			snd_printd(KERN_ERR LOGNAME ": DSP reset timeout\n");
448*4882a593Smuzhiyun 			return -EIO;
449*4882a593Smuzhiyun 		}
450*4882a593Smuzhiyun 	}
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	snd_msndmix_setup(chip);
453*4882a593Smuzhiyun 	return 0;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun 
snd_msnd_dsp_full_reset(struct snd_card * card)456*4882a593Smuzhiyun static int snd_msnd_dsp_full_reset(struct snd_card *card)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun 	struct snd_msnd *chip = card->private_data;
459*4882a593Smuzhiyun 	int rv;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	if (test_bit(F_RESETTING, &chip->flags) || ++chip->nresets > 10)
462*4882a593Smuzhiyun 		return 0;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	set_bit(F_RESETTING, &chip->flags);
465*4882a593Smuzhiyun 	snd_msnd_dsp_halt(chip, NULL);	/* Unconditionally halt */
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	rv = snd_msnd_initialize(card);
468*4882a593Smuzhiyun 	if (rv)
469*4882a593Smuzhiyun 		printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
470*4882a593Smuzhiyun 	snd_msndmix_force_recsrc(chip, 0);
471*4882a593Smuzhiyun 	clear_bit(F_RESETTING, &chip->flags);
472*4882a593Smuzhiyun 	return rv;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
snd_msnd_dev_free(struct snd_device * device)475*4882a593Smuzhiyun static int snd_msnd_dev_free(struct snd_device *device)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	snd_printdd("snd_msnd_chip_free()\n");
478*4882a593Smuzhiyun 	return 0;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun 
snd_msnd_send_dsp_cmd_chk(struct snd_msnd * chip,u8 cmd)481*4882a593Smuzhiyun static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun 	if (snd_msnd_send_dsp_cmd(chip, cmd) == 0)
484*4882a593Smuzhiyun 		return 0;
485*4882a593Smuzhiyun 	snd_msnd_dsp_full_reset(chip->card);
486*4882a593Smuzhiyun 	return snd_msnd_send_dsp_cmd(chip, cmd);
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun 
snd_msnd_calibrate_adc(struct snd_msnd * chip,u16 srate)489*4882a593Smuzhiyun static int snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun 	snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate);
492*4882a593Smuzhiyun 	writew(srate, chip->SMA + SMA_wCalFreqAtoD);
493*4882a593Smuzhiyun 	if (chip->calibrate_signal == 0)
494*4882a593Smuzhiyun 		writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
495*4882a593Smuzhiyun 		       | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
496*4882a593Smuzhiyun 	else
497*4882a593Smuzhiyun 		writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
498*4882a593Smuzhiyun 		       & ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
499*4882a593Smuzhiyun 	if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
500*4882a593Smuzhiyun 	    snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {
501*4882a593Smuzhiyun 		schedule_timeout_interruptible(msecs_to_jiffies(333));
502*4882a593Smuzhiyun 		return 0;
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 	printk(KERN_WARNING LOGNAME ": ADC calibration failed\n");
505*4882a593Smuzhiyun 	return -EIO;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun /*
509*4882a593Smuzhiyun  * ALSA callback function, called when attempting to open the MIDI device.
510*4882a593Smuzhiyun  */
snd_msnd_mpu401_open(struct snd_mpu401 * mpu)511*4882a593Smuzhiyun static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun 	snd_msnd_enable_irq(mpu->private_data);
514*4882a593Smuzhiyun 	snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_START);
515*4882a593Smuzhiyun 	return 0;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
snd_msnd_mpu401_close(struct snd_mpu401 * mpu)518*4882a593Smuzhiyun static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_STOP);
521*4882a593Smuzhiyun 	snd_msnd_disable_irq(mpu->private_data);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
525*4882a593Smuzhiyun static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
526*4882a593Smuzhiyun 
snd_msnd_attach(struct snd_card * card)527*4882a593Smuzhiyun static int snd_msnd_attach(struct snd_card *card)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	struct snd_msnd *chip = card->private_data;
530*4882a593Smuzhiyun 	int err;
531*4882a593Smuzhiyun 	static const struct snd_device_ops ops = {
532*4882a593Smuzhiyun 		.dev_free =      snd_msnd_dev_free,
533*4882a593Smuzhiyun 		};
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	err = request_irq(chip->irq, snd_msnd_interrupt, 0, card->shortname,
536*4882a593Smuzhiyun 			  chip);
537*4882a593Smuzhiyun 	if (err < 0) {
538*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
539*4882a593Smuzhiyun 		return err;
540*4882a593Smuzhiyun 	}
541*4882a593Smuzhiyun 	card->sync_irq = chip->irq;
542*4882a593Smuzhiyun 	if (request_region(chip->io, DSP_NUMIO, card->shortname) == NULL) {
543*4882a593Smuzhiyun 		free_irq(chip->irq, chip);
544*4882a593Smuzhiyun 		return -EBUSY;
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
548*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME
549*4882a593Smuzhiyun 			": unable to grab memory region 0x%lx-0x%lx\n",
550*4882a593Smuzhiyun 			chip->base, chip->base + BUFFSIZE - 1);
551*4882a593Smuzhiyun 		release_region(chip->io, DSP_NUMIO);
552*4882a593Smuzhiyun 		free_irq(chip->irq, chip);
553*4882a593Smuzhiyun 		return -EBUSY;
554*4882a593Smuzhiyun 	}
555*4882a593Smuzhiyun 	chip->mappedbase = ioremap(chip->base, 0x8000);
556*4882a593Smuzhiyun 	if (!chip->mappedbase) {
557*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME
558*4882a593Smuzhiyun 			": unable to map memory region 0x%lx-0x%lx\n",
559*4882a593Smuzhiyun 			chip->base, chip->base + BUFFSIZE - 1);
560*4882a593Smuzhiyun 		err = -EIO;
561*4882a593Smuzhiyun 		goto err_release_region;
562*4882a593Smuzhiyun 	}
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 	err = snd_msnd_dsp_full_reset(card);
565*4882a593Smuzhiyun 	if (err < 0)
566*4882a593Smuzhiyun 		goto err_release_region;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	/* Register device */
569*4882a593Smuzhiyun 	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
570*4882a593Smuzhiyun 	if (err < 0)
571*4882a593Smuzhiyun 		goto err_release_region;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	err = snd_msnd_pcm(card, 0);
574*4882a593Smuzhiyun 	if (err < 0) {
575*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
576*4882a593Smuzhiyun 		goto err_release_region;
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	err = snd_msndmix_new(card);
580*4882a593Smuzhiyun 	if (err < 0) {
581*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": error creating new Mixer device\n");
582*4882a593Smuzhiyun 		goto err_release_region;
583*4882a593Smuzhiyun 	}
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	if (mpu_io[0] != SNDRV_AUTO_PORT) {
587*4882a593Smuzhiyun 		struct snd_mpu401 *mpu;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 		err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
590*4882a593Smuzhiyun 					  mpu_io[0],
591*4882a593Smuzhiyun 					  MPU401_MODE_INPUT |
592*4882a593Smuzhiyun 					  MPU401_MODE_OUTPUT,
593*4882a593Smuzhiyun 					  mpu_irq[0],
594*4882a593Smuzhiyun 					  &chip->rmidi);
595*4882a593Smuzhiyun 		if (err < 0) {
596*4882a593Smuzhiyun 			printk(KERN_ERR LOGNAME
597*4882a593Smuzhiyun 				": error creating new Midi device\n");
598*4882a593Smuzhiyun 			goto err_release_region;
599*4882a593Smuzhiyun 		}
600*4882a593Smuzhiyun 		mpu = chip->rmidi->private_data;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 		mpu->open_input = snd_msnd_mpu401_open;
603*4882a593Smuzhiyun 		mpu->close_input = snd_msnd_mpu401_close;
604*4882a593Smuzhiyun 		mpu->private_data = chip;
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	disable_irq(chip->irq);
608*4882a593Smuzhiyun 	snd_msnd_calibrate_adc(chip, chip->play_sample_rate);
609*4882a593Smuzhiyun 	snd_msndmix_force_recsrc(chip, 0);
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	err = snd_card_register(card);
612*4882a593Smuzhiyun 	if (err < 0)
613*4882a593Smuzhiyun 		goto err_release_region;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	return 0;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun err_release_region:
618*4882a593Smuzhiyun 	iounmap(chip->mappedbase);
619*4882a593Smuzhiyun 	release_mem_region(chip->base, BUFFSIZE);
620*4882a593Smuzhiyun 	release_region(chip->io, DSP_NUMIO);
621*4882a593Smuzhiyun 	free_irq(chip->irq, chip);
622*4882a593Smuzhiyun 	return err;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 
snd_msnd_unload(struct snd_card * card)626*4882a593Smuzhiyun static void snd_msnd_unload(struct snd_card *card)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	struct snd_msnd *chip = card->private_data;
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	iounmap(chip->mappedbase);
631*4882a593Smuzhiyun 	release_mem_region(chip->base, BUFFSIZE);
632*4882a593Smuzhiyun 	release_region(chip->io, DSP_NUMIO);
633*4882a593Smuzhiyun 	free_irq(chip->irq, chip);
634*4882a593Smuzhiyun 	snd_card_free(card);
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun #ifndef MSND_CLASSIC
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun /* Pinnacle/Fiji Logical Device Configuration */
640*4882a593Smuzhiyun 
snd_msnd_write_cfg(int cfg,int reg,int value)641*4882a593Smuzhiyun static int snd_msnd_write_cfg(int cfg, int reg, int value)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	outb(reg, cfg);
644*4882a593Smuzhiyun 	outb(value, cfg + 1);
645*4882a593Smuzhiyun 	if (value != inb(cfg + 1)) {
646*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": snd_msnd_write_cfg: I/O error\n");
647*4882a593Smuzhiyun 		return -EIO;
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 	return 0;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
snd_msnd_write_cfg_io0(int cfg,int num,u16 io)652*4882a593Smuzhiyun static int snd_msnd_write_cfg_io0(int cfg, int num, u16 io)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
655*4882a593Smuzhiyun 		return -EIO;
656*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
657*4882a593Smuzhiyun 		return -EIO;
658*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
659*4882a593Smuzhiyun 		return -EIO;
660*4882a593Smuzhiyun 	return 0;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
snd_msnd_write_cfg_io1(int cfg,int num,u16 io)663*4882a593Smuzhiyun static int snd_msnd_write_cfg_io1(int cfg, int num, u16 io)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
666*4882a593Smuzhiyun 		return -EIO;
667*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
668*4882a593Smuzhiyun 		return -EIO;
669*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
670*4882a593Smuzhiyun 		return -EIO;
671*4882a593Smuzhiyun 	return 0;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun 
snd_msnd_write_cfg_irq(int cfg,int num,u16 irq)674*4882a593Smuzhiyun static int snd_msnd_write_cfg_irq(int cfg, int num, u16 irq)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
677*4882a593Smuzhiyun 		return -EIO;
678*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
679*4882a593Smuzhiyun 		return -EIO;
680*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
681*4882a593Smuzhiyun 		return -EIO;
682*4882a593Smuzhiyun 	return 0;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
snd_msnd_write_cfg_mem(int cfg,int num,int mem)685*4882a593Smuzhiyun static int snd_msnd_write_cfg_mem(int cfg, int num, int mem)
686*4882a593Smuzhiyun {
687*4882a593Smuzhiyun 	u16 wmem;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	mem >>= 8;
690*4882a593Smuzhiyun 	wmem = (u16)(mem & 0xfff);
691*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
692*4882a593Smuzhiyun 		return -EIO;
693*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
694*4882a593Smuzhiyun 		return -EIO;
695*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
696*4882a593Smuzhiyun 		return -EIO;
697*4882a593Smuzhiyun 	if (wmem && snd_msnd_write_cfg(cfg, IREG_MEMCONTROL,
698*4882a593Smuzhiyun 				       MEMTYPE_HIADDR | MEMTYPE_16BIT))
699*4882a593Smuzhiyun 		return -EIO;
700*4882a593Smuzhiyun 	return 0;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun 
snd_msnd_activate_logical(int cfg,int num)703*4882a593Smuzhiyun static int snd_msnd_activate_logical(int cfg, int num)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
706*4882a593Smuzhiyun 		return -EIO;
707*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
708*4882a593Smuzhiyun 		return -EIO;
709*4882a593Smuzhiyun 	return 0;
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun 
snd_msnd_write_cfg_logical(int cfg,int num,u16 io0,u16 io1,u16 irq,int mem)712*4882a593Smuzhiyun static int snd_msnd_write_cfg_logical(int cfg, int num, u16 io0,
713*4882a593Smuzhiyun 				      u16 io1, u16 irq, int mem)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun 	if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
716*4882a593Smuzhiyun 		return -EIO;
717*4882a593Smuzhiyun 	if (snd_msnd_write_cfg_io0(cfg, num, io0))
718*4882a593Smuzhiyun 		return -EIO;
719*4882a593Smuzhiyun 	if (snd_msnd_write_cfg_io1(cfg, num, io1))
720*4882a593Smuzhiyun 		return -EIO;
721*4882a593Smuzhiyun 	if (snd_msnd_write_cfg_irq(cfg, num, irq))
722*4882a593Smuzhiyun 		return -EIO;
723*4882a593Smuzhiyun 	if (snd_msnd_write_cfg_mem(cfg, num, mem))
724*4882a593Smuzhiyun 		return -EIO;
725*4882a593Smuzhiyun 	if (snd_msnd_activate_logical(cfg, num))
726*4882a593Smuzhiyun 		return -EIO;
727*4882a593Smuzhiyun 	return 0;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun 
snd_msnd_pinnacle_cfg_reset(int cfg)730*4882a593Smuzhiyun static int snd_msnd_pinnacle_cfg_reset(int cfg)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun 	int i;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	/* Reset devices if told to */
735*4882a593Smuzhiyun 	printk(KERN_INFO LOGNAME ": Resetting all devices\n");
736*4882a593Smuzhiyun 	for (i = 0; i < 4; ++i)
737*4882a593Smuzhiyun 		if (snd_msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0))
738*4882a593Smuzhiyun 			return -EIO;
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	return 0;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun #endif
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
745*4882a593Smuzhiyun static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun module_param_array(index, int, NULL, 0444);
748*4882a593Smuzhiyun MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard.");
749*4882a593Smuzhiyun module_param_array(id, charp, NULL, 0444);
750*4882a593Smuzhiyun MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard.");
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
753*4882a593Smuzhiyun static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
754*4882a593Smuzhiyun static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun #ifndef MSND_CLASSIC
757*4882a593Smuzhiyun static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun /* Extra Peripheral Configuration (Default: Disable) */
760*4882a593Smuzhiyun static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
761*4882a593Smuzhiyun static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
762*4882a593Smuzhiyun static int ide_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun static long joystick_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
765*4882a593Smuzhiyun /* If we have the digital daugherboard... */
766*4882a593Smuzhiyun static int digital[SNDRV_CARDS];
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun /* Extra Peripheral Configuration */
769*4882a593Smuzhiyun static int reset[SNDRV_CARDS];
770*4882a593Smuzhiyun #endif
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun static int write_ndelay[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun static int calibrate_signal;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun #ifdef CONFIG_PNP
777*4882a593Smuzhiyun static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
778*4882a593Smuzhiyun module_param_array(isapnp, bool, NULL, 0444);
779*4882a593Smuzhiyun MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
780*4882a593Smuzhiyun #define has_isapnp(x) isapnp[x]
781*4882a593Smuzhiyun #else
782*4882a593Smuzhiyun #define has_isapnp(x) 0
783*4882a593Smuzhiyun #endif
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
786*4882a593Smuzhiyun MODULE_DESCRIPTION("Turtle Beach " LONGNAME " Linux Driver");
787*4882a593Smuzhiyun MODULE_LICENSE("GPL");
788*4882a593Smuzhiyun MODULE_FIRMWARE(INITCODEFILE);
789*4882a593Smuzhiyun MODULE_FIRMWARE(PERMCODEFILE);
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun module_param_hw_array(io, long, ioport, NULL, 0444);
792*4882a593Smuzhiyun MODULE_PARM_DESC(io, "IO port #");
793*4882a593Smuzhiyun module_param_hw_array(irq, int, irq, NULL, 0444);
794*4882a593Smuzhiyun module_param_hw_array(mem, long, iomem, NULL, 0444);
795*4882a593Smuzhiyun module_param_array(write_ndelay, int, NULL, 0444);
796*4882a593Smuzhiyun module_param(calibrate_signal, int, 0444);
797*4882a593Smuzhiyun #ifndef MSND_CLASSIC
798*4882a593Smuzhiyun module_param_array(digital, int, NULL, 0444);
799*4882a593Smuzhiyun module_param_hw_array(cfg, long, ioport, NULL, 0444);
800*4882a593Smuzhiyun module_param_array(reset, int, NULL, 0444);
801*4882a593Smuzhiyun module_param_hw_array(mpu_io, long, ioport, NULL, 0444);
802*4882a593Smuzhiyun module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
803*4882a593Smuzhiyun module_param_hw_array(ide_io0, long, ioport, NULL, 0444);
804*4882a593Smuzhiyun module_param_hw_array(ide_io1, long, ioport, NULL, 0444);
805*4882a593Smuzhiyun module_param_hw_array(ide_irq, int, irq, NULL, 0444);
806*4882a593Smuzhiyun module_param_hw_array(joystick_io, long, ioport, NULL, 0444);
807*4882a593Smuzhiyun #endif
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 
snd_msnd_isa_match(struct device * pdev,unsigned int i)810*4882a593Smuzhiyun static int snd_msnd_isa_match(struct device *pdev, unsigned int i)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun 	if (io[i] == SNDRV_AUTO_PORT)
813*4882a593Smuzhiyun 		return 0;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {
816*4882a593Smuzhiyun 		printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
817*4882a593Smuzhiyun 		return 0;
818*4882a593Smuzhiyun 	}
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun #ifdef MSND_CLASSIC
821*4882a593Smuzhiyun 	if (!(io[i] == 0x290 ||
822*4882a593Smuzhiyun 	      io[i] == 0x260 ||
823*4882a593Smuzhiyun 	      io[i] == 0x250 ||
824*4882a593Smuzhiyun 	      io[i] == 0x240 ||
825*4882a593Smuzhiyun 	      io[i] == 0x230 ||
826*4882a593Smuzhiyun 	      io[i] == 0x220 ||
827*4882a593Smuzhiyun 	      io[i] == 0x210 ||
828*4882a593Smuzhiyun 	      io[i] == 0x3e0)) {
829*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set "
830*4882a593Smuzhiyun 			" to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, "
831*4882a593Smuzhiyun 			"or 0x3E0\n");
832*4882a593Smuzhiyun 		return 0;
833*4882a593Smuzhiyun 	}
834*4882a593Smuzhiyun #else
835*4882a593Smuzhiyun 	if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {
836*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME
837*4882a593Smuzhiyun 			": \"io\" - DSP I/O base must within the range 0x100 "
838*4882a593Smuzhiyun 			"to 0x3E0 and must be evenly divisible by 0x10\n");
839*4882a593Smuzhiyun 		return 0;
840*4882a593Smuzhiyun 	}
841*4882a593Smuzhiyun #endif /* MSND_CLASSIC */
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	if (!(irq[i] == 5 ||
844*4882a593Smuzhiyun 	      irq[i] == 7 ||
845*4882a593Smuzhiyun 	      irq[i] == 9 ||
846*4882a593Smuzhiyun 	      irq[i] == 10 ||
847*4882a593Smuzhiyun 	      irq[i] == 11 ||
848*4882a593Smuzhiyun 	      irq[i] == 12)) {
849*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME
850*4882a593Smuzhiyun 			": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
851*4882a593Smuzhiyun 		return 0;
852*4882a593Smuzhiyun 	}
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	if (!(mem[i] == 0xb0000 ||
855*4882a593Smuzhiyun 	      mem[i] == 0xc8000 ||
856*4882a593Smuzhiyun 	      mem[i] == 0xd0000 ||
857*4882a593Smuzhiyun 	      mem[i] == 0xd8000 ||
858*4882a593Smuzhiyun 	      mem[i] == 0xe0000 ||
859*4882a593Smuzhiyun 	      mem[i] == 0xe8000)) {
860*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
861*4882a593Smuzhiyun 		       "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or "
862*4882a593Smuzhiyun 		       "0xe8000\n");
863*4882a593Smuzhiyun 		return 0;
864*4882a593Smuzhiyun 	}
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun #ifndef MSND_CLASSIC
867*4882a593Smuzhiyun 	if (cfg[i] == SNDRV_AUTO_PORT) {
868*4882a593Smuzhiyun 		printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
869*4882a593Smuzhiyun 	} else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {
870*4882a593Smuzhiyun 		printk(KERN_INFO LOGNAME
871*4882a593Smuzhiyun 			": Config port must be 0x250, 0x260 or 0x270 "
872*4882a593Smuzhiyun 			"(or unspecified for PnP mode)\n");
873*4882a593Smuzhiyun 		return 0;
874*4882a593Smuzhiyun 	}
875*4882a593Smuzhiyun #endif /* MSND_CLASSIC */
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	return 1;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun 
snd_msnd_isa_probe(struct device * pdev,unsigned int idx)880*4882a593Smuzhiyun static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
881*4882a593Smuzhiyun {
882*4882a593Smuzhiyun 	int err;
883*4882a593Smuzhiyun 	struct snd_card *card;
884*4882a593Smuzhiyun 	struct snd_msnd *chip;
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun 	if (has_isapnp(idx)
887*4882a593Smuzhiyun #ifndef MSND_CLASSIC
888*4882a593Smuzhiyun 	    || cfg[idx] == SNDRV_AUTO_PORT
889*4882a593Smuzhiyun #endif
890*4882a593Smuzhiyun 	    ) {
891*4882a593Smuzhiyun 		printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
892*4882a593Smuzhiyun 		return -ENODEV;
893*4882a593Smuzhiyun 	}
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	err = snd_card_new(pdev, index[idx], id[idx], THIS_MODULE,
896*4882a593Smuzhiyun 			   sizeof(struct snd_msnd), &card);
897*4882a593Smuzhiyun 	if (err < 0)
898*4882a593Smuzhiyun 		return err;
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	chip = card->private_data;
901*4882a593Smuzhiyun 	chip->card = card;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun #ifdef MSND_CLASSIC
904*4882a593Smuzhiyun 	switch (irq[idx]) {
905*4882a593Smuzhiyun 	case 5:
906*4882a593Smuzhiyun 		chip->irqid = HPIRQ_5; break;
907*4882a593Smuzhiyun 	case 7:
908*4882a593Smuzhiyun 		chip->irqid = HPIRQ_7; break;
909*4882a593Smuzhiyun 	case 9:
910*4882a593Smuzhiyun 		chip->irqid = HPIRQ_9; break;
911*4882a593Smuzhiyun 	case 10:
912*4882a593Smuzhiyun 		chip->irqid = HPIRQ_10; break;
913*4882a593Smuzhiyun 	case 11:
914*4882a593Smuzhiyun 		chip->irqid = HPIRQ_11; break;
915*4882a593Smuzhiyun 	case 12:
916*4882a593Smuzhiyun 		chip->irqid = HPIRQ_12; break;
917*4882a593Smuzhiyun 	}
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	switch (mem[idx]) {
920*4882a593Smuzhiyun 	case 0xb0000:
921*4882a593Smuzhiyun 		chip->memid = HPMEM_B000; break;
922*4882a593Smuzhiyun 	case 0xc8000:
923*4882a593Smuzhiyun 		chip->memid = HPMEM_C800; break;
924*4882a593Smuzhiyun 	case 0xd0000:
925*4882a593Smuzhiyun 		chip->memid = HPMEM_D000; break;
926*4882a593Smuzhiyun 	case 0xd8000:
927*4882a593Smuzhiyun 		chip->memid = HPMEM_D800; break;
928*4882a593Smuzhiyun 	case 0xe0000:
929*4882a593Smuzhiyun 		chip->memid = HPMEM_E000; break;
930*4882a593Smuzhiyun 	case 0xe8000:
931*4882a593Smuzhiyun 		chip->memid = HPMEM_E800; break;
932*4882a593Smuzhiyun 	}
933*4882a593Smuzhiyun #else
934*4882a593Smuzhiyun 	printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",
935*4882a593Smuzhiyun 			cfg[idx]);
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	if (!request_region(cfg[idx], 2, "Pinnacle/Fiji Config")) {
938*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": Config port 0x%lx conflict\n",
939*4882a593Smuzhiyun 			   cfg[idx]);
940*4882a593Smuzhiyun 		snd_card_free(card);
941*4882a593Smuzhiyun 		return -EIO;
942*4882a593Smuzhiyun 	}
943*4882a593Smuzhiyun 	if (reset[idx])
944*4882a593Smuzhiyun 		if (snd_msnd_pinnacle_cfg_reset(cfg[idx])) {
945*4882a593Smuzhiyun 			err = -EIO;
946*4882a593Smuzhiyun 			goto cfg_error;
947*4882a593Smuzhiyun 		}
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	/* DSP */
950*4882a593Smuzhiyun 	err = snd_msnd_write_cfg_logical(cfg[idx], 0,
951*4882a593Smuzhiyun 					 io[idx], 0,
952*4882a593Smuzhiyun 					 irq[idx], mem[idx]);
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	if (err)
955*4882a593Smuzhiyun 		goto cfg_error;
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	/* The following are Pinnacle specific */
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	/* MPU */
960*4882a593Smuzhiyun 	if (mpu_io[idx] != SNDRV_AUTO_PORT
961*4882a593Smuzhiyun 	    && mpu_irq[idx] != SNDRV_AUTO_IRQ) {
962*4882a593Smuzhiyun 		printk(KERN_INFO LOGNAME
963*4882a593Smuzhiyun 		       ": Configuring MPU to I/O 0x%lx IRQ %d\n",
964*4882a593Smuzhiyun 		       mpu_io[idx], mpu_irq[idx]);
965*4882a593Smuzhiyun 		err = snd_msnd_write_cfg_logical(cfg[idx], 1,
966*4882a593Smuzhiyun 						 mpu_io[idx], 0,
967*4882a593Smuzhiyun 						 mpu_irq[idx], 0);
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 		if (err)
970*4882a593Smuzhiyun 			goto cfg_error;
971*4882a593Smuzhiyun 	}
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 	/* IDE */
974*4882a593Smuzhiyun 	if (ide_io0[idx] != SNDRV_AUTO_PORT
975*4882a593Smuzhiyun 	    && ide_io1[idx] != SNDRV_AUTO_PORT
976*4882a593Smuzhiyun 	    && ide_irq[idx] != SNDRV_AUTO_IRQ) {
977*4882a593Smuzhiyun 		printk(KERN_INFO LOGNAME
978*4882a593Smuzhiyun 		       ": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",
979*4882a593Smuzhiyun 		       ide_io0[idx], ide_io1[idx], ide_irq[idx]);
980*4882a593Smuzhiyun 		err = snd_msnd_write_cfg_logical(cfg[idx], 2,
981*4882a593Smuzhiyun 						 ide_io0[idx], ide_io1[idx],
982*4882a593Smuzhiyun 						 ide_irq[idx], 0);
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 		if (err)
985*4882a593Smuzhiyun 			goto cfg_error;
986*4882a593Smuzhiyun 	}
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	/* Joystick */
989*4882a593Smuzhiyun 	if (joystick_io[idx] != SNDRV_AUTO_PORT) {
990*4882a593Smuzhiyun 		printk(KERN_INFO LOGNAME
991*4882a593Smuzhiyun 		       ": Configuring joystick to I/O 0x%lx\n",
992*4882a593Smuzhiyun 		       joystick_io[idx]);
993*4882a593Smuzhiyun 		err = snd_msnd_write_cfg_logical(cfg[idx], 3,
994*4882a593Smuzhiyun 						 joystick_io[idx], 0,
995*4882a593Smuzhiyun 						 0, 0);
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 		if (err)
998*4882a593Smuzhiyun 			goto cfg_error;
999*4882a593Smuzhiyun 	}
1000*4882a593Smuzhiyun 	release_region(cfg[idx], 2);
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun #endif /* MSND_CLASSIC */
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun 	set_default_audio_parameters(chip);
1005*4882a593Smuzhiyun #ifdef MSND_CLASSIC
1006*4882a593Smuzhiyun 	chip->type = msndClassic;
1007*4882a593Smuzhiyun #else
1008*4882a593Smuzhiyun 	chip->type = msndPinnacle;
1009*4882a593Smuzhiyun #endif
1010*4882a593Smuzhiyun 	chip->io = io[idx];
1011*4882a593Smuzhiyun 	chip->irq = irq[idx];
1012*4882a593Smuzhiyun 	chip->base = mem[idx];
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	chip->calibrate_signal = calibrate_signal ? 1 : 0;
1015*4882a593Smuzhiyun 	chip->recsrc = 0;
1016*4882a593Smuzhiyun 	chip->dspq_data_buff = DSPQ_DATA_BUFF;
1017*4882a593Smuzhiyun 	chip->dspq_buff_size = DSPQ_BUFF_SIZE;
1018*4882a593Smuzhiyun 	if (write_ndelay[idx])
1019*4882a593Smuzhiyun 		clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1020*4882a593Smuzhiyun 	else
1021*4882a593Smuzhiyun 		set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1022*4882a593Smuzhiyun #ifndef MSND_CLASSIC
1023*4882a593Smuzhiyun 	if (digital[idx])
1024*4882a593Smuzhiyun 		set_bit(F_HAVEDIGITAL, &chip->flags);
1025*4882a593Smuzhiyun #endif
1026*4882a593Smuzhiyun 	spin_lock_init(&chip->lock);
1027*4882a593Smuzhiyun 	err = snd_msnd_probe(card);
1028*4882a593Smuzhiyun 	if (err < 0) {
1029*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": Probe failed\n");
1030*4882a593Smuzhiyun 		snd_card_free(card);
1031*4882a593Smuzhiyun 		return err;
1032*4882a593Smuzhiyun 	}
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 	err = snd_msnd_attach(card);
1035*4882a593Smuzhiyun 	if (err < 0) {
1036*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": Attach failed\n");
1037*4882a593Smuzhiyun 		snd_card_free(card);
1038*4882a593Smuzhiyun 		return err;
1039*4882a593Smuzhiyun 	}
1040*4882a593Smuzhiyun 	dev_set_drvdata(pdev, card);
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun 	return 0;
1043*4882a593Smuzhiyun 
1044*4882a593Smuzhiyun #ifndef MSND_CLASSIC
1045*4882a593Smuzhiyun cfg_error:
1046*4882a593Smuzhiyun 	release_region(cfg[idx], 2);
1047*4882a593Smuzhiyun 	snd_card_free(card);
1048*4882a593Smuzhiyun 	return err;
1049*4882a593Smuzhiyun #endif
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun 
snd_msnd_isa_remove(struct device * pdev,unsigned int dev)1052*4882a593Smuzhiyun static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
1053*4882a593Smuzhiyun {
1054*4882a593Smuzhiyun 	snd_msnd_unload(dev_get_drvdata(pdev));
1055*4882a593Smuzhiyun 	return 0;
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun static struct isa_driver snd_msnd_driver = {
1059*4882a593Smuzhiyun 	.match		= snd_msnd_isa_match,
1060*4882a593Smuzhiyun 	.probe		= snd_msnd_isa_probe,
1061*4882a593Smuzhiyun 	.remove		= snd_msnd_isa_remove,
1062*4882a593Smuzhiyun 	/* FIXME: suspend, resume */
1063*4882a593Smuzhiyun 	.driver		= {
1064*4882a593Smuzhiyun 		.name	= DEV_NAME
1065*4882a593Smuzhiyun 	},
1066*4882a593Smuzhiyun };
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun #ifdef CONFIG_PNP
snd_msnd_pnp_detect(struct pnp_card_link * pcard,const struct pnp_card_device_id * pid)1069*4882a593Smuzhiyun static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,
1070*4882a593Smuzhiyun 			       const struct pnp_card_device_id *pid)
1071*4882a593Smuzhiyun {
1072*4882a593Smuzhiyun 	static int idx;
1073*4882a593Smuzhiyun 	struct pnp_dev *pnp_dev;
1074*4882a593Smuzhiyun 	struct pnp_dev *mpu_dev;
1075*4882a593Smuzhiyun 	struct snd_card *card;
1076*4882a593Smuzhiyun 	struct snd_msnd *chip;
1077*4882a593Smuzhiyun 	int ret;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	for ( ; idx < SNDRV_CARDS; idx++) {
1080*4882a593Smuzhiyun 		if (has_isapnp(idx))
1081*4882a593Smuzhiyun 			break;
1082*4882a593Smuzhiyun 	}
1083*4882a593Smuzhiyun 	if (idx >= SNDRV_CARDS)
1084*4882a593Smuzhiyun 		return -ENODEV;
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	/*
1087*4882a593Smuzhiyun 	 * Check that we still have room for another sound card ...
1088*4882a593Smuzhiyun 	 */
1089*4882a593Smuzhiyun 	pnp_dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
1090*4882a593Smuzhiyun 	if (!pnp_dev)
1091*4882a593Smuzhiyun 		return -ENODEV;
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	mpu_dev = pnp_request_card_device(pcard, pid->devs[1].id, NULL);
1094*4882a593Smuzhiyun 	if (!mpu_dev)
1095*4882a593Smuzhiyun 		return -ENODEV;
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {
1098*4882a593Smuzhiyun 		printk(KERN_INFO "msnd_pinnacle: device is inactive\n");
1099*4882a593Smuzhiyun 		return -EBUSY;
1100*4882a593Smuzhiyun 	}
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {
1103*4882a593Smuzhiyun 		printk(KERN_INFO "msnd_pinnacle: MPU device is inactive\n");
1104*4882a593Smuzhiyun 		return -EBUSY;
1105*4882a593Smuzhiyun 	}
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	/*
1108*4882a593Smuzhiyun 	 * Create a new ALSA sound card entry, in anticipation
1109*4882a593Smuzhiyun 	 * of detecting our hardware ...
1110*4882a593Smuzhiyun 	 */
1111*4882a593Smuzhiyun 	ret = snd_card_new(&pcard->card->dev,
1112*4882a593Smuzhiyun 			   index[idx], id[idx], THIS_MODULE,
1113*4882a593Smuzhiyun 			   sizeof(struct snd_msnd), &card);
1114*4882a593Smuzhiyun 	if (ret < 0)
1115*4882a593Smuzhiyun 		return ret;
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	chip = card->private_data;
1118*4882a593Smuzhiyun 	chip->card = card;
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	/*
1121*4882a593Smuzhiyun 	 * Read the correct parameters off the ISA PnP bus ...
1122*4882a593Smuzhiyun 	 */
1123*4882a593Smuzhiyun 	io[idx] = pnp_port_start(pnp_dev, 0);
1124*4882a593Smuzhiyun 	irq[idx] = pnp_irq(pnp_dev, 0);
1125*4882a593Smuzhiyun 	mem[idx] = pnp_mem_start(pnp_dev, 0);
1126*4882a593Smuzhiyun 	mpu_io[idx] = pnp_port_start(mpu_dev, 0);
1127*4882a593Smuzhiyun 	mpu_irq[idx] = pnp_irq(mpu_dev, 0);
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 	set_default_audio_parameters(chip);
1130*4882a593Smuzhiyun #ifdef MSND_CLASSIC
1131*4882a593Smuzhiyun 	chip->type = msndClassic;
1132*4882a593Smuzhiyun #else
1133*4882a593Smuzhiyun 	chip->type = msndPinnacle;
1134*4882a593Smuzhiyun #endif
1135*4882a593Smuzhiyun 	chip->io = io[idx];
1136*4882a593Smuzhiyun 	chip->irq = irq[idx];
1137*4882a593Smuzhiyun 	chip->base = mem[idx];
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	chip->calibrate_signal = calibrate_signal ? 1 : 0;
1140*4882a593Smuzhiyun 	chip->recsrc = 0;
1141*4882a593Smuzhiyun 	chip->dspq_data_buff = DSPQ_DATA_BUFF;
1142*4882a593Smuzhiyun 	chip->dspq_buff_size = DSPQ_BUFF_SIZE;
1143*4882a593Smuzhiyun 	if (write_ndelay[idx])
1144*4882a593Smuzhiyun 		clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1145*4882a593Smuzhiyun 	else
1146*4882a593Smuzhiyun 		set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1147*4882a593Smuzhiyun #ifndef MSND_CLASSIC
1148*4882a593Smuzhiyun 	if (digital[idx])
1149*4882a593Smuzhiyun 		set_bit(F_HAVEDIGITAL, &chip->flags);
1150*4882a593Smuzhiyun #endif
1151*4882a593Smuzhiyun 	spin_lock_init(&chip->lock);
1152*4882a593Smuzhiyun 	ret = snd_msnd_probe(card);
1153*4882a593Smuzhiyun 	if (ret < 0) {
1154*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": Probe failed\n");
1155*4882a593Smuzhiyun 		goto _release_card;
1156*4882a593Smuzhiyun 	}
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	ret = snd_msnd_attach(card);
1159*4882a593Smuzhiyun 	if (ret < 0) {
1160*4882a593Smuzhiyun 		printk(KERN_ERR LOGNAME ": Attach failed\n");
1161*4882a593Smuzhiyun 		goto _release_card;
1162*4882a593Smuzhiyun 	}
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun 	pnp_set_card_drvdata(pcard, card);
1165*4882a593Smuzhiyun 	++idx;
1166*4882a593Smuzhiyun 	return 0;
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun _release_card:
1169*4882a593Smuzhiyun 	snd_card_free(card);
1170*4882a593Smuzhiyun 	return ret;
1171*4882a593Smuzhiyun }
1172*4882a593Smuzhiyun 
snd_msnd_pnp_remove(struct pnp_card_link * pcard)1173*4882a593Smuzhiyun static void snd_msnd_pnp_remove(struct pnp_card_link *pcard)
1174*4882a593Smuzhiyun {
1175*4882a593Smuzhiyun 	snd_msnd_unload(pnp_get_card_drvdata(pcard));
1176*4882a593Smuzhiyun 	pnp_set_card_drvdata(pcard, NULL);
1177*4882a593Smuzhiyun }
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun static int isa_registered;
1180*4882a593Smuzhiyun static int pnp_registered;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun static const struct pnp_card_device_id msnd_pnpids[] = {
1183*4882a593Smuzhiyun 	/* Pinnacle PnP */
1184*4882a593Smuzhiyun 	{ .id = "BVJ0440", .devs = { { "TBS0000" }, { "TBS0001" } } },
1185*4882a593Smuzhiyun 	{ .id = "" }	/* end */
1186*4882a593Smuzhiyun };
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pnp_card, msnd_pnpids);
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun static struct pnp_card_driver msnd_pnpc_driver = {
1191*4882a593Smuzhiyun 	.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
1192*4882a593Smuzhiyun 	.name = "msnd_pinnacle",
1193*4882a593Smuzhiyun 	.id_table = msnd_pnpids,
1194*4882a593Smuzhiyun 	.probe = snd_msnd_pnp_detect,
1195*4882a593Smuzhiyun 	.remove = snd_msnd_pnp_remove,
1196*4882a593Smuzhiyun };
1197*4882a593Smuzhiyun #endif /* CONFIG_PNP */
1198*4882a593Smuzhiyun 
snd_msnd_init(void)1199*4882a593Smuzhiyun static int __init snd_msnd_init(void)
1200*4882a593Smuzhiyun {
1201*4882a593Smuzhiyun 	int err;
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	err = isa_register_driver(&snd_msnd_driver, SNDRV_CARDS);
1204*4882a593Smuzhiyun #ifdef CONFIG_PNP
1205*4882a593Smuzhiyun 	if (!err)
1206*4882a593Smuzhiyun 		isa_registered = 1;
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	err = pnp_register_card_driver(&msnd_pnpc_driver);
1209*4882a593Smuzhiyun 	if (!err)
1210*4882a593Smuzhiyun 		pnp_registered = 1;
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	if (isa_registered)
1213*4882a593Smuzhiyun 		err = 0;
1214*4882a593Smuzhiyun #endif
1215*4882a593Smuzhiyun 	return err;
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun 
snd_msnd_exit(void)1218*4882a593Smuzhiyun static void __exit snd_msnd_exit(void)
1219*4882a593Smuzhiyun {
1220*4882a593Smuzhiyun #ifdef CONFIG_PNP
1221*4882a593Smuzhiyun 	if (pnp_registered)
1222*4882a593Smuzhiyun 		pnp_unregister_card_driver(&msnd_pnpc_driver);
1223*4882a593Smuzhiyun 	if (isa_registered)
1224*4882a593Smuzhiyun #endif
1225*4882a593Smuzhiyun 		isa_unregister_driver(&snd_msnd_driver);
1226*4882a593Smuzhiyun }
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun module_init(snd_msnd_init);
1229*4882a593Smuzhiyun module_exit(snd_msnd_exit);
1230*4882a593Smuzhiyun 
1231