xref: /OK3568_Linux_fs/kernel/sound/isa/opti9xx/miro.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *   ALSA soundcard driver for Miro miroSOUND PCM1 pro
4*4882a593Smuzhiyun  *                                  miroSOUND PCM12
5*4882a593Smuzhiyun  *                                  miroSOUND PCM20 Radio
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *   Copyright (C) 2004-2005 Martin Langer <martin-langer@gmx.de>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *   Based on OSS ACI and ALSA OPTi9xx drivers
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/err.h>
14*4882a593Smuzhiyun #include <linux/isa.h>
15*4882a593Smuzhiyun #include <linux/pnp.h>
16*4882a593Smuzhiyun #include <linux/delay.h>
17*4882a593Smuzhiyun #include <linux/ioport.h>
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/io.h>
20*4882a593Smuzhiyun #include <asm/dma.h>
21*4882a593Smuzhiyun #include <sound/core.h>
22*4882a593Smuzhiyun #include <sound/wss.h>
23*4882a593Smuzhiyun #include <sound/mpu401.h>
24*4882a593Smuzhiyun #include <sound/opl4.h>
25*4882a593Smuzhiyun #include <sound/control.h>
26*4882a593Smuzhiyun #include <sound/info.h>
27*4882a593Smuzhiyun #define SNDRV_LEGACY_FIND_FREE_IOPORT
28*4882a593Smuzhiyun #define SNDRV_LEGACY_FIND_FREE_IRQ
29*4882a593Smuzhiyun #define SNDRV_LEGACY_FIND_FREE_DMA
30*4882a593Smuzhiyun #include <sound/initval.h>
31*4882a593Smuzhiyun #include <sound/aci.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun MODULE_AUTHOR("Martin Langer <martin-langer@gmx.de>");
34*4882a593Smuzhiyun MODULE_LICENSE("GPL");
35*4882a593Smuzhiyun MODULE_DESCRIPTION("Miro miroSOUND PCM1 pro, PCM12, PCM20 Radio");
36*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("{{Miro,miroSOUND PCM1 pro}, "
37*4882a593Smuzhiyun 			"{Miro,miroSOUND PCM12}, "
38*4882a593Smuzhiyun 			"{Miro,miroSOUND PCM20 Radio}}");
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun static int index = SNDRV_DEFAULT_IDX1;		/* Index 0-MAX */
41*4882a593Smuzhiyun static char *id = SNDRV_DEFAULT_STR1;		/* ID for this card */
42*4882a593Smuzhiyun static long port = SNDRV_DEFAULT_PORT1; 	/* 0x530,0xe80,0xf40,0x604 */
43*4882a593Smuzhiyun static long mpu_port = SNDRV_DEFAULT_PORT1;	/* 0x300,0x310,0x320,0x330 */
44*4882a593Smuzhiyun static long fm_port = SNDRV_DEFAULT_PORT1;	/* 0x388 */
45*4882a593Smuzhiyun static int irq = SNDRV_DEFAULT_IRQ1;		/* 5,7,9,10,11 */
46*4882a593Smuzhiyun static int mpu_irq = SNDRV_DEFAULT_IRQ1;	/* 5,7,9,10 */
47*4882a593Smuzhiyun static int dma1 = SNDRV_DEFAULT_DMA1;		/* 0,1,3 */
48*4882a593Smuzhiyun static int dma2 = SNDRV_DEFAULT_DMA1;		/* 0,1,3 */
49*4882a593Smuzhiyun static int wss;
50*4882a593Smuzhiyun static int ide;
51*4882a593Smuzhiyun #ifdef CONFIG_PNP
52*4882a593Smuzhiyun static bool isapnp = 1;				/* Enable ISA PnP detection */
53*4882a593Smuzhiyun #endif
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun module_param(index, int, 0444);
56*4882a593Smuzhiyun MODULE_PARM_DESC(index, "Index value for miro soundcard.");
57*4882a593Smuzhiyun module_param(id, charp, 0444);
58*4882a593Smuzhiyun MODULE_PARM_DESC(id, "ID string for miro soundcard.");
59*4882a593Smuzhiyun module_param_hw(port, long, ioport, 0444);
60*4882a593Smuzhiyun MODULE_PARM_DESC(port, "WSS port # for miro driver.");
61*4882a593Smuzhiyun module_param_hw(mpu_port, long, ioport, 0444);
62*4882a593Smuzhiyun MODULE_PARM_DESC(mpu_port, "MPU-401 port # for miro driver.");
63*4882a593Smuzhiyun module_param_hw(fm_port, long, ioport, 0444);
64*4882a593Smuzhiyun MODULE_PARM_DESC(fm_port, "FM Port # for miro driver.");
65*4882a593Smuzhiyun module_param_hw(irq, int, irq, 0444);
66*4882a593Smuzhiyun MODULE_PARM_DESC(irq, "WSS irq # for miro driver.");
67*4882a593Smuzhiyun module_param_hw(mpu_irq, int, irq, 0444);
68*4882a593Smuzhiyun MODULE_PARM_DESC(mpu_irq, "MPU-401 irq # for miro driver.");
69*4882a593Smuzhiyun module_param_hw(dma1, int, dma, 0444);
70*4882a593Smuzhiyun MODULE_PARM_DESC(dma1, "1st dma # for miro driver.");
71*4882a593Smuzhiyun module_param_hw(dma2, int, dma, 0444);
72*4882a593Smuzhiyun MODULE_PARM_DESC(dma2, "2nd dma # for miro driver.");
73*4882a593Smuzhiyun module_param(wss, int, 0444);
74*4882a593Smuzhiyun MODULE_PARM_DESC(wss, "wss mode");
75*4882a593Smuzhiyun module_param(ide, int, 0444);
76*4882a593Smuzhiyun MODULE_PARM_DESC(ide, "enable ide port");
77*4882a593Smuzhiyun #ifdef CONFIG_PNP
78*4882a593Smuzhiyun module_param(isapnp, bool, 0444);
79*4882a593Smuzhiyun MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
80*4882a593Smuzhiyun #endif
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun #define OPTi9XX_HW_DETECT	0
83*4882a593Smuzhiyun #define OPTi9XX_HW_82C928	1
84*4882a593Smuzhiyun #define OPTi9XX_HW_82C929	2
85*4882a593Smuzhiyun #define OPTi9XX_HW_82C924	3
86*4882a593Smuzhiyun #define OPTi9XX_HW_82C925	4
87*4882a593Smuzhiyun #define OPTi9XX_HW_82C930	5
88*4882a593Smuzhiyun #define OPTi9XX_HW_82C931	6
89*4882a593Smuzhiyun #define OPTi9XX_HW_82C933	7
90*4882a593Smuzhiyun #define OPTi9XX_HW_LAST		OPTi9XX_HW_82C933
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun #define OPTi9XX_MC_REG(n)	n
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun struct snd_miro {
95*4882a593Smuzhiyun 	unsigned short hardware;
96*4882a593Smuzhiyun 	unsigned char password;
97*4882a593Smuzhiyun 	char name[7];
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	struct resource *res_mc_base;
100*4882a593Smuzhiyun 	struct resource *res_aci_port;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	unsigned long mc_base;
103*4882a593Smuzhiyun 	unsigned long mc_base_size;
104*4882a593Smuzhiyun 	unsigned long pwd_reg;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	spinlock_t lock;
107*4882a593Smuzhiyun 	struct snd_pcm *pcm;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	long wss_base;
110*4882a593Smuzhiyun 	int irq;
111*4882a593Smuzhiyun 	int dma1;
112*4882a593Smuzhiyun 	int dma2;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	long mpu_port;
115*4882a593Smuzhiyun 	int mpu_irq;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	struct snd_miro_aci *aci;
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun static struct snd_miro_aci aci_device;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun static const char * const snd_opti9xx_names[] = {
123*4882a593Smuzhiyun 	"unknown",
124*4882a593Smuzhiyun 	"82C928", "82C929",
125*4882a593Smuzhiyun 	"82C924", "82C925",
126*4882a593Smuzhiyun 	"82C930", "82C931", "82C933"
127*4882a593Smuzhiyun };
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun static int snd_miro_pnp_is_probed;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun #ifdef CONFIG_PNP
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun static const struct pnp_card_device_id snd_miro_pnpids[] = {
134*4882a593Smuzhiyun 	/* PCM20 and PCM12 in PnP mode */
135*4882a593Smuzhiyun 	{ .id = "MIR0924",
136*4882a593Smuzhiyun 	  .devs = { { "MIR0000" }, { "MIR0002" }, { "MIR0005" } }, },
137*4882a593Smuzhiyun 	{ .id = "" }
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pnp_card, snd_miro_pnpids);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun #endif	/* CONFIG_PNP */
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun /*
145*4882a593Smuzhiyun  *  ACI control
146*4882a593Smuzhiyun  */
147*4882a593Smuzhiyun 
aci_busy_wait(struct snd_miro_aci * aci)148*4882a593Smuzhiyun static int aci_busy_wait(struct snd_miro_aci *aci)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun 	long timeout;
151*4882a593Smuzhiyun 	unsigned char byte;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	for (timeout = 1; timeout <= ACI_MINTIME + 30; timeout++) {
154*4882a593Smuzhiyun 		byte = inb(aci->aci_port + ACI_REG_BUSY);
155*4882a593Smuzhiyun 		if ((byte & 1) == 0) {
156*4882a593Smuzhiyun 			if (timeout >= ACI_MINTIME)
157*4882a593Smuzhiyun 				snd_printd("aci ready in round %ld.\n",
158*4882a593Smuzhiyun 					   timeout-ACI_MINTIME);
159*4882a593Smuzhiyun 			return byte;
160*4882a593Smuzhiyun 		}
161*4882a593Smuzhiyun 		if (timeout >= ACI_MINTIME) {
162*4882a593Smuzhiyun 			long out=10*HZ;
163*4882a593Smuzhiyun 			switch (timeout-ACI_MINTIME) {
164*4882a593Smuzhiyun 			case 0 ... 9:
165*4882a593Smuzhiyun 				out /= 10;
166*4882a593Smuzhiyun 				fallthrough;
167*4882a593Smuzhiyun 			case 10 ... 19:
168*4882a593Smuzhiyun 				out /= 10;
169*4882a593Smuzhiyun 				fallthrough;
170*4882a593Smuzhiyun 			case 20 ... 30:
171*4882a593Smuzhiyun 				out /= 10;
172*4882a593Smuzhiyun 				fallthrough;
173*4882a593Smuzhiyun 			default:
174*4882a593Smuzhiyun 				set_current_state(TASK_UNINTERRUPTIBLE);
175*4882a593Smuzhiyun 				schedule_timeout(out);
176*4882a593Smuzhiyun 				break;
177*4882a593Smuzhiyun 			}
178*4882a593Smuzhiyun 		}
179*4882a593Smuzhiyun 	}
180*4882a593Smuzhiyun 	snd_printk(KERN_ERR "aci_busy_wait() time out\n");
181*4882a593Smuzhiyun 	return -EBUSY;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
aci_write(struct snd_miro_aci * aci,unsigned char byte)184*4882a593Smuzhiyun static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	if (aci_busy_wait(aci) >= 0) {
187*4882a593Smuzhiyun 		outb(byte, aci->aci_port + ACI_REG_COMMAND);
188*4882a593Smuzhiyun 		return 0;
189*4882a593Smuzhiyun 	} else {
190*4882a593Smuzhiyun 		snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte);
191*4882a593Smuzhiyun 		return -EBUSY;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
aci_read(struct snd_miro_aci * aci)195*4882a593Smuzhiyun static inline int aci_read(struct snd_miro_aci *aci)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	unsigned char byte;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (aci_busy_wait(aci) >= 0) {
200*4882a593Smuzhiyun 		byte = inb(aci->aci_port + ACI_REG_STATUS);
201*4882a593Smuzhiyun 		return byte;
202*4882a593Smuzhiyun 	} else {
203*4882a593Smuzhiyun 		snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n");
204*4882a593Smuzhiyun 		return -EBUSY;
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
snd_aci_cmd(struct snd_miro_aci * aci,int write1,int write2,int write3)208*4882a593Smuzhiyun int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	int write[] = {write1, write2, write3};
211*4882a593Smuzhiyun 	int value, i;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	if (mutex_lock_interruptible(&aci->aci_mutex))
214*4882a593Smuzhiyun 		return -EINTR;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	for (i=0; i<3; i++) {
217*4882a593Smuzhiyun 		if (write[i]< 0 || write[i] > 255)
218*4882a593Smuzhiyun 			break;
219*4882a593Smuzhiyun 		else {
220*4882a593Smuzhiyun 			value = aci_write(aci, write[i]);
221*4882a593Smuzhiyun 			if (value < 0)
222*4882a593Smuzhiyun 				goto out;
223*4882a593Smuzhiyun 		}
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	value = aci_read(aci);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun out:	mutex_unlock(&aci->aci_mutex);
229*4882a593Smuzhiyun 	return value;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun EXPORT_SYMBOL(snd_aci_cmd);
232*4882a593Smuzhiyun 
aci_getvalue(struct snd_miro_aci * aci,unsigned char index)233*4882a593Smuzhiyun static int aci_getvalue(struct snd_miro_aci *aci, unsigned char index)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	return snd_aci_cmd(aci, ACI_STATUS, index, -1);
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
aci_setvalue(struct snd_miro_aci * aci,unsigned char index,int value)238*4882a593Smuzhiyun static int aci_setvalue(struct snd_miro_aci *aci, unsigned char index,
239*4882a593Smuzhiyun 			int value)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	return snd_aci_cmd(aci, index, value, -1);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
snd_aci_get_aci(void)244*4882a593Smuzhiyun struct snd_miro_aci *snd_aci_get_aci(void)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun 	if (aci_device.aci_port == 0)
247*4882a593Smuzhiyun 		return NULL;
248*4882a593Smuzhiyun 	return &aci_device;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun EXPORT_SYMBOL(snd_aci_get_aci);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun /*
253*4882a593Smuzhiyun  *  MIXER part
254*4882a593Smuzhiyun  */
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun #define snd_miro_info_capture	snd_ctl_boolean_mono_info
257*4882a593Smuzhiyun 
snd_miro_get_capture(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)258*4882a593Smuzhiyun static int snd_miro_get_capture(struct snd_kcontrol *kcontrol,
259*4882a593Smuzhiyun 				struct snd_ctl_elem_value *ucontrol)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
262*4882a593Smuzhiyun 	int value;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	value = aci_getvalue(miro->aci, ACI_S_GENERAL);
265*4882a593Smuzhiyun 	if (value < 0) {
266*4882a593Smuzhiyun 		snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n",
267*4882a593Smuzhiyun 			   value);
268*4882a593Smuzhiyun 		return value;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = value & 0x20;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	return 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
snd_miro_put_capture(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)276*4882a593Smuzhiyun static int snd_miro_put_capture(struct snd_kcontrol *kcontrol,
277*4882a593Smuzhiyun 				struct snd_ctl_elem_value *ucontrol)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
280*4882a593Smuzhiyun 	int change, value, error;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	value = !(ucontrol->value.integer.value[0]);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value);
285*4882a593Smuzhiyun 	if (error < 0) {
286*4882a593Smuzhiyun 		snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n",
287*4882a593Smuzhiyun 			   error);
288*4882a593Smuzhiyun 		return error;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	change = (value != miro->aci->aci_solomode);
292*4882a593Smuzhiyun 	miro->aci->aci_solomode = value;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	return change;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
snd_miro_info_preamp(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)297*4882a593Smuzhiyun static int snd_miro_info_preamp(struct snd_kcontrol *kcontrol,
298*4882a593Smuzhiyun 				struct snd_ctl_elem_info *uinfo)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
301*4882a593Smuzhiyun 	uinfo->count = 1;
302*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
303*4882a593Smuzhiyun 	uinfo->value.integer.max = 3;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	return 0;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
snd_miro_get_preamp(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)308*4882a593Smuzhiyun static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol,
309*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *ucontrol)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun 	struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
312*4882a593Smuzhiyun 	int value;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (miro->aci->aci_version <= 176) {
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 		/*
317*4882a593Smuzhiyun 		   OSS says it's not readable with versions < 176.
318*4882a593Smuzhiyun 		   But it doesn't work on my card,
319*4882a593Smuzhiyun 		   which is a PCM12 with aci_version = 176.
320*4882a593Smuzhiyun 		*/
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 		ucontrol->value.integer.value[0] = miro->aci->aci_preamp;
323*4882a593Smuzhiyun 		return 0;
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	value = aci_getvalue(miro->aci, ACI_GET_PREAMP);
327*4882a593Smuzhiyun 	if (value < 0) {
328*4882a593Smuzhiyun 		snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n",
329*4882a593Smuzhiyun 			   value);
330*4882a593Smuzhiyun 		return value;
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = value;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	return 0;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
snd_miro_put_preamp(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)338*4882a593Smuzhiyun static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol,
339*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *ucontrol)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
342*4882a593Smuzhiyun 	int error, value, change;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	value = ucontrol->value.integer.value[0];
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value);
347*4882a593Smuzhiyun 	if (error < 0) {
348*4882a593Smuzhiyun 		snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n",
349*4882a593Smuzhiyun 			   error);
350*4882a593Smuzhiyun 		return error;
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	change = (value != miro->aci->aci_preamp);
354*4882a593Smuzhiyun 	miro->aci->aci_preamp = value;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	return change;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun #define snd_miro_info_amp	snd_ctl_boolean_mono_info
360*4882a593Smuzhiyun 
snd_miro_get_amp(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)361*4882a593Smuzhiyun static int snd_miro_get_amp(struct snd_kcontrol *kcontrol,
362*4882a593Smuzhiyun 			    struct snd_ctl_elem_value *ucontrol)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
365*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = miro->aci->aci_amp;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
snd_miro_put_amp(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)370*4882a593Smuzhiyun static int snd_miro_put_amp(struct snd_kcontrol *kcontrol,
371*4882a593Smuzhiyun 			    struct snd_ctl_elem_value *ucontrol)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun 	struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
374*4882a593Smuzhiyun 	int error, value, change;
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	value = ucontrol->value.integer.value[0];
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value);
379*4882a593Smuzhiyun 	if (error < 0) {
380*4882a593Smuzhiyun 		snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error);
381*4882a593Smuzhiyun 		return error;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	change = (value != miro->aci->aci_amp);
385*4882a593Smuzhiyun 	miro->aci->aci_amp = value;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	return change;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun #define MIRO_DOUBLE(ctl_name, ctl_index, get_right_reg, set_right_reg) \
391*4882a593Smuzhiyun { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
392*4882a593Smuzhiyun   .name = ctl_name, \
393*4882a593Smuzhiyun   .index = ctl_index, \
394*4882a593Smuzhiyun   .info = snd_miro_info_double, \
395*4882a593Smuzhiyun   .get = snd_miro_get_double, \
396*4882a593Smuzhiyun   .put = snd_miro_put_double, \
397*4882a593Smuzhiyun   .private_value = get_right_reg | (set_right_reg << 8) \
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
snd_miro_info_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)400*4882a593Smuzhiyun static int snd_miro_info_double(struct snd_kcontrol *kcontrol,
401*4882a593Smuzhiyun 				struct snd_ctl_elem_info *uinfo)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	int reg = kcontrol->private_value & 0xff;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
406*4882a593Smuzhiyun 	uinfo->count = 2;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if ((reg >= ACI_GET_EQ1) && (reg <= ACI_GET_EQ7)) {
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 		/* equalizer elements */
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 		uinfo->value.integer.min = - 0x7f;
413*4882a593Smuzhiyun 		uinfo->value.integer.max = 0x7f;
414*4882a593Smuzhiyun 	} else {
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 		/* non-equalizer elements */
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 		uinfo->value.integer.min = 0;
419*4882a593Smuzhiyun 		uinfo->value.integer.max = 0x20;
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	return 0;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
snd_miro_get_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uinfo)425*4882a593Smuzhiyun static int snd_miro_get_double(struct snd_kcontrol *kcontrol,
426*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *uinfo)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
429*4882a593Smuzhiyun 	int left_val, right_val;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	int right_reg = kcontrol->private_value & 0xff;
432*4882a593Smuzhiyun 	int left_reg = right_reg + 1;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	right_val = aci_getvalue(miro->aci, right_reg);
435*4882a593Smuzhiyun 	if (right_val < 0) {
436*4882a593Smuzhiyun 		snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val);
437*4882a593Smuzhiyun 		return right_val;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	left_val = aci_getvalue(miro->aci, left_reg);
441*4882a593Smuzhiyun 	if (left_val < 0) {
442*4882a593Smuzhiyun 		snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val);
443*4882a593Smuzhiyun 		return left_val;
444*4882a593Smuzhiyun 	}
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	if ((right_reg >= ACI_GET_EQ1) && (right_reg <= ACI_GET_EQ7)) {
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 		/* equalizer elements */
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 		if (left_val < 0x80) {
451*4882a593Smuzhiyun 			uinfo->value.integer.value[0] = left_val;
452*4882a593Smuzhiyun 		} else {
453*4882a593Smuzhiyun 			uinfo->value.integer.value[0] = 0x80 - left_val;
454*4882a593Smuzhiyun 		}
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 		if (right_val < 0x80) {
457*4882a593Smuzhiyun 			uinfo->value.integer.value[1] = right_val;
458*4882a593Smuzhiyun 		} else {
459*4882a593Smuzhiyun 			uinfo->value.integer.value[1] = 0x80 - right_val;
460*4882a593Smuzhiyun 		}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	} else {
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 		/* non-equalizer elements */
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 		uinfo->value.integer.value[0] = 0x20 - left_val;
467*4882a593Smuzhiyun 		uinfo->value.integer.value[1] = 0x20 - right_val;
468*4882a593Smuzhiyun 	}
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	return 0;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
snd_miro_put_double(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)473*4882a593Smuzhiyun static int snd_miro_put_double(struct snd_kcontrol *kcontrol,
474*4882a593Smuzhiyun 			       struct snd_ctl_elem_value *ucontrol)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	struct snd_miro *miro = snd_kcontrol_chip(kcontrol);
477*4882a593Smuzhiyun 	struct snd_miro_aci *aci = miro->aci;
478*4882a593Smuzhiyun 	int left, right, left_old, right_old;
479*4882a593Smuzhiyun 	int setreg_left, setreg_right, getreg_left, getreg_right;
480*4882a593Smuzhiyun 	int change, error;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	left = ucontrol->value.integer.value[0];
483*4882a593Smuzhiyun 	right = ucontrol->value.integer.value[1];
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	setreg_right = (kcontrol->private_value >> 8) & 0xff;
486*4882a593Smuzhiyun 	setreg_left = setreg_right + 8;
487*4882a593Smuzhiyun 	if (setreg_right == ACI_SET_MASTER)
488*4882a593Smuzhiyun 		setreg_left -= 7;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	getreg_right = kcontrol->private_value & 0xff;
491*4882a593Smuzhiyun 	getreg_left = getreg_right + 1;
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	left_old = aci_getvalue(aci, getreg_left);
494*4882a593Smuzhiyun 	if (left_old < 0) {
495*4882a593Smuzhiyun 		snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old);
496*4882a593Smuzhiyun 		return left_old;
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	right_old = aci_getvalue(aci, getreg_right);
500*4882a593Smuzhiyun 	if (right_old < 0) {
501*4882a593Smuzhiyun 		snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old);
502*4882a593Smuzhiyun 		return right_old;
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	if ((getreg_right >= ACI_GET_EQ1) && (getreg_right <= ACI_GET_EQ7)) {
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 		/* equalizer elements */
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 		if (left < -0x7f || left > 0x7f ||
510*4882a593Smuzhiyun 		    right < -0x7f || right > 0x7f)
511*4882a593Smuzhiyun 			return -EINVAL;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 		if (left_old > 0x80)
514*4882a593Smuzhiyun 			left_old = 0x80 - left_old;
515*4882a593Smuzhiyun 		if (right_old > 0x80)
516*4882a593Smuzhiyun 			right_old = 0x80 - right_old;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 		if (left >= 0) {
519*4882a593Smuzhiyun 			error = aci_setvalue(aci, setreg_left, left);
520*4882a593Smuzhiyun 			if (error < 0) {
521*4882a593Smuzhiyun 				snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
522*4882a593Smuzhiyun 					   left, error);
523*4882a593Smuzhiyun 				return error;
524*4882a593Smuzhiyun 			}
525*4882a593Smuzhiyun 		} else {
526*4882a593Smuzhiyun 			error = aci_setvalue(aci, setreg_left, 0x80 - left);
527*4882a593Smuzhiyun 			if (error < 0) {
528*4882a593Smuzhiyun 				snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
529*4882a593Smuzhiyun 					   0x80 - left, error);
530*4882a593Smuzhiyun 				return error;
531*4882a593Smuzhiyun 			}
532*4882a593Smuzhiyun 		}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 		if (right >= 0) {
535*4882a593Smuzhiyun 			error = aci_setvalue(aci, setreg_right, right);
536*4882a593Smuzhiyun 			if (error < 0) {
537*4882a593Smuzhiyun 				snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
538*4882a593Smuzhiyun 					   right, error);
539*4882a593Smuzhiyun 				return error;
540*4882a593Smuzhiyun 			}
541*4882a593Smuzhiyun 		} else {
542*4882a593Smuzhiyun 			error = aci_setvalue(aci, setreg_right, 0x80 - right);
543*4882a593Smuzhiyun 			if (error < 0) {
544*4882a593Smuzhiyun 				snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
545*4882a593Smuzhiyun 					   0x80 - right, error);
546*4882a593Smuzhiyun 				return error;
547*4882a593Smuzhiyun 			}
548*4882a593Smuzhiyun 		}
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	} else {
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 		/* non-equalizer elements */
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 		if (left < 0 || left > 0x20 ||
555*4882a593Smuzhiyun 		    right < 0 || right > 0x20)
556*4882a593Smuzhiyun 			return -EINVAL;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 		left_old = 0x20 - left_old;
559*4882a593Smuzhiyun 		right_old = 0x20 - right_old;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 		error = aci_setvalue(aci, setreg_left, 0x20 - left);
562*4882a593Smuzhiyun 		if (error < 0) {
563*4882a593Smuzhiyun 			snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
564*4882a593Smuzhiyun 				   0x20 - left, error);
565*4882a593Smuzhiyun 			return error;
566*4882a593Smuzhiyun 		}
567*4882a593Smuzhiyun 		error = aci_setvalue(aci, setreg_right, 0x20 - right);
568*4882a593Smuzhiyun 		if (error < 0) {
569*4882a593Smuzhiyun 			snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
570*4882a593Smuzhiyun 				   0x20 - right, error);
571*4882a593Smuzhiyun 			return error;
572*4882a593Smuzhiyun 		}
573*4882a593Smuzhiyun 	}
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	change = (left != left_old) || (right != right_old);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	return change;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_miro_controls[] = {
581*4882a593Smuzhiyun MIRO_DOUBLE("Master Playback Volume", 0, ACI_GET_MASTER, ACI_SET_MASTER),
582*4882a593Smuzhiyun MIRO_DOUBLE("Mic Playback Volume", 1, ACI_GET_MIC, ACI_SET_MIC),
583*4882a593Smuzhiyun MIRO_DOUBLE("Line Playback Volume", 1, ACI_GET_LINE, ACI_SET_LINE),
584*4882a593Smuzhiyun MIRO_DOUBLE("CD Playback Volume", 0, ACI_GET_CD, ACI_SET_CD),
585*4882a593Smuzhiyun MIRO_DOUBLE("Synth Playback Volume", 0, ACI_GET_SYNTH, ACI_SET_SYNTH),
586*4882a593Smuzhiyun MIRO_DOUBLE("PCM Playback Volume", 1, ACI_GET_PCM, ACI_SET_PCM),
587*4882a593Smuzhiyun MIRO_DOUBLE("Aux Playback Volume", 2, ACI_GET_LINE2, ACI_SET_LINE2),
588*4882a593Smuzhiyun };
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun /* Equalizer with seven bands (only PCM20)
591*4882a593Smuzhiyun    from -12dB up to +12dB on each band */
592*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_miro_eq_controls[] = {
593*4882a593Smuzhiyun MIRO_DOUBLE("Tone Control - 28 Hz", 0, ACI_GET_EQ1, ACI_SET_EQ1),
594*4882a593Smuzhiyun MIRO_DOUBLE("Tone Control - 160 Hz", 0, ACI_GET_EQ2, ACI_SET_EQ2),
595*4882a593Smuzhiyun MIRO_DOUBLE("Tone Control - 400 Hz", 0, ACI_GET_EQ3, ACI_SET_EQ3),
596*4882a593Smuzhiyun MIRO_DOUBLE("Tone Control - 1 kHz", 0, ACI_GET_EQ4, ACI_SET_EQ4),
597*4882a593Smuzhiyun MIRO_DOUBLE("Tone Control - 2.5 kHz", 0, ACI_GET_EQ5, ACI_SET_EQ5),
598*4882a593Smuzhiyun MIRO_DOUBLE("Tone Control - 6.3 kHz", 0, ACI_GET_EQ6, ACI_SET_EQ6),
599*4882a593Smuzhiyun MIRO_DOUBLE("Tone Control - 16 kHz", 0, ACI_GET_EQ7, ACI_SET_EQ7),
600*4882a593Smuzhiyun };
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_miro_radio_control[] = {
603*4882a593Smuzhiyun MIRO_DOUBLE("Radio Playback Volume", 0, ACI_GET_LINE1, ACI_SET_LINE1),
604*4882a593Smuzhiyun };
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_miro_line_control[] = {
607*4882a593Smuzhiyun MIRO_DOUBLE("Line Playback Volume", 2, ACI_GET_LINE1, ACI_SET_LINE1),
608*4882a593Smuzhiyun };
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_miro_preamp_control[] = {
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
613*4882a593Smuzhiyun 	.name = "Mic Boost",
614*4882a593Smuzhiyun 	.index = 1,
615*4882a593Smuzhiyun 	.info = snd_miro_info_preamp,
616*4882a593Smuzhiyun 	.get = snd_miro_get_preamp,
617*4882a593Smuzhiyun 	.put = snd_miro_put_preamp,
618*4882a593Smuzhiyun }};
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_miro_amp_control[] = {
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
623*4882a593Smuzhiyun 	.name = "Line Boost",
624*4882a593Smuzhiyun 	.index = 0,
625*4882a593Smuzhiyun 	.info = snd_miro_info_amp,
626*4882a593Smuzhiyun 	.get = snd_miro_get_amp,
627*4882a593Smuzhiyun 	.put = snd_miro_put_amp,
628*4882a593Smuzhiyun }};
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun static const struct snd_kcontrol_new snd_miro_capture_control[] = {
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
633*4882a593Smuzhiyun 	.name = "PCM Capture Switch",
634*4882a593Smuzhiyun 	.index = 0,
635*4882a593Smuzhiyun 	.info = snd_miro_info_capture,
636*4882a593Smuzhiyun 	.get = snd_miro_get_capture,
637*4882a593Smuzhiyun 	.put = snd_miro_put_capture,
638*4882a593Smuzhiyun }};
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun static const unsigned char aci_init_values[][2] = {
641*4882a593Smuzhiyun 	{ ACI_SET_MUTE, 0x00 },
642*4882a593Smuzhiyun 	{ ACI_SET_POWERAMP, 0x00 },
643*4882a593Smuzhiyun 	{ ACI_SET_PREAMP, 0x00 },
644*4882a593Smuzhiyun 	{ ACI_SET_SOLOMODE, 0x00 },
645*4882a593Smuzhiyun 	{ ACI_SET_MIC + 0, 0x20 },
646*4882a593Smuzhiyun 	{ ACI_SET_MIC + 8, 0x20 },
647*4882a593Smuzhiyun 	{ ACI_SET_LINE + 0, 0x20 },
648*4882a593Smuzhiyun 	{ ACI_SET_LINE + 8, 0x20 },
649*4882a593Smuzhiyun 	{ ACI_SET_CD + 0, 0x20 },
650*4882a593Smuzhiyun 	{ ACI_SET_CD + 8, 0x20 },
651*4882a593Smuzhiyun 	{ ACI_SET_PCM + 0, 0x20 },
652*4882a593Smuzhiyun 	{ ACI_SET_PCM + 8, 0x20 },
653*4882a593Smuzhiyun 	{ ACI_SET_LINE1 + 0, 0x20 },
654*4882a593Smuzhiyun 	{ ACI_SET_LINE1 + 8, 0x20 },
655*4882a593Smuzhiyun 	{ ACI_SET_LINE2 + 0, 0x20 },
656*4882a593Smuzhiyun 	{ ACI_SET_LINE2 + 8, 0x20 },
657*4882a593Smuzhiyun 	{ ACI_SET_SYNTH + 0, 0x20 },
658*4882a593Smuzhiyun 	{ ACI_SET_SYNTH + 8, 0x20 },
659*4882a593Smuzhiyun 	{ ACI_SET_MASTER + 0, 0x20 },
660*4882a593Smuzhiyun 	{ ACI_SET_MASTER + 1, 0x20 },
661*4882a593Smuzhiyun };
662*4882a593Smuzhiyun 
snd_set_aci_init_values(struct snd_miro * miro)663*4882a593Smuzhiyun static int snd_set_aci_init_values(struct snd_miro *miro)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	int idx, error;
666*4882a593Smuzhiyun 	struct snd_miro_aci *aci = miro->aci;
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	/* enable WSS on PCM1 */
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	if ((aci->aci_product == 'A') && wss) {
671*4882a593Smuzhiyun 		error = aci_setvalue(aci, ACI_SET_WSS, wss);
672*4882a593Smuzhiyun 		if (error < 0) {
673*4882a593Smuzhiyun 			snd_printk(KERN_ERR "enabling WSS mode failed\n");
674*4882a593Smuzhiyun 			return error;
675*4882a593Smuzhiyun 		}
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	/* enable IDE port */
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	if (ide) {
681*4882a593Smuzhiyun 		error = aci_setvalue(aci, ACI_SET_IDE, ide);
682*4882a593Smuzhiyun 		if (error < 0) {
683*4882a593Smuzhiyun 			snd_printk(KERN_ERR "enabling IDE port failed\n");
684*4882a593Smuzhiyun 			return error;
685*4882a593Smuzhiyun 		}
686*4882a593Smuzhiyun 	}
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	/* set common aci values */
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) {
691*4882a593Smuzhiyun 		error = aci_setvalue(aci, aci_init_values[idx][0],
692*4882a593Smuzhiyun 				     aci_init_values[idx][1]);
693*4882a593Smuzhiyun 		if (error < 0) {
694*4882a593Smuzhiyun 			snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n",
695*4882a593Smuzhiyun 				   aci_init_values[idx][0], error);
696*4882a593Smuzhiyun                         return error;
697*4882a593Smuzhiyun                 }
698*4882a593Smuzhiyun 	}
699*4882a593Smuzhiyun 	aci->aci_amp = 0;
700*4882a593Smuzhiyun 	aci->aci_preamp = 0;
701*4882a593Smuzhiyun 	aci->aci_solomode = 1;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	return 0;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun 
snd_miro_mixer(struct snd_card * card,struct snd_miro * miro)706*4882a593Smuzhiyun static int snd_miro_mixer(struct snd_card *card,
707*4882a593Smuzhiyun 			  struct snd_miro *miro)
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun 	unsigned int idx;
710*4882a593Smuzhiyun 	int err;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	if (snd_BUG_ON(!miro || !card))
713*4882a593Smuzhiyun 		return -EINVAL;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	switch (miro->hardware) {
716*4882a593Smuzhiyun 	case OPTi9XX_HW_82C924:
717*4882a593Smuzhiyun 		strcpy(card->mixername, "ACI & OPTi924");
718*4882a593Smuzhiyun 		break;
719*4882a593Smuzhiyun 	case OPTi9XX_HW_82C929:
720*4882a593Smuzhiyun 		strcpy(card->mixername, "ACI & OPTi929");
721*4882a593Smuzhiyun 		break;
722*4882a593Smuzhiyun 	default:
723*4882a593Smuzhiyun 		snd_BUG();
724*4882a593Smuzhiyun 		break;
725*4882a593Smuzhiyun 	}
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	for (idx = 0; idx < ARRAY_SIZE(snd_miro_controls); idx++) {
728*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_controls[idx], miro))) < 0)
729*4882a593Smuzhiyun 			return err;
730*4882a593Smuzhiyun 	}
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	if ((miro->aci->aci_product == 'A') ||
733*4882a593Smuzhiyun 	    (miro->aci->aci_product == 'B')) {
734*4882a593Smuzhiyun 		/* PCM1/PCM12 with power-amp and Line 2 */
735*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0)
736*4882a593Smuzhiyun 			return err;
737*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_amp_control[0], miro))) < 0)
738*4882a593Smuzhiyun 			return err;
739*4882a593Smuzhiyun 	}
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	if ((miro->aci->aci_product == 'B') ||
742*4882a593Smuzhiyun 	    (miro->aci->aci_product == 'C')) {
743*4882a593Smuzhiyun 		/* PCM12/PCM20 with mic-preamp */
744*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0)
745*4882a593Smuzhiyun 			return err;
746*4882a593Smuzhiyun 		if (miro->aci->aci_version >= 176)
747*4882a593Smuzhiyun 			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0)
748*4882a593Smuzhiyun 				return err;
749*4882a593Smuzhiyun 	}
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	if (miro->aci->aci_product == 'C') {
752*4882a593Smuzhiyun 		/* PCM20 with radio and 7 band equalizer */
753*4882a593Smuzhiyun 		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0)
754*4882a593Smuzhiyun 			return err;
755*4882a593Smuzhiyun 		for (idx = 0; idx < ARRAY_SIZE(snd_miro_eq_controls); idx++) {
756*4882a593Smuzhiyun 			if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_eq_controls[idx], miro))) < 0)
757*4882a593Smuzhiyun 				return err;
758*4882a593Smuzhiyun 		}
759*4882a593Smuzhiyun 	}
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	return 0;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun 
snd_miro_init(struct snd_miro * chip,unsigned short hardware)764*4882a593Smuzhiyun static int snd_miro_init(struct snd_miro *chip,
765*4882a593Smuzhiyun 			 unsigned short hardware)
766*4882a593Smuzhiyun {
767*4882a593Smuzhiyun 	static const int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	chip->hardware = hardware;
770*4882a593Smuzhiyun 	strcpy(chip->name, snd_opti9xx_names[hardware]);
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	chip->mc_base_size = opti9xx_mc_size[hardware];
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	spin_lock_init(&chip->lock);
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	chip->wss_base = -1;
777*4882a593Smuzhiyun 	chip->irq = -1;
778*4882a593Smuzhiyun 	chip->dma1 = -1;
779*4882a593Smuzhiyun 	chip->dma2 = -1;
780*4882a593Smuzhiyun 	chip->mpu_port = -1;
781*4882a593Smuzhiyun 	chip->mpu_irq = -1;
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	chip->pwd_reg = 3;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun #ifdef CONFIG_PNP
786*4882a593Smuzhiyun 	if (isapnp && chip->mc_base)
787*4882a593Smuzhiyun 		/* PnP resource gives the least 10 bits */
788*4882a593Smuzhiyun 		chip->mc_base |= 0xc00;
789*4882a593Smuzhiyun 	else
790*4882a593Smuzhiyun #endif
791*4882a593Smuzhiyun 		chip->mc_base = 0xf8c;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 	switch (hardware) {
794*4882a593Smuzhiyun 	case OPTi9XX_HW_82C929:
795*4882a593Smuzhiyun 		chip->password = 0xe3;
796*4882a593Smuzhiyun 		break;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	case OPTi9XX_HW_82C924:
799*4882a593Smuzhiyun 		chip->password = 0xe5;
800*4882a593Smuzhiyun 		break;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	default:
803*4882a593Smuzhiyun 		snd_printk(KERN_ERR "sorry, no support for %d\n", hardware);
804*4882a593Smuzhiyun 		return -ENODEV;
805*4882a593Smuzhiyun 	}
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	return 0;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun 
snd_miro_read(struct snd_miro * chip,unsigned char reg)810*4882a593Smuzhiyun static unsigned char snd_miro_read(struct snd_miro *chip,
811*4882a593Smuzhiyun 				   unsigned char reg)
812*4882a593Smuzhiyun {
813*4882a593Smuzhiyun 	unsigned long flags;
814*4882a593Smuzhiyun 	unsigned char retval = 0xff;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	spin_lock_irqsave(&chip->lock, flags);
817*4882a593Smuzhiyun 	outb(chip->password, chip->mc_base + chip->pwd_reg);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	switch (chip->hardware) {
820*4882a593Smuzhiyun 	case OPTi9XX_HW_82C924:
821*4882a593Smuzhiyun 		if (reg > 7) {
822*4882a593Smuzhiyun 			outb(reg, chip->mc_base + 8);
823*4882a593Smuzhiyun 			outb(chip->password, chip->mc_base + chip->pwd_reg);
824*4882a593Smuzhiyun 			retval = inb(chip->mc_base + 9);
825*4882a593Smuzhiyun 			break;
826*4882a593Smuzhiyun 		}
827*4882a593Smuzhiyun 		fallthrough;
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	case OPTi9XX_HW_82C929:
830*4882a593Smuzhiyun 		retval = inb(chip->mc_base + reg);
831*4882a593Smuzhiyun 		break;
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	default:
834*4882a593Smuzhiyun 		snd_printk(KERN_ERR "sorry, no support for %d\n", chip->hardware);
835*4882a593Smuzhiyun 	}
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	spin_unlock_irqrestore(&chip->lock, flags);
838*4882a593Smuzhiyun 	return retval;
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun 
snd_miro_write(struct snd_miro * chip,unsigned char reg,unsigned char value)841*4882a593Smuzhiyun static void snd_miro_write(struct snd_miro *chip, unsigned char reg,
842*4882a593Smuzhiyun 			   unsigned char value)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun 	unsigned long flags;
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	spin_lock_irqsave(&chip->lock, flags);
847*4882a593Smuzhiyun 	outb(chip->password, chip->mc_base + chip->pwd_reg);
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	switch (chip->hardware) {
850*4882a593Smuzhiyun 	case OPTi9XX_HW_82C924:
851*4882a593Smuzhiyun 		if (reg > 7) {
852*4882a593Smuzhiyun 			outb(reg, chip->mc_base + 8);
853*4882a593Smuzhiyun 			outb(chip->password, chip->mc_base + chip->pwd_reg);
854*4882a593Smuzhiyun 			outb(value, chip->mc_base + 9);
855*4882a593Smuzhiyun 			break;
856*4882a593Smuzhiyun 		}
857*4882a593Smuzhiyun 		fallthrough;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	case OPTi9XX_HW_82C929:
860*4882a593Smuzhiyun 		outb(value, chip->mc_base + reg);
861*4882a593Smuzhiyun 		break;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	default:
864*4882a593Smuzhiyun 		snd_printk(KERN_ERR "sorry, no support for %d\n", chip->hardware);
865*4882a593Smuzhiyun 	}
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	spin_unlock_irqrestore(&chip->lock, flags);
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun 
snd_miro_write_mask(struct snd_miro * chip,unsigned char reg,unsigned char value,unsigned char mask)870*4882a593Smuzhiyun static inline void snd_miro_write_mask(struct snd_miro *chip,
871*4882a593Smuzhiyun 		unsigned char reg, unsigned char value, unsigned char mask)
872*4882a593Smuzhiyun {
873*4882a593Smuzhiyun 	unsigned char oldval = snd_miro_read(chip, reg);
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	snd_miro_write(chip, reg, (oldval & ~mask) | (value & mask));
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun /*
879*4882a593Smuzhiyun  *  Proc Interface
880*4882a593Smuzhiyun  */
881*4882a593Smuzhiyun 
snd_miro_proc_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)882*4882a593Smuzhiyun static void snd_miro_proc_read(struct snd_info_entry * entry,
883*4882a593Smuzhiyun 			       struct snd_info_buffer *buffer)
884*4882a593Smuzhiyun {
885*4882a593Smuzhiyun 	struct snd_miro *miro = (struct snd_miro *) entry->private_data;
886*4882a593Smuzhiyun 	struct snd_miro_aci *aci = miro->aci;
887*4882a593Smuzhiyun 	char* model = "unknown";
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	/* miroSOUND PCM1 pro, early PCM12 */
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun 	if ((miro->hardware == OPTi9XX_HW_82C929) &&
892*4882a593Smuzhiyun 	    (aci->aci_vendor == 'm') &&
893*4882a593Smuzhiyun 	    (aci->aci_product == 'A')) {
894*4882a593Smuzhiyun 		switch (aci->aci_version) {
895*4882a593Smuzhiyun 		case 3:
896*4882a593Smuzhiyun 			model = "miroSOUND PCM1 pro";
897*4882a593Smuzhiyun 			break;
898*4882a593Smuzhiyun 		default:
899*4882a593Smuzhiyun 			model = "miroSOUND PCM1 pro / (early) PCM12";
900*4882a593Smuzhiyun 			break;
901*4882a593Smuzhiyun 		}
902*4882a593Smuzhiyun 	}
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	/* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	if ((miro->hardware == OPTi9XX_HW_82C924) &&
907*4882a593Smuzhiyun 	    (aci->aci_vendor == 'm') &&
908*4882a593Smuzhiyun 	    (aci->aci_product == 'B')) {
909*4882a593Smuzhiyun 		switch (aci->aci_version) {
910*4882a593Smuzhiyun 		case 4:
911*4882a593Smuzhiyun 			model = "miroSOUND PCM12";
912*4882a593Smuzhiyun 			break;
913*4882a593Smuzhiyun 		case 176:
914*4882a593Smuzhiyun 			model = "miroSOUND PCM12 (Rev. E)";
915*4882a593Smuzhiyun 			break;
916*4882a593Smuzhiyun 		default:
917*4882a593Smuzhiyun 			model = "miroSOUND PCM12 / PCM12 pnp";
918*4882a593Smuzhiyun 			break;
919*4882a593Smuzhiyun 		}
920*4882a593Smuzhiyun 	}
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	/* miroSOUND PCM20 radio */
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	if ((miro->hardware == OPTi9XX_HW_82C924) &&
925*4882a593Smuzhiyun 	    (aci->aci_vendor == 'm') &&
926*4882a593Smuzhiyun 	    (aci->aci_product == 'C')) {
927*4882a593Smuzhiyun 		switch (aci->aci_version) {
928*4882a593Smuzhiyun 		case 7:
929*4882a593Smuzhiyun 			model = "miroSOUND PCM20 radio (Rev. E)";
930*4882a593Smuzhiyun 			break;
931*4882a593Smuzhiyun 		default:
932*4882a593Smuzhiyun 			model = "miroSOUND PCM20 radio";
933*4882a593Smuzhiyun 			break;
934*4882a593Smuzhiyun 		}
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	snd_iprintf(buffer, "\nGeneral information:\n");
938*4882a593Smuzhiyun 	snd_iprintf(buffer, "  model   : %s\n", model);
939*4882a593Smuzhiyun 	snd_iprintf(buffer, "  opti    : %s\n", miro->name);
940*4882a593Smuzhiyun 	snd_iprintf(buffer, "  codec   : %s\n", miro->pcm->name);
941*4882a593Smuzhiyun 	snd_iprintf(buffer, "  port    : 0x%lx\n", miro->wss_base);
942*4882a593Smuzhiyun 	snd_iprintf(buffer, "  irq     : %d\n", miro->irq);
943*4882a593Smuzhiyun 	snd_iprintf(buffer, "  dma     : %d,%d\n\n", miro->dma1, miro->dma2);
944*4882a593Smuzhiyun 
945*4882a593Smuzhiyun 	snd_iprintf(buffer, "MPU-401:\n");
946*4882a593Smuzhiyun 	snd_iprintf(buffer, "  port    : 0x%lx\n", miro->mpu_port);
947*4882a593Smuzhiyun 	snd_iprintf(buffer, "  irq     : %d\n\n", miro->mpu_irq);
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	snd_iprintf(buffer, "ACI information:\n");
950*4882a593Smuzhiyun 	snd_iprintf(buffer, "  vendor  : ");
951*4882a593Smuzhiyun 	switch (aci->aci_vendor) {
952*4882a593Smuzhiyun 	case 'm':
953*4882a593Smuzhiyun 		snd_iprintf(buffer, "Miro\n");
954*4882a593Smuzhiyun 		break;
955*4882a593Smuzhiyun 	default:
956*4882a593Smuzhiyun 		snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_vendor);
957*4882a593Smuzhiyun 		break;
958*4882a593Smuzhiyun 	}
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	snd_iprintf(buffer, "  product : ");
961*4882a593Smuzhiyun 	switch (aci->aci_product) {
962*4882a593Smuzhiyun 	case 'A':
963*4882a593Smuzhiyun 		snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n");
964*4882a593Smuzhiyun 		break;
965*4882a593Smuzhiyun 	case 'B':
966*4882a593Smuzhiyun 		snd_iprintf(buffer, "miroSOUND PCM12\n");
967*4882a593Smuzhiyun 		break;
968*4882a593Smuzhiyun 	case 'C':
969*4882a593Smuzhiyun 		snd_iprintf(buffer, "miroSOUND PCM20 radio\n");
970*4882a593Smuzhiyun 		break;
971*4882a593Smuzhiyun 	default:
972*4882a593Smuzhiyun 		snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_product);
973*4882a593Smuzhiyun 		break;
974*4882a593Smuzhiyun 	}
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	snd_iprintf(buffer, "  firmware: %d (0x%x)\n",
977*4882a593Smuzhiyun 		    aci->aci_version, aci->aci_version);
978*4882a593Smuzhiyun 	snd_iprintf(buffer, "  port    : 0x%lx-0x%lx\n",
979*4882a593Smuzhiyun 		    aci->aci_port, aci->aci_port+2);
980*4882a593Smuzhiyun 	snd_iprintf(buffer, "  wss     : 0x%x\n", wss);
981*4882a593Smuzhiyun 	snd_iprintf(buffer, "  ide     : 0x%x\n", ide);
982*4882a593Smuzhiyun 	snd_iprintf(buffer, "  solomode: 0x%x\n", aci->aci_solomode);
983*4882a593Smuzhiyun 	snd_iprintf(buffer, "  amp     : 0x%x\n", aci->aci_amp);
984*4882a593Smuzhiyun 	snd_iprintf(buffer, "  preamp  : 0x%x\n", aci->aci_preamp);
985*4882a593Smuzhiyun }
986*4882a593Smuzhiyun 
snd_miro_proc_init(struct snd_card * card,struct snd_miro * miro)987*4882a593Smuzhiyun static void snd_miro_proc_init(struct snd_card *card,
988*4882a593Smuzhiyun 			       struct snd_miro *miro)
989*4882a593Smuzhiyun {
990*4882a593Smuzhiyun 	snd_card_ro_proc_new(card, "miro", miro, snd_miro_proc_read);
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun /*
994*4882a593Smuzhiyun  *  Init
995*4882a593Smuzhiyun  */
996*4882a593Smuzhiyun 
snd_miro_configure(struct snd_miro * chip)997*4882a593Smuzhiyun static int snd_miro_configure(struct snd_miro *chip)
998*4882a593Smuzhiyun {
999*4882a593Smuzhiyun 	unsigned char wss_base_bits;
1000*4882a593Smuzhiyun 	unsigned char irq_bits;
1001*4882a593Smuzhiyun 	unsigned char dma_bits;
1002*4882a593Smuzhiyun 	unsigned char mpu_port_bits = 0;
1003*4882a593Smuzhiyun 	unsigned char mpu_irq_bits;
1004*4882a593Smuzhiyun 	unsigned long flags;
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
1007*4882a593Smuzhiyun 	snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */
1008*4882a593Smuzhiyun 	snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	switch (chip->hardware) {
1011*4882a593Smuzhiyun 	case OPTi9XX_HW_82C924:
1012*4882a593Smuzhiyun 		snd_miro_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
1013*4882a593Smuzhiyun 		snd_miro_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
1014*4882a593Smuzhiyun 		break;
1015*4882a593Smuzhiyun 	case OPTi9XX_HW_82C929:
1016*4882a593Smuzhiyun 		/* untested init commands for OPTi929 */
1017*4882a593Smuzhiyun 		snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c);
1018*4882a593Smuzhiyun 		break;
1019*4882a593Smuzhiyun 	default:
1020*4882a593Smuzhiyun 		snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
1021*4882a593Smuzhiyun 		return -EINVAL;
1022*4882a593Smuzhiyun 	}
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	/* PnP resource says it decodes only 10 bits of address */
1025*4882a593Smuzhiyun 	switch (chip->wss_base & 0x3ff) {
1026*4882a593Smuzhiyun 	case 0x130:
1027*4882a593Smuzhiyun 		chip->wss_base = 0x530;
1028*4882a593Smuzhiyun 		wss_base_bits = 0x00;
1029*4882a593Smuzhiyun 		break;
1030*4882a593Smuzhiyun 	case 0x204:
1031*4882a593Smuzhiyun 		chip->wss_base = 0x604;
1032*4882a593Smuzhiyun 		wss_base_bits = 0x03;
1033*4882a593Smuzhiyun 		break;
1034*4882a593Smuzhiyun 	case 0x280:
1035*4882a593Smuzhiyun 		chip->wss_base = 0xe80;
1036*4882a593Smuzhiyun 		wss_base_bits = 0x01;
1037*4882a593Smuzhiyun 		break;
1038*4882a593Smuzhiyun 	case 0x340:
1039*4882a593Smuzhiyun 		chip->wss_base = 0xf40;
1040*4882a593Smuzhiyun 		wss_base_bits = 0x02;
1041*4882a593Smuzhiyun 		break;
1042*4882a593Smuzhiyun 	default:
1043*4882a593Smuzhiyun 		snd_printk(KERN_ERR "WSS port 0x%lx not valid\n", chip->wss_base);
1044*4882a593Smuzhiyun 		goto __skip_base;
1045*4882a593Smuzhiyun 	}
1046*4882a593Smuzhiyun 	snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun __skip_base:
1049*4882a593Smuzhiyun 	switch (chip->irq) {
1050*4882a593Smuzhiyun 	case 5:
1051*4882a593Smuzhiyun 		irq_bits = 0x05;
1052*4882a593Smuzhiyun 		break;
1053*4882a593Smuzhiyun 	case 7:
1054*4882a593Smuzhiyun 		irq_bits = 0x01;
1055*4882a593Smuzhiyun 		break;
1056*4882a593Smuzhiyun 	case 9:
1057*4882a593Smuzhiyun 		irq_bits = 0x02;
1058*4882a593Smuzhiyun 		break;
1059*4882a593Smuzhiyun 	case 10:
1060*4882a593Smuzhiyun 		irq_bits = 0x03;
1061*4882a593Smuzhiyun 		break;
1062*4882a593Smuzhiyun 	case 11:
1063*4882a593Smuzhiyun 		irq_bits = 0x04;
1064*4882a593Smuzhiyun 		break;
1065*4882a593Smuzhiyun 	default:
1066*4882a593Smuzhiyun 		snd_printk(KERN_ERR "WSS irq # %d not valid\n", chip->irq);
1067*4882a593Smuzhiyun 		goto __skip_resources;
1068*4882a593Smuzhiyun 	}
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	switch (chip->dma1) {
1071*4882a593Smuzhiyun 	case 0:
1072*4882a593Smuzhiyun 		dma_bits = 0x01;
1073*4882a593Smuzhiyun 		break;
1074*4882a593Smuzhiyun 	case 1:
1075*4882a593Smuzhiyun 		dma_bits = 0x02;
1076*4882a593Smuzhiyun 		break;
1077*4882a593Smuzhiyun 	case 3:
1078*4882a593Smuzhiyun 		dma_bits = 0x03;
1079*4882a593Smuzhiyun 		break;
1080*4882a593Smuzhiyun 	default:
1081*4882a593Smuzhiyun 		snd_printk(KERN_ERR "WSS dma1 # %d not valid\n", chip->dma1);
1082*4882a593Smuzhiyun 		goto __skip_resources;
1083*4882a593Smuzhiyun 	}
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	if (chip->dma1 == chip->dma2) {
1086*4882a593Smuzhiyun 		snd_printk(KERN_ERR "don't want to share dmas\n");
1087*4882a593Smuzhiyun 		return -EBUSY;
1088*4882a593Smuzhiyun 	}
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	switch (chip->dma2) {
1091*4882a593Smuzhiyun 	case 0:
1092*4882a593Smuzhiyun 	case 1:
1093*4882a593Smuzhiyun 		break;
1094*4882a593Smuzhiyun 	default:
1095*4882a593Smuzhiyun 		snd_printk(KERN_ERR "WSS dma2 # %d not valid\n", chip->dma2);
1096*4882a593Smuzhiyun 		goto __skip_resources;
1097*4882a593Smuzhiyun 	}
1098*4882a593Smuzhiyun 	dma_bits |= 0x04;
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	spin_lock_irqsave(&chip->lock, flags);
1101*4882a593Smuzhiyun 	outb(irq_bits << 3 | dma_bits, chip->wss_base);
1102*4882a593Smuzhiyun 	spin_unlock_irqrestore(&chip->lock, flags);
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun __skip_resources:
1105*4882a593Smuzhiyun 	if (chip->hardware > OPTi9XX_HW_82C928) {
1106*4882a593Smuzhiyun 		switch (chip->mpu_port) {
1107*4882a593Smuzhiyun 		case 0:
1108*4882a593Smuzhiyun 		case -1:
1109*4882a593Smuzhiyun 			break;
1110*4882a593Smuzhiyun 		case 0x300:
1111*4882a593Smuzhiyun 			mpu_port_bits = 0x03;
1112*4882a593Smuzhiyun 			break;
1113*4882a593Smuzhiyun 		case 0x310:
1114*4882a593Smuzhiyun 			mpu_port_bits = 0x02;
1115*4882a593Smuzhiyun 			break;
1116*4882a593Smuzhiyun 		case 0x320:
1117*4882a593Smuzhiyun 			mpu_port_bits = 0x01;
1118*4882a593Smuzhiyun 			break;
1119*4882a593Smuzhiyun 		case 0x330:
1120*4882a593Smuzhiyun 			mpu_port_bits = 0x00;
1121*4882a593Smuzhiyun 			break;
1122*4882a593Smuzhiyun 		default:
1123*4882a593Smuzhiyun 			snd_printk(KERN_ERR "MPU-401 port 0x%lx not valid\n",
1124*4882a593Smuzhiyun 				   chip->mpu_port);
1125*4882a593Smuzhiyun 			goto __skip_mpu;
1126*4882a593Smuzhiyun 		}
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 		switch (chip->mpu_irq) {
1129*4882a593Smuzhiyun 		case 5:
1130*4882a593Smuzhiyun 			mpu_irq_bits = 0x02;
1131*4882a593Smuzhiyun 			break;
1132*4882a593Smuzhiyun 		case 7:
1133*4882a593Smuzhiyun 			mpu_irq_bits = 0x03;
1134*4882a593Smuzhiyun 			break;
1135*4882a593Smuzhiyun 		case 9:
1136*4882a593Smuzhiyun 			mpu_irq_bits = 0x00;
1137*4882a593Smuzhiyun 			break;
1138*4882a593Smuzhiyun 		case 10:
1139*4882a593Smuzhiyun 			mpu_irq_bits = 0x01;
1140*4882a593Smuzhiyun 			break;
1141*4882a593Smuzhiyun 		default:
1142*4882a593Smuzhiyun 			snd_printk(KERN_ERR "MPU-401 irq # %d not valid\n",
1143*4882a593Smuzhiyun 				   chip->mpu_irq);
1144*4882a593Smuzhiyun 			goto __skip_mpu;
1145*4882a593Smuzhiyun 		}
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun 		snd_miro_write_mask(chip, OPTi9XX_MC_REG(6),
1148*4882a593Smuzhiyun 			(chip->mpu_port <= 0) ? 0x00 :
1149*4882a593Smuzhiyun 				0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3,
1150*4882a593Smuzhiyun 			0xf8);
1151*4882a593Smuzhiyun 	}
1152*4882a593Smuzhiyun __skip_mpu:
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 	return 0;
1155*4882a593Smuzhiyun }
1156*4882a593Smuzhiyun 
snd_miro_opti_check(struct snd_miro * chip)1157*4882a593Smuzhiyun static int snd_miro_opti_check(struct snd_miro *chip)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun 	unsigned char value;
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size,
1162*4882a593Smuzhiyun 					   "OPTi9xx MC");
1163*4882a593Smuzhiyun 	if (chip->res_mc_base == NULL)
1164*4882a593Smuzhiyun 		return -ENOMEM;
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	value = snd_miro_read(chip, OPTi9XX_MC_REG(1));
1167*4882a593Smuzhiyun 	if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1)))
1168*4882a593Smuzhiyun 		if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1)))
1169*4882a593Smuzhiyun 			return 0;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	release_and_free_resource(chip->res_mc_base);
1172*4882a593Smuzhiyun 	chip->res_mc_base = NULL;
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	return -ENODEV;
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun 
snd_card_miro_detect(struct snd_card * card,struct snd_miro * chip)1177*4882a593Smuzhiyun static int snd_card_miro_detect(struct snd_card *card,
1178*4882a593Smuzhiyun 				struct snd_miro *chip)
1179*4882a593Smuzhiyun {
1180*4882a593Smuzhiyun 	int i, err;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) {
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 		if ((err = snd_miro_init(chip, i)) < 0)
1185*4882a593Smuzhiyun 			return err;
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 		err = snd_miro_opti_check(chip);
1188*4882a593Smuzhiyun 		if (err == 0)
1189*4882a593Smuzhiyun 			return 1;
1190*4882a593Smuzhiyun 	}
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	return -ENODEV;
1193*4882a593Smuzhiyun }
1194*4882a593Smuzhiyun 
snd_card_miro_aci_detect(struct snd_card * card,struct snd_miro * miro)1195*4882a593Smuzhiyun static int snd_card_miro_aci_detect(struct snd_card *card,
1196*4882a593Smuzhiyun 				    struct snd_miro *miro)
1197*4882a593Smuzhiyun {
1198*4882a593Smuzhiyun 	unsigned char regval;
1199*4882a593Smuzhiyun 	int i;
1200*4882a593Smuzhiyun 	struct snd_miro_aci *aci = &aci_device;
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	miro->aci = aci;
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	mutex_init(&aci->aci_mutex);
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	/* get ACI port from OPTi9xx MC 4 */
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	regval=inb(miro->mc_base + 4);
1209*4882a593Smuzhiyun 	aci->aci_port = (regval & 0x10) ? 0x344 : 0x354;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	miro->res_aci_port = request_region(aci->aci_port, 3, "miro aci");
1212*4882a593Smuzhiyun 	if (miro->res_aci_port == NULL) {
1213*4882a593Smuzhiyun 		snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n",
1214*4882a593Smuzhiyun 			   aci->aci_port, aci->aci_port+2);
1215*4882a593Smuzhiyun 		return -ENOMEM;
1216*4882a593Smuzhiyun 	}
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun         /* force ACI into a known state */
1219*4882a593Smuzhiyun 	for (i = 0; i < 3; i++)
1220*4882a593Smuzhiyun 		if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) {
1221*4882a593Smuzhiyun 			snd_printk(KERN_ERR "can't force aci into known state.\n");
1222*4882a593Smuzhiyun 			return -ENXIO;
1223*4882a593Smuzhiyun 		}
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 	aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
1226*4882a593Smuzhiyun 	aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1);
1227*4882a593Smuzhiyun 	if (aci->aci_vendor < 0 || aci->aci_product < 0) {
1228*4882a593Smuzhiyun 		snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n",
1229*4882a593Smuzhiyun 			   aci->aci_port);
1230*4882a593Smuzhiyun 		return -ENXIO;
1231*4882a593Smuzhiyun 	}
1232*4882a593Smuzhiyun 
1233*4882a593Smuzhiyun 	aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1);
1234*4882a593Smuzhiyun 	if (aci->aci_version < 0) {
1235*4882a593Smuzhiyun 		snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n",
1236*4882a593Smuzhiyun 			   aci->aci_port);
1237*4882a593Smuzhiyun 		return -ENXIO;
1238*4882a593Smuzhiyun 	}
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun 	if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 ||
1241*4882a593Smuzhiyun 	    snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 ||
1242*4882a593Smuzhiyun 	    snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) {
1243*4882a593Smuzhiyun 		snd_printk(KERN_ERR "can't initialize aci.\n");
1244*4882a593Smuzhiyun 		return -ENXIO;
1245*4882a593Smuzhiyun 	}
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	return 0;
1248*4882a593Smuzhiyun }
1249*4882a593Smuzhiyun 
snd_card_miro_free(struct snd_card * card)1250*4882a593Smuzhiyun static void snd_card_miro_free(struct snd_card *card)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun 	struct snd_miro *miro = card->private_data;
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 	release_and_free_resource(miro->res_aci_port);
1255*4882a593Smuzhiyun 	if (miro->aci)
1256*4882a593Smuzhiyun 		miro->aci->aci_port = 0;
1257*4882a593Smuzhiyun 	release_and_free_resource(miro->res_mc_base);
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun 
snd_miro_probe(struct snd_card * card)1260*4882a593Smuzhiyun static int snd_miro_probe(struct snd_card *card)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun 	int error;
1263*4882a593Smuzhiyun 	struct snd_miro *miro = card->private_data;
1264*4882a593Smuzhiyun 	struct snd_wss *codec;
1265*4882a593Smuzhiyun 	struct snd_rawmidi *rmidi;
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	if (!miro->res_mc_base) {
1268*4882a593Smuzhiyun 		miro->res_mc_base = request_region(miro->mc_base,
1269*4882a593Smuzhiyun 						miro->mc_base_size,
1270*4882a593Smuzhiyun 						"miro (OPTi9xx MC)");
1271*4882a593Smuzhiyun 		if (miro->res_mc_base == NULL) {
1272*4882a593Smuzhiyun 			snd_printk(KERN_ERR "request for OPTI9xx MC failed\n");
1273*4882a593Smuzhiyun 			return -ENOMEM;
1274*4882a593Smuzhiyun 		}
1275*4882a593Smuzhiyun 	}
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	error = snd_card_miro_aci_detect(card, miro);
1278*4882a593Smuzhiyun 	if (error < 0) {
1279*4882a593Smuzhiyun 		snd_printk(KERN_ERR "unable to detect aci chip\n");
1280*4882a593Smuzhiyun 		return -ENODEV;
1281*4882a593Smuzhiyun 	}
1282*4882a593Smuzhiyun 
1283*4882a593Smuzhiyun 	miro->wss_base = port;
1284*4882a593Smuzhiyun 	miro->mpu_port = mpu_port;
1285*4882a593Smuzhiyun 	miro->irq = irq;
1286*4882a593Smuzhiyun 	miro->mpu_irq = mpu_irq;
1287*4882a593Smuzhiyun 	miro->dma1 = dma1;
1288*4882a593Smuzhiyun 	miro->dma2 = dma2;
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 	/* init proc interface */
1291*4882a593Smuzhiyun 	snd_miro_proc_init(card, miro);
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun 	error = snd_miro_configure(miro);
1294*4882a593Smuzhiyun 	if (error)
1295*4882a593Smuzhiyun 		return error;
1296*4882a593Smuzhiyun 
1297*4882a593Smuzhiyun 	error = snd_wss_create(card, miro->wss_base + 4, -1,
1298*4882a593Smuzhiyun 			       miro->irq, miro->dma1, miro->dma2,
1299*4882a593Smuzhiyun 			       WSS_HW_DETECT, 0, &codec);
1300*4882a593Smuzhiyun 	if (error < 0)
1301*4882a593Smuzhiyun 		return error;
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	error = snd_wss_pcm(codec, 0);
1304*4882a593Smuzhiyun 	if (error < 0)
1305*4882a593Smuzhiyun 		return error;
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun 	error = snd_wss_mixer(codec);
1308*4882a593Smuzhiyun 	if (error < 0)
1309*4882a593Smuzhiyun 		return error;
1310*4882a593Smuzhiyun 
1311*4882a593Smuzhiyun 	error = snd_wss_timer(codec, 0);
1312*4882a593Smuzhiyun 	if (error < 0)
1313*4882a593Smuzhiyun 		return error;
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun 	miro->pcm = codec->pcm;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	error = snd_miro_mixer(card, miro);
1318*4882a593Smuzhiyun 	if (error < 0)
1319*4882a593Smuzhiyun 		return error;
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	if (miro->aci->aci_vendor == 'm') {
1322*4882a593Smuzhiyun 		/* It looks like a miro sound card. */
1323*4882a593Smuzhiyun 		switch (miro->aci->aci_product) {
1324*4882a593Smuzhiyun 		case 'A':
1325*4882a593Smuzhiyun 			sprintf(card->shortname,
1326*4882a593Smuzhiyun 				"miroSOUND PCM1 pro / PCM12");
1327*4882a593Smuzhiyun 			break;
1328*4882a593Smuzhiyun 		case 'B':
1329*4882a593Smuzhiyun 			sprintf(card->shortname,
1330*4882a593Smuzhiyun 				"miroSOUND PCM12");
1331*4882a593Smuzhiyun 			break;
1332*4882a593Smuzhiyun 		case 'C':
1333*4882a593Smuzhiyun 			sprintf(card->shortname,
1334*4882a593Smuzhiyun 				"miroSOUND PCM20 radio");
1335*4882a593Smuzhiyun 			break;
1336*4882a593Smuzhiyun 		default:
1337*4882a593Smuzhiyun 			sprintf(card->shortname,
1338*4882a593Smuzhiyun 				"unknown miro");
1339*4882a593Smuzhiyun 			snd_printk(KERN_INFO "unknown miro aci id\n");
1340*4882a593Smuzhiyun 			break;
1341*4882a593Smuzhiyun 		}
1342*4882a593Smuzhiyun 	} else {
1343*4882a593Smuzhiyun 		snd_printk(KERN_INFO "found unsupported aci card\n");
1344*4882a593Smuzhiyun 		sprintf(card->shortname, "unknown Cardinal Technologies");
1345*4882a593Smuzhiyun 	}
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 	strcpy(card->driver, "miro");
1348*4882a593Smuzhiyun 	snprintf(card->longname, sizeof(card->longname),
1349*4882a593Smuzhiyun 		 "%s: OPTi%s, %s at 0x%lx, irq %d, dma %d&%d",
1350*4882a593Smuzhiyun 		 card->shortname, miro->name, codec->pcm->name,
1351*4882a593Smuzhiyun 		 miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2);
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 	if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
1354*4882a593Smuzhiyun 		rmidi = NULL;
1355*4882a593Smuzhiyun 	else {
1356*4882a593Smuzhiyun 		error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
1357*4882a593Smuzhiyun 				mpu_port, 0, miro->mpu_irq, &rmidi);
1358*4882a593Smuzhiyun 		if (error < 0)
1359*4882a593Smuzhiyun 			snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
1360*4882a593Smuzhiyun 				   mpu_port);
1361*4882a593Smuzhiyun 	}
1362*4882a593Smuzhiyun 
1363*4882a593Smuzhiyun 	if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
1364*4882a593Smuzhiyun 		struct snd_opl3 *opl3 = NULL;
1365*4882a593Smuzhiyun 		struct snd_opl4 *opl4;
1366*4882a593Smuzhiyun 
1367*4882a593Smuzhiyun 		if (snd_opl4_create(card, fm_port, fm_port - 8,
1368*4882a593Smuzhiyun 				    2, &opl3, &opl4) < 0)
1369*4882a593Smuzhiyun 			snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n",
1370*4882a593Smuzhiyun 				   fm_port);
1371*4882a593Smuzhiyun 	}
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	error = snd_set_aci_init_values(miro);
1374*4882a593Smuzhiyun 	if (error < 0)
1375*4882a593Smuzhiyun                 return error;
1376*4882a593Smuzhiyun 
1377*4882a593Smuzhiyun 	return snd_card_register(card);
1378*4882a593Smuzhiyun }
1379*4882a593Smuzhiyun 
snd_miro_isa_match(struct device * devptr,unsigned int n)1380*4882a593Smuzhiyun static int snd_miro_isa_match(struct device *devptr, unsigned int n)
1381*4882a593Smuzhiyun {
1382*4882a593Smuzhiyun #ifdef CONFIG_PNP
1383*4882a593Smuzhiyun 	if (snd_miro_pnp_is_probed)
1384*4882a593Smuzhiyun 		return 0;
1385*4882a593Smuzhiyun 	if (isapnp)
1386*4882a593Smuzhiyun 		return 0;
1387*4882a593Smuzhiyun #endif
1388*4882a593Smuzhiyun 	return 1;
1389*4882a593Smuzhiyun }
1390*4882a593Smuzhiyun 
snd_miro_isa_probe(struct device * devptr,unsigned int n)1391*4882a593Smuzhiyun static int snd_miro_isa_probe(struct device *devptr, unsigned int n)
1392*4882a593Smuzhiyun {
1393*4882a593Smuzhiyun 	static const long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
1394*4882a593Smuzhiyun 	static const long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1};
1395*4882a593Smuzhiyun 	static const int possible_irqs[] = {11, 9, 10, 7, -1};
1396*4882a593Smuzhiyun 	static const int possible_mpu_irqs[] = {10, 5, 9, 7, -1};
1397*4882a593Smuzhiyun 	static const int possible_dma1s[] = {3, 1, 0, -1};
1398*4882a593Smuzhiyun 	static const int possible_dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1},
1399*4882a593Smuzhiyun 					   {0, -1} };
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 	int error;
1402*4882a593Smuzhiyun 	struct snd_miro *miro;
1403*4882a593Smuzhiyun 	struct snd_card *card;
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 	error = snd_card_new(devptr, index, id, THIS_MODULE,
1406*4882a593Smuzhiyun 			     sizeof(struct snd_miro), &card);
1407*4882a593Smuzhiyun 	if (error < 0)
1408*4882a593Smuzhiyun 		return error;
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 	card->private_free = snd_card_miro_free;
1411*4882a593Smuzhiyun 	miro = card->private_data;
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	error = snd_card_miro_detect(card, miro);
1414*4882a593Smuzhiyun 	if (error < 0) {
1415*4882a593Smuzhiyun 		snd_card_free(card);
1416*4882a593Smuzhiyun 		snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n");
1417*4882a593Smuzhiyun 		return -ENODEV;
1418*4882a593Smuzhiyun 	}
1419*4882a593Smuzhiyun 
1420*4882a593Smuzhiyun 	if (port == SNDRV_AUTO_PORT) {
1421*4882a593Smuzhiyun 		port = snd_legacy_find_free_ioport(possible_ports, 4);
1422*4882a593Smuzhiyun 		if (port < 0) {
1423*4882a593Smuzhiyun 			snd_card_free(card);
1424*4882a593Smuzhiyun 			snd_printk(KERN_ERR "unable to find a free WSS port\n");
1425*4882a593Smuzhiyun 			return -EBUSY;
1426*4882a593Smuzhiyun 		}
1427*4882a593Smuzhiyun 	}
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 	if (mpu_port == SNDRV_AUTO_PORT) {
1430*4882a593Smuzhiyun 		mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2);
1431*4882a593Smuzhiyun 		if (mpu_port < 0) {
1432*4882a593Smuzhiyun 			snd_card_free(card);
1433*4882a593Smuzhiyun 			snd_printk(KERN_ERR
1434*4882a593Smuzhiyun 				   "unable to find a free MPU401 port\n");
1435*4882a593Smuzhiyun 			return -EBUSY;
1436*4882a593Smuzhiyun 		}
1437*4882a593Smuzhiyun 	}
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 	if (irq == SNDRV_AUTO_IRQ) {
1440*4882a593Smuzhiyun 		irq = snd_legacy_find_free_irq(possible_irqs);
1441*4882a593Smuzhiyun 		if (irq < 0) {
1442*4882a593Smuzhiyun 			snd_card_free(card);
1443*4882a593Smuzhiyun 			snd_printk(KERN_ERR "unable to find a free IRQ\n");
1444*4882a593Smuzhiyun 			return -EBUSY;
1445*4882a593Smuzhiyun 		}
1446*4882a593Smuzhiyun 	}
1447*4882a593Smuzhiyun 	if (mpu_irq == SNDRV_AUTO_IRQ) {
1448*4882a593Smuzhiyun 		mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs);
1449*4882a593Smuzhiyun 		if (mpu_irq < 0) {
1450*4882a593Smuzhiyun 			snd_card_free(card);
1451*4882a593Smuzhiyun 			snd_printk(KERN_ERR
1452*4882a593Smuzhiyun 				   "unable to find a free MPU401 IRQ\n");
1453*4882a593Smuzhiyun 			return -EBUSY;
1454*4882a593Smuzhiyun 		}
1455*4882a593Smuzhiyun 	}
1456*4882a593Smuzhiyun 	if (dma1 == SNDRV_AUTO_DMA) {
1457*4882a593Smuzhiyun 		dma1 = snd_legacy_find_free_dma(possible_dma1s);
1458*4882a593Smuzhiyun 		if (dma1 < 0) {
1459*4882a593Smuzhiyun 			snd_card_free(card);
1460*4882a593Smuzhiyun 			snd_printk(KERN_ERR "unable to find a free DMA1\n");
1461*4882a593Smuzhiyun 			return -EBUSY;
1462*4882a593Smuzhiyun 		}
1463*4882a593Smuzhiyun 	}
1464*4882a593Smuzhiyun 	if (dma2 == SNDRV_AUTO_DMA) {
1465*4882a593Smuzhiyun 		dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]);
1466*4882a593Smuzhiyun 		if (dma2 < 0) {
1467*4882a593Smuzhiyun 			snd_card_free(card);
1468*4882a593Smuzhiyun 			snd_printk(KERN_ERR "unable to find a free DMA2\n");
1469*4882a593Smuzhiyun 			return -EBUSY;
1470*4882a593Smuzhiyun 		}
1471*4882a593Smuzhiyun 	}
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 	error = snd_miro_probe(card);
1474*4882a593Smuzhiyun 	if (error < 0) {
1475*4882a593Smuzhiyun 		snd_card_free(card);
1476*4882a593Smuzhiyun 		return error;
1477*4882a593Smuzhiyun 	}
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun 	dev_set_drvdata(devptr, card);
1480*4882a593Smuzhiyun 	return 0;
1481*4882a593Smuzhiyun }
1482*4882a593Smuzhiyun 
snd_miro_isa_remove(struct device * devptr,unsigned int dev)1483*4882a593Smuzhiyun static int snd_miro_isa_remove(struct device *devptr,
1484*4882a593Smuzhiyun 			       unsigned int dev)
1485*4882a593Smuzhiyun {
1486*4882a593Smuzhiyun 	snd_card_free(dev_get_drvdata(devptr));
1487*4882a593Smuzhiyun 	return 0;
1488*4882a593Smuzhiyun }
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun #define DEV_NAME "miro"
1491*4882a593Smuzhiyun 
1492*4882a593Smuzhiyun static struct isa_driver snd_miro_driver = {
1493*4882a593Smuzhiyun 	.match		= snd_miro_isa_match,
1494*4882a593Smuzhiyun 	.probe		= snd_miro_isa_probe,
1495*4882a593Smuzhiyun 	.remove		= snd_miro_isa_remove,
1496*4882a593Smuzhiyun 	/* FIXME: suspend/resume */
1497*4882a593Smuzhiyun 	.driver		= {
1498*4882a593Smuzhiyun 		.name	= DEV_NAME
1499*4882a593Smuzhiyun 	},
1500*4882a593Smuzhiyun };
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun #ifdef CONFIG_PNP
1503*4882a593Smuzhiyun 
snd_card_miro_pnp(struct snd_miro * chip,struct pnp_card_link * card,const struct pnp_card_device_id * pid)1504*4882a593Smuzhiyun static int snd_card_miro_pnp(struct snd_miro *chip,
1505*4882a593Smuzhiyun 			     struct pnp_card_link *card,
1506*4882a593Smuzhiyun 			     const struct pnp_card_device_id *pid)
1507*4882a593Smuzhiyun {
1508*4882a593Smuzhiyun 	struct pnp_dev *pdev;
1509*4882a593Smuzhiyun 	int err;
1510*4882a593Smuzhiyun 	struct pnp_dev *devmpu;
1511*4882a593Smuzhiyun 	struct pnp_dev *devmc;
1512*4882a593Smuzhiyun 
1513*4882a593Smuzhiyun 	pdev = pnp_request_card_device(card, pid->devs[0].id, NULL);
1514*4882a593Smuzhiyun 	if (pdev == NULL)
1515*4882a593Smuzhiyun 		return -EBUSY;
1516*4882a593Smuzhiyun 
1517*4882a593Smuzhiyun 	devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
1518*4882a593Smuzhiyun 	if (devmpu == NULL)
1519*4882a593Smuzhiyun 		return -EBUSY;
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	devmc = pnp_request_card_device(card, pid->devs[2].id, NULL);
1522*4882a593Smuzhiyun 	if (devmc == NULL)
1523*4882a593Smuzhiyun 		return -EBUSY;
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun 	err = pnp_activate_dev(pdev);
1526*4882a593Smuzhiyun 	if (err < 0) {
1527*4882a593Smuzhiyun 		snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
1528*4882a593Smuzhiyun 		return err;
1529*4882a593Smuzhiyun 	}
1530*4882a593Smuzhiyun 
1531*4882a593Smuzhiyun 	err = pnp_activate_dev(devmc);
1532*4882a593Smuzhiyun 	if (err < 0) {
1533*4882a593Smuzhiyun 		snd_printk(KERN_ERR "MC pnp configure failure: %d\n",
1534*4882a593Smuzhiyun 				    err);
1535*4882a593Smuzhiyun 		return err;
1536*4882a593Smuzhiyun 	}
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	port = pnp_port_start(pdev, 1);
1539*4882a593Smuzhiyun 	fm_port = pnp_port_start(pdev, 2) + 8;
1540*4882a593Smuzhiyun 
1541*4882a593Smuzhiyun 	/*
1542*4882a593Smuzhiyun 	 * The MC(0) is never accessed and the miroSOUND PCM20 card does not
1543*4882a593Smuzhiyun 	 * include it in the PnP resource range. OPTI93x include it.
1544*4882a593Smuzhiyun 	 */
1545*4882a593Smuzhiyun 	chip->mc_base = pnp_port_start(devmc, 0) - 1;
1546*4882a593Smuzhiyun 	chip->mc_base_size = pnp_port_len(devmc, 0) + 1;
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun 	irq = pnp_irq(pdev, 0);
1549*4882a593Smuzhiyun 	dma1 = pnp_dma(pdev, 0);
1550*4882a593Smuzhiyun 	dma2 = pnp_dma(pdev, 1);
1551*4882a593Smuzhiyun 
1552*4882a593Smuzhiyun 	if (mpu_port > 0) {
1553*4882a593Smuzhiyun 		err = pnp_activate_dev(devmpu);
1554*4882a593Smuzhiyun 		if (err < 0) {
1555*4882a593Smuzhiyun 			snd_printk(KERN_ERR "MPU401 pnp configure failure\n");
1556*4882a593Smuzhiyun 			mpu_port = -1;
1557*4882a593Smuzhiyun 			return err;
1558*4882a593Smuzhiyun 		}
1559*4882a593Smuzhiyun 		mpu_port = pnp_port_start(devmpu, 0);
1560*4882a593Smuzhiyun 		mpu_irq = pnp_irq(devmpu, 0);
1561*4882a593Smuzhiyun 	}
1562*4882a593Smuzhiyun 	return 0;
1563*4882a593Smuzhiyun }
1564*4882a593Smuzhiyun 
snd_miro_pnp_probe(struct pnp_card_link * pcard,const struct pnp_card_device_id * pid)1565*4882a593Smuzhiyun static int snd_miro_pnp_probe(struct pnp_card_link *pcard,
1566*4882a593Smuzhiyun 			      const struct pnp_card_device_id *pid)
1567*4882a593Smuzhiyun {
1568*4882a593Smuzhiyun 	struct snd_card *card;
1569*4882a593Smuzhiyun 	int err;
1570*4882a593Smuzhiyun 	struct snd_miro *miro;
1571*4882a593Smuzhiyun 
1572*4882a593Smuzhiyun 	if (snd_miro_pnp_is_probed)
1573*4882a593Smuzhiyun 		return -EBUSY;
1574*4882a593Smuzhiyun 	if (!isapnp)
1575*4882a593Smuzhiyun 		return -ENODEV;
1576*4882a593Smuzhiyun 	err = snd_card_new(&pcard->card->dev, index, id, THIS_MODULE,
1577*4882a593Smuzhiyun 			   sizeof(struct snd_miro), &card);
1578*4882a593Smuzhiyun 	if (err < 0)
1579*4882a593Smuzhiyun 		return err;
1580*4882a593Smuzhiyun 
1581*4882a593Smuzhiyun 	card->private_free = snd_card_miro_free;
1582*4882a593Smuzhiyun 	miro = card->private_data;
1583*4882a593Smuzhiyun 
1584*4882a593Smuzhiyun 	err = snd_card_miro_pnp(miro, pcard, pid);
1585*4882a593Smuzhiyun 	if (err) {
1586*4882a593Smuzhiyun 		snd_card_free(card);
1587*4882a593Smuzhiyun 		return err;
1588*4882a593Smuzhiyun 	}
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 	/* only miroSOUND PCM20 and PCM12 == OPTi924 */
1591*4882a593Smuzhiyun 	err = snd_miro_init(miro, OPTi9XX_HW_82C924);
1592*4882a593Smuzhiyun 	if (err) {
1593*4882a593Smuzhiyun 		snd_card_free(card);
1594*4882a593Smuzhiyun 		return err;
1595*4882a593Smuzhiyun 	}
1596*4882a593Smuzhiyun 
1597*4882a593Smuzhiyun 	err = snd_miro_opti_check(miro);
1598*4882a593Smuzhiyun 	if (err) {
1599*4882a593Smuzhiyun 		snd_printk(KERN_ERR "OPTI chip not found\n");
1600*4882a593Smuzhiyun 		snd_card_free(card);
1601*4882a593Smuzhiyun 		return err;
1602*4882a593Smuzhiyun 	}
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun 	err = snd_miro_probe(card);
1605*4882a593Smuzhiyun 	if (err < 0) {
1606*4882a593Smuzhiyun 		snd_card_free(card);
1607*4882a593Smuzhiyun 		return err;
1608*4882a593Smuzhiyun 	}
1609*4882a593Smuzhiyun 	pnp_set_card_drvdata(pcard, card);
1610*4882a593Smuzhiyun 	snd_miro_pnp_is_probed = 1;
1611*4882a593Smuzhiyun 	return 0;
1612*4882a593Smuzhiyun }
1613*4882a593Smuzhiyun 
snd_miro_pnp_remove(struct pnp_card_link * pcard)1614*4882a593Smuzhiyun static void snd_miro_pnp_remove(struct pnp_card_link *pcard)
1615*4882a593Smuzhiyun {
1616*4882a593Smuzhiyun 	snd_card_free(pnp_get_card_drvdata(pcard));
1617*4882a593Smuzhiyun 	pnp_set_card_drvdata(pcard, NULL);
1618*4882a593Smuzhiyun 	snd_miro_pnp_is_probed = 0;
1619*4882a593Smuzhiyun }
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun static struct pnp_card_driver miro_pnpc_driver = {
1622*4882a593Smuzhiyun 	.flags		= PNP_DRIVER_RES_DISABLE,
1623*4882a593Smuzhiyun 	.name		= "miro",
1624*4882a593Smuzhiyun 	.id_table	= snd_miro_pnpids,
1625*4882a593Smuzhiyun 	.probe		= snd_miro_pnp_probe,
1626*4882a593Smuzhiyun 	.remove		= snd_miro_pnp_remove,
1627*4882a593Smuzhiyun };
1628*4882a593Smuzhiyun #endif
1629*4882a593Smuzhiyun 
alsa_card_miro_init(void)1630*4882a593Smuzhiyun static int __init alsa_card_miro_init(void)
1631*4882a593Smuzhiyun {
1632*4882a593Smuzhiyun #ifdef CONFIG_PNP
1633*4882a593Smuzhiyun 	pnp_register_card_driver(&miro_pnpc_driver);
1634*4882a593Smuzhiyun 	if (snd_miro_pnp_is_probed)
1635*4882a593Smuzhiyun 		return 0;
1636*4882a593Smuzhiyun 	pnp_unregister_card_driver(&miro_pnpc_driver);
1637*4882a593Smuzhiyun #endif
1638*4882a593Smuzhiyun 	return isa_register_driver(&snd_miro_driver, 1);
1639*4882a593Smuzhiyun }
1640*4882a593Smuzhiyun 
alsa_card_miro_exit(void)1641*4882a593Smuzhiyun static void __exit alsa_card_miro_exit(void)
1642*4882a593Smuzhiyun {
1643*4882a593Smuzhiyun 	if (!snd_miro_pnp_is_probed) {
1644*4882a593Smuzhiyun 		isa_unregister_driver(&snd_miro_driver);
1645*4882a593Smuzhiyun 		return;
1646*4882a593Smuzhiyun 	}
1647*4882a593Smuzhiyun #ifdef CONFIG_PNP
1648*4882a593Smuzhiyun 	pnp_unregister_card_driver(&miro_pnpc_driver);
1649*4882a593Smuzhiyun #endif
1650*4882a593Smuzhiyun }
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun module_init(alsa_card_miro_init)
1653*4882a593Smuzhiyun module_exit(alsa_card_miro_exit)
1654