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