Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | card-opti92x-ad1848.c - driver for OPTi 82c92x based soundcards. | |
3 | Copyright (C) 1998-2000 by Massimo Piccioni <dafastidio@libero.it> | |
4 | ||
5 | Part of this code was developed at the Italian Ministry of Air Defence, | |
6 | Sixth Division (oh, che pace ...), Rome. | |
7 | ||
8 | Thanks to Maria Grazia Pollarini, Salvatore Vassallo. | |
9 | ||
10 | This program is free software; you can redistribute it and/or modify | |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 2 of the License, or | |
13 | (at your option) any later version. | |
14 | ||
15 | This program is distributed in the hope that it will be useful, | |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
21 | along with this program; if not, write to the Free Software | |
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 | */ | |
24 | ||
25 | ||
1da177e4 | 26 | #include <linux/init.h> |
99a0b768 | 27 | #include <linux/err.h> |
5e24c1c1 | 28 | #include <linux/isa.h> |
99a0b768 | 29 | #include <linux/delay.h> |
1da177e4 LT |
30 | #include <linux/slab.h> |
31 | #include <linux/pnp.h> | |
32 | #include <linux/moduleparam.h> | |
99a0b768 TI |
33 | #include <asm/io.h> |
34 | #include <asm/dma.h> | |
1da177e4 LT |
35 | #include <sound/core.h> |
36 | #ifdef CS4231 | |
37 | #include <sound/cs4231.h> | |
38 | #else | |
39 | #ifndef OPTi93X | |
40 | #include <sound/ad1848.h> | |
41 | #else | |
42 | #include <sound/control.h> | |
43 | #include <sound/pcm.h> | |
44 | #endif /* OPTi93X */ | |
45 | #endif /* CS4231 */ | |
46 | #include <sound/mpu401.h> | |
47 | #include <sound/opl3.h> | |
48 | #ifndef OPTi93X | |
49 | #include <sound/opl4.h> | |
50 | #endif | |
51 | #define SNDRV_LEGACY_FIND_FREE_IRQ | |
52 | #define SNDRV_LEGACY_FIND_FREE_DMA | |
53 | #include <sound/initval.h> | |
54 | ||
55 | MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); | |
56 | MODULE_LICENSE("GPL"); | |
57 | #ifdef OPTi93X | |
58 | MODULE_DESCRIPTION("OPTi93X"); | |
59 | MODULE_SUPPORTED_DEVICE("{{OPTi,82C931/3}}"); | |
60 | #else /* OPTi93X */ | |
61 | #ifdef CS4231 | |
62 | MODULE_DESCRIPTION("OPTi92X - CS4231"); | |
63 | MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (CS4231)}," | |
64 | "{OPTi,82C925 (CS4231)}}"); | |
65 | #else /* CS4231 */ | |
66 | MODULE_DESCRIPTION("OPTi92X - AD1848"); | |
67 | MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (AD1848)}," | |
68 | "{OPTi,82C925 (AD1848)}," | |
69 | "{OAK,Mozart}}"); | |
70 | #endif /* CS4231 */ | |
71 | #endif /* OPTi93X */ | |
72 | ||
73 | static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ | |
74 | static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ | |
75 | //static int enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */ | |
76 | static int isapnp = 1; /* Enable ISA PnP detection */ | |
77 | static long port = SNDRV_DEFAULT_PORT1; /* 0x530,0xe80,0xf40,0x604 */ | |
78 | static long mpu_port = SNDRV_DEFAULT_PORT1; /* 0x300,0x310,0x320,0x330 */ | |
79 | static long fm_port = SNDRV_DEFAULT_PORT1; /* 0x388 */ | |
80 | static int irq = SNDRV_DEFAULT_IRQ1; /* 5,7,9,10,11 */ | |
81 | static int mpu_irq = SNDRV_DEFAULT_IRQ1; /* 5,7,9,10 */ | |
82 | static int dma1 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ | |
83 | #if defined(CS4231) || defined(OPTi93X) | |
84 | static int dma2 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ | |
85 | #endif /* CS4231 || OPTi93X */ | |
86 | ||
87 | module_param(index, int, 0444); | |
88 | MODULE_PARM_DESC(index, "Index value for opti9xx based soundcard."); | |
89 | module_param(id, charp, 0444); | |
90 | MODULE_PARM_DESC(id, "ID string for opti9xx based soundcard."); | |
91 | //module_param(enable, bool, 0444); | |
92 | //MODULE_PARM_DESC(enable, "Enable opti9xx soundcard."); | |
93 | module_param(isapnp, bool, 0444); | |
94 | MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard."); | |
95 | module_param(port, long, 0444); | |
96 | MODULE_PARM_DESC(port, "WSS port # for opti9xx driver."); | |
97 | module_param(mpu_port, long, 0444); | |
98 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for opti9xx driver."); | |
99 | module_param(fm_port, long, 0444); | |
100 | MODULE_PARM_DESC(fm_port, "FM port # for opti9xx driver."); | |
101 | module_param(irq, int, 0444); | |
102 | MODULE_PARM_DESC(irq, "WSS irq # for opti9xx driver."); | |
103 | module_param(mpu_irq, int, 0444); | |
104 | MODULE_PARM_DESC(mpu_irq, "MPU-401 irq # for opti9xx driver."); | |
105 | module_param(dma1, int, 0444); | |
106 | MODULE_PARM_DESC(dma1, "1st dma # for opti9xx driver."); | |
107 | #if defined(CS4231) || defined(OPTi93X) | |
108 | module_param(dma2, int, 0444); | |
109 | MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver."); | |
110 | #endif /* CS4231 || OPTi93X */ | |
111 | ||
112 | #define OPTi9XX_HW_DETECT 0 | |
113 | #define OPTi9XX_HW_82C928 1 | |
114 | #define OPTi9XX_HW_82C929 2 | |
115 | #define OPTi9XX_HW_82C924 3 | |
116 | #define OPTi9XX_HW_82C925 4 | |
117 | #define OPTi9XX_HW_82C930 5 | |
118 | #define OPTi9XX_HW_82C931 6 | |
119 | #define OPTi9XX_HW_82C933 7 | |
120 | #define OPTi9XX_HW_LAST OPTi9XX_HW_82C933 | |
121 | ||
122 | #define OPTi9XX_MC_REG(n) n | |
123 | ||
1da177e4 LT |
124 | #ifdef OPTi93X |
125 | ||
126 | #define OPTi93X_INDEX 0x00 | |
127 | #define OPTi93X_DATA 0x01 | |
128 | #define OPTi93X_STATUS 0x02 | |
129 | #define OPTi93X_DDATA 0x03 | |
130 | #define OPTi93X_PORT(chip, r) ((chip)->port + OPTi93X_##r) | |
131 | ||
132 | #define OPTi93X_MIXOUT_LEFT 0x00 | |
133 | #define OPTi93X_MIXOUT_RIGHT 0x01 | |
134 | #define OPTi93X_CD_LEFT_INPUT 0x02 | |
135 | #define OPTi93X_CD_RIGHT_INPUT 0x03 | |
136 | #define OPTi930_AUX_LEFT_INPUT 0x04 | |
137 | #define OPTi930_AUX_RIGHT_INPUT 0x05 | |
138 | #define OPTi931_FM_LEFT_INPUT 0x04 | |
139 | #define OPTi931_FM_RIGHT_INPUT 0x05 | |
140 | #define OPTi93X_DAC_LEFT 0x06 | |
141 | #define OPTi93X_DAC_RIGHT 0x07 | |
142 | #define OPTi93X_PLAY_FORMAT 0x08 | |
143 | #define OPTi93X_IFACE_CONF 0x09 | |
144 | #define OPTi93X_PIN_CTRL 0x0a | |
145 | #define OPTi93X_ERR_INIT 0x0b | |
146 | #define OPTi93X_ID 0x0c | |
147 | #define OPTi93X_PLAY_UPR_CNT 0x0e | |
148 | #define OPTi93X_PLAY_LWR_CNT 0x0f | |
149 | #define OPTi931_AUX_LEFT_INPUT 0x10 | |
150 | #define OPTi931_AUX_RIGHT_INPUT 0x11 | |
151 | #define OPTi93X_LINE_LEFT_INPUT 0x12 | |
152 | #define OPTi93X_LINE_RIGHT_INPUT 0x13 | |
153 | #define OPTi93X_MIC_LEFT_INPUT 0x14 | |
154 | #define OPTi93X_MIC_RIGHT_INPUT 0x15 | |
155 | #define OPTi93X_OUT_LEFT 0x16 | |
156 | #define OPTi93X_OUT_RIGHT 0x17 | |
157 | #define OPTi93X_CAPT_FORMAT 0x1c | |
158 | #define OPTi93X_CAPT_UPR_CNT 0x1e | |
159 | #define OPTi93X_CAPT_LWR_CNT 0x1f | |
160 | ||
161 | #define OPTi93X_TRD 0x20 | |
162 | #define OPTi93X_MCE 0x40 | |
163 | #define OPTi93X_INIT 0x80 | |
164 | ||
165 | #define OPTi93X_MIXOUT_MIC_GAIN 0x20 | |
166 | #define OPTi93X_MIXOUT_LINE 0x00 | |
167 | #define OPTi93X_MIXOUT_CD 0x40 | |
168 | #define OPTi93X_MIXOUT_MIC 0x80 | |
169 | #define OPTi93X_MIXOUT_MIXER 0xc0 | |
170 | ||
171 | #define OPTi93X_STEREO 0x10 | |
172 | #define OPTi93X_LINEAR_8 0x00 | |
173 | #define OPTi93X_ULAW_8 0x20 | |
174 | #define OPTi93X_LINEAR_16_LIT 0x40 | |
175 | #define OPTi93X_ALAW_8 0x60 | |
176 | #define OPTi93X_ADPCM_16 0xa0 | |
177 | #define OPTi93X_LINEAR_16_BIG 0xc0 | |
178 | ||
179 | #define OPTi93X_CAPTURE_PIO 0x80 | |
180 | #define OPTi93X_PLAYBACK_PIO 0x40 | |
181 | #define OPTi93X_AUTOCALIB 0x08 | |
182 | #define OPTi93X_SINGLE_DMA 0x04 | |
183 | #define OPTi93X_CAPTURE_ENABLE 0x02 | |
184 | #define OPTi93X_PLAYBACK_ENABLE 0x01 | |
185 | ||
186 | #define OPTi93X_IRQ_ENABLE 0x02 | |
187 | ||
188 | #define OPTi93X_DMA_REQUEST 0x10 | |
189 | #define OPTi93X_CALIB_IN_PROGRESS 0x20 | |
190 | ||
191 | #define OPTi93X_IRQ_PLAYBACK 0x04 | |
192 | #define OPTi93X_IRQ_CAPTURE 0x08 | |
193 | ||
194 | ||
346c7a68 | 195 | struct snd_opti93x { |
1da177e4 LT |
196 | unsigned long port; |
197 | struct resource *res_port; | |
198 | int irq; | |
199 | int dma1; | |
200 | int dma2; | |
201 | ||
346c7a68 | 202 | struct snd_opti9xx *chip; |
1da177e4 LT |
203 | unsigned short hardware; |
204 | unsigned char image[32]; | |
205 | ||
206 | unsigned char mce_bit; | |
207 | unsigned short mode; | |
208 | int mute; | |
209 | ||
210 | spinlock_t lock; | |
211 | ||
346c7a68 TI |
212 | struct snd_card *card; |
213 | struct snd_pcm *pcm; | |
214 | struct snd_pcm_substream *playback_substream; | |
215 | struct snd_pcm_substream *capture_substream; | |
1da177e4 LT |
216 | unsigned int p_dma_size; |
217 | unsigned int c_dma_size; | |
218 | }; | |
219 | ||
220 | #define OPTi93X_MODE_NONE 0x00 | |
221 | #define OPTi93X_MODE_PLAY 0x01 | |
222 | #define OPTi93X_MODE_CAPTURE 0x02 | |
223 | #define OPTi93X_MODE_OPEN (OPTi93X_MODE_PLAY | OPTi93X_MODE_CAPTURE) | |
224 | ||
225 | #endif /* OPTi93X */ | |
226 | ||
346c7a68 | 227 | struct snd_opti9xx { |
1da177e4 LT |
228 | unsigned short hardware; |
229 | unsigned char password; | |
230 | char name[7]; | |
231 | ||
232 | unsigned long mc_base; | |
233 | struct resource *res_mc_base; | |
234 | unsigned long mc_base_size; | |
235 | #ifdef OPTi93X | |
236 | unsigned long mc_indir_index; | |
237 | #endif /* OPTi93X */ | |
238 | unsigned long pwd_reg; | |
239 | ||
240 | spinlock_t lock; | |
241 | ||
242 | long wss_base; | |
243 | int irq; | |
244 | int dma1; | |
245 | #if defined(CS4231) || defined(OPTi93X) | |
246 | int dma2; | |
247 | #endif /* CS4231 || OPTi93X */ | |
248 | ||
249 | long fm_port; | |
250 | ||
251 | long mpu_port; | |
252 | int mpu_irq; | |
253 | ||
254 | #ifdef CONFIG_PNP | |
255 | struct pnp_dev *dev; | |
256 | struct pnp_dev *devmpu; | |
257 | #endif /* CONFIG_PNP */ | |
258 | }; | |
259 | ||
99a0b768 | 260 | static int snd_opti9xx_pnp_is_probed; |
1da177e4 LT |
261 | |
262 | #ifdef CONFIG_PNP | |
263 | ||
264 | static struct pnp_card_device_id snd_opti9xx_pnpids[] = { | |
265 | #ifndef OPTi93X | |
266 | /* OPTi 82C924 */ | |
267 | { .id = "OPT0924", .devs = { { "OPT0000" }, { "OPT0002" } }, .driver_data = 0x0924 }, | |
268 | /* OPTi 82C925 */ | |
269 | { .id = "OPT0925", .devs = { { "OPT9250" }, { "OPT0002" } }, .driver_data = 0x0925 }, | |
270 | #else | |
271 | /* OPTi 82C931/3 */ | |
272 | { .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } }, .driver_data = 0x0931 }, | |
273 | #endif /* OPTi93X */ | |
274 | { .id = "" } | |
275 | }; | |
276 | ||
277 | MODULE_DEVICE_TABLE(pnp_card, snd_opti9xx_pnpids); | |
278 | ||
279 | #endif /* CONFIG_PNP */ | |
280 | ||
281 | #ifdef OPTi93X | |
83c51c0a | 282 | #define DEV_NAME "opti93x" |
1da177e4 | 283 | #else |
83c51c0a RH |
284 | #define DEV_NAME "opti92x" |
285 | #endif | |
1da177e4 LT |
286 | |
287 | static char * snd_opti9xx_names[] = { | |
288 | "unkown", | |
289 | "82C928", "82C929", | |
290 | "82C924", "82C925", | |
291 | "82C930", "82C931", "82C933" | |
292 | }; | |
293 | ||
294 | ||
5e24c1c1 | 295 | static long __devinit snd_legacy_find_free_ioport(long *port_table, long size) |
1da177e4 LT |
296 | { |
297 | while (*port_table != -1) { | |
b1d5776d TI |
298 | if (request_region(*port_table, size, "ALSA test")) { |
299 | release_region(*port_table, size); | |
1da177e4 LT |
300 | return *port_table; |
301 | } | |
302 | port_table++; | |
303 | } | |
304 | return -1; | |
305 | } | |
306 | ||
5e24c1c1 TI |
307 | static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, |
308 | unsigned short hardware) | |
1da177e4 LT |
309 | { |
310 | static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2}; | |
311 | ||
312 | chip->hardware = hardware; | |
313 | strcpy(chip->name, snd_opti9xx_names[hardware]); | |
314 | ||
315 | chip->mc_base_size = opti9xx_mc_size[hardware]; | |
316 | ||
317 | spin_lock_init(&chip->lock); | |
318 | ||
319 | chip->wss_base = -1; | |
320 | chip->irq = -1; | |
321 | chip->dma1 = -1; | |
322 | #if defined(CS4231) || defined (OPTi93X) | |
323 | chip->dma2 = -1; | |
324 | #endif /* CS4231 || OPTi93X */ | |
325 | chip->fm_port = -1; | |
326 | chip->mpu_port = -1; | |
327 | chip->mpu_irq = -1; | |
328 | ||
329 | switch (hardware) { | |
330 | #ifndef OPTi93X | |
331 | case OPTi9XX_HW_82C928: | |
332 | case OPTi9XX_HW_82C929: | |
333 | chip->mc_base = 0xf8c; | |
334 | chip->password = (hardware == OPTi9XX_HW_82C928) ? 0xe2 : 0xe3; | |
335 | chip->pwd_reg = 3; | |
336 | break; | |
337 | ||
338 | case OPTi9XX_HW_82C924: | |
339 | case OPTi9XX_HW_82C925: | |
340 | chip->mc_base = 0xf8c; | |
341 | chip->password = 0xe5; | |
342 | chip->pwd_reg = 3; | |
343 | break; | |
344 | #else /* OPTi93X */ | |
345 | ||
346 | case OPTi9XX_HW_82C930: | |
347 | case OPTi9XX_HW_82C931: | |
348 | case OPTi9XX_HW_82C933: | |
349 | chip->mc_base = (hardware == OPTi9XX_HW_82C930) ? 0xf8f : 0xf8d; | |
350 | chip->mc_indir_index = 0xe0e; | |
351 | chip->password = 0xe4; | |
352 | chip->pwd_reg = 0; | |
353 | break; | |
354 | #endif /* OPTi93X */ | |
355 | ||
356 | default: | |
357 | snd_printk("chip %d not supported\n", hardware); | |
358 | return -ENODEV; | |
359 | } | |
360 | return 0; | |
361 | } | |
362 | ||
346c7a68 | 363 | static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip, |
1da177e4 LT |
364 | unsigned char reg) |
365 | { | |
366 | unsigned long flags; | |
367 | unsigned char retval = 0xff; | |
368 | ||
369 | spin_lock_irqsave(&chip->lock, flags); | |
370 | outb(chip->password, chip->mc_base + chip->pwd_reg); | |
371 | ||
372 | switch (chip->hardware) { | |
373 | #ifndef OPTi93X | |
374 | case OPTi9XX_HW_82C924: | |
375 | case OPTi9XX_HW_82C925: | |
376 | if (reg > 7) { | |
377 | outb(reg, chip->mc_base + 8); | |
378 | outb(chip->password, chip->mc_base + chip->pwd_reg); | |
379 | retval = inb(chip->mc_base + 9); | |
380 | break; | |
381 | } | |
382 | ||
383 | case OPTi9XX_HW_82C928: | |
384 | case OPTi9XX_HW_82C929: | |
385 | retval = inb(chip->mc_base + reg); | |
386 | break; | |
387 | #else /* OPTi93X */ | |
388 | ||
389 | case OPTi9XX_HW_82C930: | |
390 | case OPTi9XX_HW_82C931: | |
391 | case OPTi9XX_HW_82C933: | |
392 | outb(reg, chip->mc_indir_index); | |
393 | outb(chip->password, chip->mc_base + chip->pwd_reg); | |
394 | retval = inb(chip->mc_indir_index + 1); | |
395 | break; | |
396 | #endif /* OPTi93X */ | |
397 | ||
398 | default: | |
399 | snd_printk("chip %d not supported\n", chip->hardware); | |
400 | } | |
401 | ||
402 | spin_unlock_irqrestore(&chip->lock, flags); | |
403 | return retval; | |
404 | } | |
405 | ||
346c7a68 | 406 | static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, |
1da177e4 LT |
407 | unsigned char value) |
408 | { | |
409 | unsigned long flags; | |
410 | ||
411 | spin_lock_irqsave(&chip->lock, flags); | |
412 | outb(chip->password, chip->mc_base + chip->pwd_reg); | |
413 | ||
414 | switch (chip->hardware) { | |
415 | #ifndef OPTi93X | |
416 | case OPTi9XX_HW_82C924: | |
417 | case OPTi9XX_HW_82C925: | |
418 | if (reg > 7) { | |
419 | outb(reg, chip->mc_base + 8); | |
420 | outb(chip->password, chip->mc_base + chip->pwd_reg); | |
421 | outb(value, chip->mc_base + 9); | |
422 | break; | |
423 | } | |
424 | ||
425 | case OPTi9XX_HW_82C928: | |
426 | case OPTi9XX_HW_82C929: | |
427 | outb(value, chip->mc_base + reg); | |
428 | break; | |
429 | #else /* OPTi93X */ | |
430 | ||
431 | case OPTi9XX_HW_82C930: | |
432 | case OPTi9XX_HW_82C931: | |
433 | case OPTi9XX_HW_82C933: | |
434 | outb(reg, chip->mc_indir_index); | |
435 | outb(chip->password, chip->mc_base + chip->pwd_reg); | |
436 | outb(value, chip->mc_indir_index + 1); | |
437 | break; | |
438 | #endif /* OPTi93X */ | |
439 | ||
440 | default: | |
441 | snd_printk("chip %d not supported\n", chip->hardware); | |
442 | } | |
443 | ||
444 | spin_unlock_irqrestore(&chip->lock, flags); | |
445 | } | |
446 | ||
447 | ||
448 | #define snd_opti9xx_write_mask(chip, reg, value, mask) \ | |
449 | snd_opti9xx_write(chip, reg, \ | |
450 | (snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask))) | |
451 | ||
452 | ||
5e24c1c1 | 453 | static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) |
1da177e4 LT |
454 | { |
455 | unsigned char wss_base_bits; | |
456 | unsigned char irq_bits; | |
457 | unsigned char dma_bits; | |
458 | unsigned char mpu_port_bits = 0; | |
459 | unsigned char mpu_irq_bits; | |
460 | ||
461 | switch (chip->hardware) { | |
462 | #ifndef OPTi93X | |
463 | case OPTi9XX_HW_82C924: | |
464 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0xf0, 0xfc); | |
465 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02); | |
466 | ||
467 | case OPTi9XX_HW_82C925: | |
468 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); | |
469 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20); | |
470 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff); | |
471 | #ifdef CS4231 | |
472 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); | |
473 | #else | |
474 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02); | |
475 | #endif /* CS4231 */ | |
476 | break; | |
477 | ||
478 | case OPTi9XX_HW_82C928: | |
479 | case OPTi9XX_HW_82C929: | |
480 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); | |
481 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20); | |
482 | /* | |
483 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xa2, 0xae); | |
484 | */ | |
485 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c); | |
486 | #ifdef CS4231 | |
487 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); | |
488 | #else | |
489 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02); | |
490 | #endif /* CS4231 */ | |
491 | break; | |
492 | ||
493 | #else /* OPTi93X */ | |
1da177e4 LT |
494 | case OPTi9XX_HW_82C931: |
495 | case OPTi9XX_HW_82C933: | |
3ae5f36a | 496 | /* |
f81b953d KH |
497 | * The BTC 1817DW has QS1000 wavetable which is connected |
498 | * to the serial digital input of the OPTI931. | |
499 | */ | |
500 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(21), 0x82, 0xff); | |
501 | /* | |
502 | * This bit sets OPTI931 to automaticaly select FM | |
503 | * or digital input signal. | |
504 | */ | |
505 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01); | |
3ae5f36a KH |
506 | case OPTi9XX_HW_82C930: /* FALL THROUGH */ |
507 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03); | |
508 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff); | |
509 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 | | |
510 | (chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04), | |
511 | 0x34); | |
512 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf); | |
1da177e4 LT |
513 | break; |
514 | #endif /* OPTi93X */ | |
515 | ||
516 | default: | |
517 | snd_printk("chip %d not supported\n", chip->hardware); | |
518 | return -EINVAL; | |
519 | } | |
520 | ||
521 | switch (chip->wss_base) { | |
522 | case 0x530: | |
523 | wss_base_bits = 0x00; | |
524 | break; | |
525 | case 0x604: | |
526 | wss_base_bits = 0x03; | |
527 | break; | |
528 | case 0xe80: | |
529 | wss_base_bits = 0x01; | |
530 | break; | |
531 | case 0xf40: | |
532 | wss_base_bits = 0x02; | |
533 | break; | |
534 | default: | |
535 | snd_printk("WSS port 0x%lx not valid\n", chip->wss_base); | |
536 | goto __skip_base; | |
537 | } | |
538 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30); | |
539 | ||
540 | __skip_base: | |
541 | switch (chip->irq) { | |
542 | //#ifdef OPTi93X | |
543 | case 5: | |
544 | irq_bits = 0x05; | |
545 | break; | |
546 | //#endif /* OPTi93X */ | |
547 | case 7: | |
548 | irq_bits = 0x01; | |
549 | break; | |
550 | case 9: | |
551 | irq_bits = 0x02; | |
552 | break; | |
553 | case 10: | |
554 | irq_bits = 0x03; | |
555 | break; | |
556 | case 11: | |
557 | irq_bits = 0x04; | |
558 | break; | |
559 | default: | |
560 | snd_printk("WSS irq # %d not valid\n", chip->irq); | |
561 | goto __skip_resources; | |
562 | } | |
563 | ||
564 | switch (chip->dma1) { | |
565 | case 0: | |
566 | dma_bits = 0x01; | |
567 | break; | |
568 | case 1: | |
569 | dma_bits = 0x02; | |
570 | break; | |
571 | case 3: | |
572 | dma_bits = 0x03; | |
573 | break; | |
574 | default: | |
575 | snd_printk("WSS dma1 # %d not valid\n", chip->dma1); | |
576 | goto __skip_resources; | |
577 | } | |
578 | ||
579 | #if defined(CS4231) || defined(OPTi93X) | |
580 | if (chip->dma1 == chip->dma2) { | |
581 | snd_printk("don't want to share dmas\n"); | |
582 | return -EBUSY; | |
583 | } | |
584 | ||
585 | switch (chip->dma2) { | |
586 | case 0: | |
587 | case 1: | |
588 | break; | |
589 | default: | |
590 | snd_printk("WSS dma2 # %d not valid\n", chip->dma2); | |
591 | goto __skip_resources; | |
592 | } | |
593 | dma_bits |= 0x04; | |
594 | #endif /* CS4231 || OPTi93X */ | |
595 | ||
596 | #ifndef OPTi93X | |
597 | outb(irq_bits << 3 | dma_bits, chip->wss_base); | |
598 | #else /* OPTi93X */ | |
599 | snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits)); | |
600 | #endif /* OPTi93X */ | |
601 | ||
602 | __skip_resources: | |
603 | if (chip->hardware > OPTi9XX_HW_82C928) { | |
604 | switch (chip->mpu_port) { | |
605 | case 0: | |
606 | case -1: | |
607 | break; | |
608 | case 0x300: | |
609 | mpu_port_bits = 0x03; | |
610 | break; | |
611 | case 0x310: | |
612 | mpu_port_bits = 0x02; | |
613 | break; | |
614 | case 0x320: | |
615 | mpu_port_bits = 0x01; | |
616 | break; | |
617 | case 0x330: | |
618 | mpu_port_bits = 0x00; | |
619 | break; | |
620 | default: | |
621 | snd_printk("MPU-401 port 0x%lx not valid\n", | |
622 | chip->mpu_port); | |
623 | goto __skip_mpu; | |
624 | } | |
625 | ||
626 | switch (chip->mpu_irq) { | |
627 | case 5: | |
628 | mpu_irq_bits = 0x02; | |
629 | break; | |
630 | case 7: | |
631 | mpu_irq_bits = 0x03; | |
632 | break; | |
633 | case 9: | |
634 | mpu_irq_bits = 0x00; | |
635 | break; | |
636 | case 10: | |
637 | mpu_irq_bits = 0x01; | |
638 | break; | |
639 | default: | |
640 | snd_printk("MPU-401 irq # %d not valid\n", | |
641 | chip->mpu_irq); | |
642 | goto __skip_mpu; | |
643 | } | |
644 | ||
645 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), | |
646 | (chip->mpu_port <= 0) ? 0x00 : | |
647 | 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3, | |
648 | 0xf8); | |
649 | } | |
650 | __skip_mpu: | |
651 | ||
652 | return 0; | |
653 | } | |
654 | ||
655 | #ifdef OPTi93X | |
656 | ||
657 | static unsigned char snd_opti93x_default_image[32] = | |
658 | { | |
659 | 0x00, /* 00/00 - l_mixout_outctrl */ | |
660 | 0x00, /* 01/01 - r_mixout_outctrl */ | |
661 | 0x88, /* 02/02 - l_cd_inctrl */ | |
662 | 0x88, /* 03/03 - r_cd_inctrl */ | |
663 | 0x88, /* 04/04 - l_a1/fm_inctrl */ | |
664 | 0x88, /* 05/05 - r_a1/fm_inctrl */ | |
665 | 0x80, /* 06/06 - l_dac_inctrl */ | |
666 | 0x80, /* 07/07 - r_dac_inctrl */ | |
667 | 0x00, /* 08/08 - ply_dataform_reg */ | |
668 | 0x00, /* 09/09 - if_conf */ | |
669 | 0x00, /* 0a/10 - pin_ctrl */ | |
670 | 0x00, /* 0b/11 - err_init_reg */ | |
671 | 0x0a, /* 0c/12 - id_reg */ | |
672 | 0x00, /* 0d/13 - reserved */ | |
673 | 0x00, /* 0e/14 - ply_upcount_reg */ | |
674 | 0x00, /* 0f/15 - ply_lowcount_reg */ | |
675 | 0x88, /* 10/16 - reserved/l_a1_inctrl */ | |
676 | 0x88, /* 11/17 - reserved/r_a1_inctrl */ | |
677 | 0x88, /* 12/18 - l_line_inctrl */ | |
678 | 0x88, /* 13/19 - r_line_inctrl */ | |
679 | 0x88, /* 14/20 - l_mic_inctrl */ | |
680 | 0x88, /* 15/21 - r_mic_inctrl */ | |
681 | 0x80, /* 16/22 - l_out_outctrl */ | |
682 | 0x80, /* 17/23 - r_out_outctrl */ | |
683 | 0x00, /* 18/24 - reserved */ | |
684 | 0x00, /* 19/25 - reserved */ | |
685 | 0x00, /* 1a/26 - reserved */ | |
686 | 0x00, /* 1b/27 - reserved */ | |
687 | 0x00, /* 1c/28 - cap_dataform_reg */ | |
688 | 0x00, /* 1d/29 - reserved */ | |
689 | 0x00, /* 1e/30 - cap_upcount_reg */ | |
690 | 0x00 /* 1f/31 - cap_lowcount_reg */ | |
691 | }; | |
692 | ||
693 | ||
346c7a68 | 694 | static int snd_opti93x_busy_wait(struct snd_opti93x *chip) |
1da177e4 LT |
695 | { |
696 | int timeout; | |
697 | ||
698 | for (timeout = 250; timeout-- > 0; udelay(10)) | |
699 | if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_INIT)) | |
700 | return 0; | |
701 | ||
702 | snd_printk("chip still busy.\n"); | |
703 | return -EBUSY; | |
704 | } | |
705 | ||
346c7a68 | 706 | static unsigned char snd_opti93x_in(struct snd_opti93x *chip, unsigned char reg) |
1da177e4 LT |
707 | { |
708 | snd_opti93x_busy_wait(chip); | |
709 | outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); | |
710 | return inb(OPTi93X_PORT(chip, DATA)); | |
711 | } | |
712 | ||
346c7a68 | 713 | static void snd_opti93x_out(struct snd_opti93x *chip, unsigned char reg, |
1da177e4 LT |
714 | unsigned char value) |
715 | { | |
716 | snd_opti93x_busy_wait(chip); | |
717 | outb(chip->mce_bit | (reg & 0x1f), OPTi93X_PORT(chip, INDEX)); | |
718 | outb(value, OPTi93X_PORT(chip, DATA)); | |
719 | } | |
720 | ||
346c7a68 | 721 | static void snd_opti93x_out_image(struct snd_opti93x *chip, unsigned char reg, |
1da177e4 LT |
722 | unsigned char value) |
723 | { | |
724 | snd_opti93x_out(chip, reg, chip->image[reg] = value); | |
725 | } | |
726 | ||
346c7a68 | 727 | static void snd_opti93x_out_mask(struct snd_opti93x *chip, unsigned char reg, |
1da177e4 LT |
728 | unsigned char mask, unsigned char value) |
729 | { | |
730 | snd_opti93x_out_image(chip, reg, | |
731 | (chip->image[reg] & ~mask) | (value & mask)); | |
732 | } | |
733 | ||
734 | ||
346c7a68 | 735 | static void snd_opti93x_mce_up(struct snd_opti93x *chip) |
1da177e4 LT |
736 | { |
737 | snd_opti93x_busy_wait(chip); | |
738 | ||
739 | chip->mce_bit = OPTi93X_MCE; | |
740 | if (!(inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE)) | |
741 | outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX)); | |
742 | } | |
743 | ||
346c7a68 | 744 | static void snd_opti93x_mce_down(struct snd_opti93x *chip) |
1da177e4 LT |
745 | { |
746 | snd_opti93x_busy_wait(chip); | |
747 | ||
748 | chip->mce_bit = 0; | |
749 | if (inb(OPTi93X_PORT(chip, INDEX)) & OPTi93X_MCE) | |
750 | outb(chip->mce_bit, OPTi93X_PORT(chip, INDEX)); | |
751 | } | |
752 | ||
753 | #define snd_opti93x_mute_reg(chip, reg, mute) \ | |
754 | snd_opti93x_out(chip, reg, mute ? 0x80 : chip->image[reg]); | |
755 | ||
346c7a68 | 756 | static void snd_opti93x_mute(struct snd_opti93x *chip, int mute) |
1da177e4 LT |
757 | { |
758 | mute = mute ? 1 : 0; | |
759 | if (chip->mute == mute) | |
760 | return; | |
761 | ||
762 | chip->mute = mute; | |
763 | ||
764 | snd_opti93x_mute_reg(chip, OPTi93X_CD_LEFT_INPUT, mute); | |
765 | snd_opti93x_mute_reg(chip, OPTi93X_CD_RIGHT_INPUT, mute); | |
766 | switch (chip->hardware) { | |
767 | case OPTi9XX_HW_82C930: | |
768 | snd_opti93x_mute_reg(chip, OPTi930_AUX_LEFT_INPUT, mute); | |
769 | snd_opti93x_mute_reg(chip, OPTi930_AUX_RIGHT_INPUT, mute); | |
770 | break; | |
771 | case OPTi9XX_HW_82C931: | |
772 | case OPTi9XX_HW_82C933: | |
773 | snd_opti93x_mute_reg(chip, OPTi931_FM_LEFT_INPUT, mute); | |
774 | snd_opti93x_mute_reg(chip, OPTi931_FM_RIGHT_INPUT, mute); | |
775 | snd_opti93x_mute_reg(chip, OPTi931_AUX_LEFT_INPUT, mute); | |
776 | snd_opti93x_mute_reg(chip, OPTi931_AUX_RIGHT_INPUT, mute); | |
777 | } | |
778 | snd_opti93x_mute_reg(chip, OPTi93X_DAC_LEFT, mute); | |
779 | snd_opti93x_mute_reg(chip, OPTi93X_DAC_RIGHT, mute); | |
780 | snd_opti93x_mute_reg(chip, OPTi93X_LINE_LEFT_INPUT, mute); | |
781 | snd_opti93x_mute_reg(chip, OPTi93X_LINE_RIGHT_INPUT, mute); | |
782 | snd_opti93x_mute_reg(chip, OPTi93X_MIC_LEFT_INPUT, mute); | |
783 | snd_opti93x_mute_reg(chip, OPTi93X_MIC_RIGHT_INPUT, mute); | |
784 | snd_opti93x_mute_reg(chip, OPTi93X_OUT_LEFT, mute); | |
785 | snd_opti93x_mute_reg(chip, OPTi93X_OUT_RIGHT, mute); | |
786 | } | |
787 | ||
788 | ||
789 | static unsigned int snd_opti93x_get_count(unsigned char format, | |
790 | unsigned int size) | |
791 | { | |
792 | switch (format & 0xe0) { | |
793 | case OPTi93X_LINEAR_16_LIT: | |
794 | case OPTi93X_LINEAR_16_BIG: | |
795 | size >>= 1; | |
796 | break; | |
797 | case OPTi93X_ADPCM_16: | |
798 | return size >> 2; | |
799 | } | |
800 | return (format & OPTi93X_STEREO) ? (size >> 1) : size; | |
801 | } | |
802 | ||
803 | static unsigned int rates[] = { 5512, 6615, 8000, 9600, 11025, 16000, | |
804 | 18900, 22050, 27428, 32000, 33075, 37800, | |
805 | 44100, 48000 }; | |
806 | #define RATES ARRAY_SIZE(rates) | |
807 | ||
346c7a68 | 808 | static struct snd_pcm_hw_constraint_list hw_constraints_rates = { |
1da177e4 LT |
809 | .count = RATES, |
810 | .list = rates, | |
811 | .mask = 0, | |
812 | }; | |
813 | ||
814 | static unsigned char bits[] = { 0x01, 0x0f, 0x00, 0x0e, 0x03, 0x02, | |
815 | 0x05, 0x07, 0x04, 0x06, 0x0d, 0x09, | |
816 | 0x0b, 0x0c}; | |
817 | ||
818 | static unsigned char snd_opti93x_get_freq(unsigned int rate) | |
819 | { | |
820 | unsigned int i; | |
821 | ||
822 | for (i = 0; i < RATES; i++) { | |
823 | if (rate == rates[i]) | |
824 | return bits[i]; | |
825 | } | |
826 | snd_BUG(); | |
827 | return bits[RATES-1]; | |
828 | } | |
829 | ||
346c7a68 | 830 | static unsigned char snd_opti93x_get_format(struct snd_opti93x *chip, |
1da177e4 LT |
831 | unsigned int format, int channels) |
832 | { | |
833 | unsigned char retval = OPTi93X_LINEAR_8; | |
834 | ||
835 | switch (format) { | |
836 | case SNDRV_PCM_FORMAT_MU_LAW: | |
837 | retval = OPTi93X_ULAW_8; | |
838 | break; | |
839 | case SNDRV_PCM_FORMAT_A_LAW: | |
840 | retval = OPTi93X_ALAW_8; | |
841 | break; | |
842 | case SNDRV_PCM_FORMAT_S16_LE: | |
843 | retval = OPTi93X_LINEAR_16_LIT; | |
844 | break; | |
845 | case SNDRV_PCM_FORMAT_S16_BE: | |
846 | retval = OPTi93X_LINEAR_16_BIG; | |
847 | break; | |
848 | case SNDRV_PCM_FORMAT_IMA_ADPCM: | |
849 | retval = OPTi93X_ADPCM_16; | |
850 | } | |
851 | return (channels > 1) ? (retval | OPTi93X_STEREO) : retval; | |
852 | } | |
853 | ||
854 | ||
346c7a68 | 855 | static void snd_opti93x_playback_format(struct snd_opti93x *chip, unsigned char fmt) |
1da177e4 LT |
856 | { |
857 | unsigned char mask; | |
858 | ||
859 | snd_opti93x_mute(chip, 1); | |
860 | ||
861 | snd_opti93x_mce_up(chip); | |
862 | mask = (chip->mode & OPTi93X_MODE_CAPTURE) ? 0xf0 : 0xff; | |
863 | snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, mask, fmt); | |
864 | snd_opti93x_mce_down(chip); | |
865 | ||
866 | snd_opti93x_mute(chip, 0); | |
867 | } | |
868 | ||
346c7a68 | 869 | static void snd_opti93x_capture_format(struct snd_opti93x *chip, unsigned char fmt) |
1da177e4 LT |
870 | { |
871 | snd_opti93x_mute(chip, 1); | |
872 | ||
873 | snd_opti93x_mce_up(chip); | |
874 | if (!(chip->mode & OPTi93X_MODE_PLAY)) | |
875 | snd_opti93x_out_mask(chip, OPTi93X_PLAY_FORMAT, 0x0f, fmt); | |
876 | else | |
877 | fmt = chip->image[OPTi93X_PLAY_FORMAT] & 0xf0; | |
878 | snd_opti93x_out_image(chip, OPTi93X_CAPT_FORMAT, fmt); | |
879 | snd_opti93x_mce_down(chip); | |
880 | ||
881 | snd_opti93x_mute(chip, 0); | |
882 | } | |
883 | ||
884 | ||
346c7a68 | 885 | static int snd_opti93x_open(struct snd_opti93x *chip, unsigned int mode) |
1da177e4 LT |
886 | { |
887 | unsigned long flags; | |
888 | ||
889 | spin_lock_irqsave(&chip->lock, flags); | |
890 | ||
891 | if (chip->mode & mode) { | |
892 | spin_unlock_irqrestore(&chip->lock, flags); | |
893 | return -EAGAIN; | |
894 | } | |
895 | ||
896 | if (!(chip->mode & OPTi93X_MODE_OPEN)) { | |
897 | outb(0x00, OPTi93X_PORT(chip, STATUS)); | |
898 | snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, | |
899 | OPTi93X_IRQ_ENABLE, OPTi93X_IRQ_ENABLE); | |
900 | chip->mode = mode; | |
901 | } | |
902 | else | |
903 | chip->mode |= mode; | |
904 | ||
905 | spin_unlock_irqrestore(&chip->lock, flags); | |
906 | return 0; | |
907 | } | |
908 | ||
346c7a68 | 909 | static void snd_opti93x_close(struct snd_opti93x *chip, unsigned int mode) |
1da177e4 LT |
910 | { |
911 | unsigned long flags; | |
912 | ||
913 | spin_lock_irqsave(&chip->lock, flags); | |
914 | ||
915 | chip->mode &= ~mode; | |
916 | if (chip->mode & OPTi93X_MODE_OPEN) { | |
917 | spin_unlock_irqrestore(&chip->lock, flags); | |
918 | return; | |
919 | } | |
920 | ||
921 | snd_opti93x_mute(chip, 1); | |
922 | ||
923 | outb(0, OPTi93X_PORT(chip, STATUS)); | |
924 | snd_opti93x_out_mask(chip, OPTi93X_PIN_CTRL, OPTi93X_IRQ_ENABLE, | |
925 | ~OPTi93X_IRQ_ENABLE); | |
926 | ||
927 | snd_opti93x_mce_up(chip); | |
928 | snd_opti93x_out_image(chip, OPTi93X_IFACE_CONF, 0x00); | |
929 | snd_opti93x_mce_down(chip); | |
930 | chip->mode = 0; | |
931 | ||
932 | snd_opti93x_mute(chip, 0); | |
933 | spin_unlock_irqrestore(&chip->lock, flags); | |
934 | } | |
935 | ||
346c7a68 | 936 | static int snd_opti93x_trigger(struct snd_pcm_substream *substream, |
1da177e4 LT |
937 | unsigned char what, int cmd) |
938 | { | |
346c7a68 | 939 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
940 | |
941 | switch (cmd) { | |
942 | case SNDRV_PCM_TRIGGER_START: | |
943 | case SNDRV_PCM_TRIGGER_STOP: | |
944 | { | |
945 | unsigned int what = 0; | |
346c7a68 | 946 | struct snd_pcm_substream *s; |
ef991b95 | 947 | snd_pcm_group_for_each_entry(s, substream) { |
1da177e4 LT |
948 | if (s == chip->playback_substream) { |
949 | what |= OPTi93X_PLAYBACK_ENABLE; | |
950 | snd_pcm_trigger_done(s, substream); | |
951 | } else if (s == chip->capture_substream) { | |
952 | what |= OPTi93X_CAPTURE_ENABLE; | |
953 | snd_pcm_trigger_done(s, substream); | |
954 | } | |
955 | } | |
956 | spin_lock(&chip->lock); | |
957 | if (cmd == SNDRV_PCM_TRIGGER_START) { | |
958 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what); | |
959 | if (what & OPTi93X_CAPTURE_ENABLE) | |
960 | udelay(50); | |
961 | } else | |
962 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, 0x00); | |
963 | spin_unlock(&chip->lock); | |
964 | break; | |
965 | } | |
966 | default: | |
967 | return -EINVAL; | |
968 | } | |
969 | return 0; | |
970 | } | |
971 | ||
346c7a68 | 972 | static int snd_opti93x_playback_trigger(struct snd_pcm_substream *substream, int cmd) |
1da177e4 LT |
973 | { |
974 | return snd_opti93x_trigger(substream, | |
975 | OPTi93X_PLAYBACK_ENABLE, cmd); | |
976 | } | |
977 | ||
346c7a68 | 978 | static int snd_opti93x_capture_trigger(struct snd_pcm_substream *substream, int cmd) |
1da177e4 LT |
979 | { |
980 | return snd_opti93x_trigger(substream, | |
981 | OPTi93X_CAPTURE_ENABLE, cmd); | |
982 | } | |
983 | ||
346c7a68 TI |
984 | static int snd_opti93x_hw_params(struct snd_pcm_substream *substream, |
985 | struct snd_pcm_hw_params *hw_params) | |
1da177e4 LT |
986 | { |
987 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | |
988 | } | |
989 | ||
990 | ||
346c7a68 | 991 | static int snd_opti93x_hw_free(struct snd_pcm_substream *substream) |
1da177e4 LT |
992 | { |
993 | snd_pcm_lib_free_pages(substream); | |
994 | return 0; | |
995 | } | |
996 | ||
997 | ||
346c7a68 | 998 | static int snd_opti93x_playback_prepare(struct snd_pcm_substream *substream) |
1da177e4 | 999 | { |
346c7a68 TI |
1000 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1001 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 LT |
1002 | unsigned long flags; |
1003 | unsigned char format; | |
1004 | unsigned int count = snd_pcm_lib_period_bytes(substream); | |
1005 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | |
1006 | ||
1007 | spin_lock_irqsave(&chip->lock, flags); | |
1008 | ||
1009 | chip->p_dma_size = size; | |
1010 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, | |
1011 | OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO, | |
1012 | ~(OPTi93X_PLAYBACK_ENABLE | OPTi93X_PLAYBACK_PIO)); | |
1013 | ||
1014 | snd_dma_program(chip->dma1, runtime->dma_addr, size, | |
1015 | DMA_MODE_WRITE | DMA_AUTOINIT); | |
1016 | ||
1017 | format = snd_opti93x_get_freq(runtime->rate); | |
1018 | format |= snd_opti93x_get_format(chip, runtime->format, | |
1019 | runtime->channels); | |
1020 | snd_opti93x_playback_format(chip, format); | |
1021 | format = chip->image[OPTi93X_PLAY_FORMAT]; | |
1022 | ||
1023 | count = snd_opti93x_get_count(format, count) - 1; | |
1024 | snd_opti93x_out_image(chip, OPTi93X_PLAY_LWR_CNT, count); | |
1025 | snd_opti93x_out_image(chip, OPTi93X_PLAY_UPR_CNT, count >> 8); | |
1026 | ||
1027 | spin_unlock_irqrestore(&chip->lock, flags); | |
1028 | return 0; | |
1029 | } | |
1030 | ||
346c7a68 | 1031 | static int snd_opti93x_capture_prepare(struct snd_pcm_substream *substream) |
1da177e4 | 1032 | { |
346c7a68 TI |
1033 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1034 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 LT |
1035 | unsigned long flags; |
1036 | unsigned char format; | |
1037 | unsigned int count = snd_pcm_lib_period_bytes(substream); | |
1038 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | |
1039 | ||
1040 | spin_lock_irqsave(&chip->lock, flags); | |
1041 | ||
1042 | chip->c_dma_size = size; | |
1043 | snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, | |
db67319a | 1044 | OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0); |
1da177e4 LT |
1045 | |
1046 | snd_dma_program(chip->dma2, runtime->dma_addr, size, | |
1047 | DMA_MODE_READ | DMA_AUTOINIT); | |
1048 | ||
1049 | format = snd_opti93x_get_freq(runtime->rate); | |
1050 | format |= snd_opti93x_get_format(chip, runtime->format, | |
1051 | runtime->channels); | |
1052 | snd_opti93x_capture_format(chip, format); | |
1053 | format = chip->image[OPTi93X_CAPT_FORMAT]; | |
1054 | ||
1055 | count = snd_opti93x_get_count(format, count) - 1; | |
1056 | snd_opti93x_out_image(chip, OPTi93X_CAPT_LWR_CNT, count); | |
1057 | snd_opti93x_out_image(chip, OPTi93X_CAPT_UPR_CNT, count >> 8); | |
1058 | ||
1059 | spin_unlock_irqrestore(&chip->lock, flags); | |
1060 | return 0; | |
1061 | } | |
1062 | ||
346c7a68 | 1063 | static snd_pcm_uframes_t snd_opti93x_playback_pointer(struct snd_pcm_substream *substream) |
1da177e4 | 1064 | { |
346c7a68 | 1065 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
1066 | size_t ptr; |
1067 | ||
1068 | if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_PLAYBACK_ENABLE)) | |
1069 | return 0; | |
1070 | ||
1071 | ptr = snd_dma_pointer(chip->dma1, chip->p_dma_size); | |
1072 | return bytes_to_frames(substream->runtime, ptr); | |
1073 | } | |
1074 | ||
346c7a68 | 1075 | static snd_pcm_uframes_t snd_opti93x_capture_pointer(struct snd_pcm_substream *substream) |
1da177e4 | 1076 | { |
346c7a68 | 1077 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
1078 | size_t ptr; |
1079 | ||
1080 | if (!(chip->image[OPTi93X_IFACE_CONF] & OPTi93X_CAPTURE_ENABLE)) | |
1081 | return 0; | |
1082 | ||
1083 | ptr = snd_dma_pointer(chip->dma2, chip->c_dma_size); | |
1084 | return bytes_to_frames(substream->runtime, ptr); | |
1085 | } | |
1086 | ||
1087 | ||
346c7a68 | 1088 | static void snd_opti93x_overrange(struct snd_opti93x *chip) |
1da177e4 LT |
1089 | { |
1090 | unsigned long flags; | |
1091 | ||
1092 | spin_lock_irqsave(&chip->lock, flags); | |
1093 | ||
1094 | if (snd_opti93x_in(chip, OPTi93X_ERR_INIT) & (0x08 | 0x02)) | |
1095 | chip->capture_substream->runtime->overrange++; | |
1096 | ||
1097 | spin_unlock_irqrestore(&chip->lock, flags); | |
1098 | } | |
1099 | ||
7d12e780 | 1100 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) |
1da177e4 | 1101 | { |
346c7a68 | 1102 | struct snd_opti93x *codec = dev_id; |
1da177e4 LT |
1103 | unsigned char status; |
1104 | ||
1105 | status = snd_opti9xx_read(codec->chip, OPTi9XX_MC_REG(11)); | |
1106 | if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) | |
1107 | snd_pcm_period_elapsed(codec->playback_substream); | |
1108 | if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) { | |
1109 | snd_opti93x_overrange(codec); | |
1110 | snd_pcm_period_elapsed(codec->capture_substream); | |
1111 | } | |
1112 | outb(0x00, OPTi93X_PORT(codec, STATUS)); | |
1113 | return IRQ_HANDLED; | |
1114 | } | |
1115 | ||
1116 | ||
346c7a68 | 1117 | static struct snd_pcm_hardware snd_opti93x_playback = { |
1da177e4 LT |
1118 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1119 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), | |
1120 | .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | | |
1121 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), | |
1122 | .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, | |
1123 | .rate_min = 5512, | |
1124 | .rate_max = 48000, | |
1125 | .channels_min = 1, | |
1126 | .channels_max = 2, | |
1127 | .buffer_bytes_max = (128*1024), | |
1128 | .period_bytes_min = 64, | |
1129 | .period_bytes_max = (128*1024), | |
1130 | .periods_min = 1, | |
1131 | .periods_max = 1024, | |
1132 | .fifo_size = 0, | |
1133 | }; | |
1134 | ||
346c7a68 | 1135 | static struct snd_pcm_hardware snd_opti93x_capture = { |
1da177e4 LT |
1136 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
1137 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START), | |
1138 | .formats = (SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | | |
1139 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE), | |
1140 | .rates = SNDRV_PCM_RATE_8000_48000, | |
1141 | .rate_min = 5512, | |
1142 | .rate_max = 48000, | |
1143 | .channels_min = 1, | |
1144 | .channels_max = 2, | |
1145 | .buffer_bytes_max = (128*1024), | |
1146 | .period_bytes_min = 64, | |
1147 | .period_bytes_max = (128*1024), | |
1148 | .periods_min = 1, | |
1149 | .periods_max = 1024, | |
1150 | .fifo_size = 0, | |
1151 | }; | |
1152 | ||
346c7a68 | 1153 | static int snd_opti93x_playback_open(struct snd_pcm_substream *substream) |
1da177e4 LT |
1154 | { |
1155 | int error; | |
346c7a68 TI |
1156 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1157 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 LT |
1158 | |
1159 | if ((error = snd_opti93x_open(chip, OPTi93X_MODE_PLAY)) < 0) | |
1160 | return error; | |
1161 | snd_pcm_set_sync(substream); | |
1162 | chip->playback_substream = substream; | |
1163 | runtime->hw = snd_opti93x_playback; | |
1164 | snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max); | |
1165 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | |
1166 | return error; | |
1167 | } | |
1168 | ||
346c7a68 | 1169 | static int snd_opti93x_capture_open(struct snd_pcm_substream *substream) |
1da177e4 LT |
1170 | { |
1171 | int error; | |
346c7a68 TI |
1172 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1173 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 LT |
1174 | |
1175 | if ((error = snd_opti93x_open(chip, OPTi93X_MODE_CAPTURE)) < 0) | |
1176 | return error; | |
1177 | runtime->hw = snd_opti93x_capture; | |
1178 | snd_pcm_set_sync(substream); | |
1179 | chip->capture_substream = substream; | |
1180 | snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max); | |
1181 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | |
1182 | return error; | |
1183 | } | |
1184 | ||
346c7a68 | 1185 | static int snd_opti93x_playback_close(struct snd_pcm_substream *substream) |
1da177e4 | 1186 | { |
346c7a68 | 1187 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
1188 | |
1189 | chip->playback_substream = NULL; | |
1190 | snd_opti93x_close(chip, OPTi93X_MODE_PLAY); | |
1191 | return 0; | |
1192 | } | |
1193 | ||
346c7a68 | 1194 | static int snd_opti93x_capture_close(struct snd_pcm_substream *substream) |
1da177e4 | 1195 | { |
346c7a68 | 1196 | struct snd_opti93x *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
1197 | |
1198 | chip->capture_substream = NULL; | |
1199 | snd_opti93x_close(chip, OPTi93X_MODE_CAPTURE); | |
1200 | return 0; | |
1201 | } | |
1202 | ||
1203 | ||
346c7a68 | 1204 | static void snd_opti93x_init(struct snd_opti93x *chip) |
1da177e4 LT |
1205 | { |
1206 | unsigned long flags; | |
1207 | int i; | |
1208 | ||
1209 | spin_lock_irqsave(&chip->lock, flags); | |
1210 | snd_opti93x_mce_up(chip); | |
1211 | ||
1212 | for (i = 0; i < 32; i++) | |
1213 | snd_opti93x_out_image(chip, i, snd_opti93x_default_image[i]); | |
1214 | ||
1215 | snd_opti93x_mce_down(chip); | |
1216 | spin_unlock_irqrestore(&chip->lock, flags); | |
1217 | } | |
1218 | ||
346c7a68 | 1219 | static int snd_opti93x_probe(struct snd_opti93x *chip) |
1da177e4 LT |
1220 | { |
1221 | unsigned long flags; | |
1222 | unsigned char val; | |
1223 | ||
1224 | spin_lock_irqsave(&chip->lock, flags); | |
1225 | val = snd_opti93x_in(chip, OPTi93X_ID) & 0x0f; | |
1226 | spin_unlock_irqrestore(&chip->lock, flags); | |
1227 | ||
1228 | return (val == 0x0a) ? 0 : -ENODEV; | |
1229 | } | |
1230 | ||
346c7a68 | 1231 | static int snd_opti93x_free(struct snd_opti93x *chip) |
1da177e4 | 1232 | { |
b1d5776d | 1233 | release_and_free_resource(chip->res_port); |
1da177e4 LT |
1234 | if (chip->dma1 >= 0) { |
1235 | disable_dma(chip->dma1); | |
1236 | free_dma(chip->dma1); | |
1237 | } | |
1238 | if (chip->dma2 >= 0) { | |
1239 | disable_dma(chip->dma2); | |
1240 | free_dma(chip->dma2); | |
1241 | } | |
1242 | if (chip->irq >= 0) { | |
1243 | free_irq(chip->irq, chip); | |
1244 | } | |
1245 | kfree(chip); | |
1246 | return 0; | |
1247 | } | |
1248 | ||
346c7a68 | 1249 | static int snd_opti93x_dev_free(struct snd_device *device) |
1da177e4 | 1250 | { |
346c7a68 | 1251 | struct snd_opti93x *chip = device->device_data; |
1da177e4 LT |
1252 | return snd_opti93x_free(chip); |
1253 | } | |
1254 | ||
346c7a68 | 1255 | static const char *snd_opti93x_chip_id(struct snd_opti93x *codec) |
1da177e4 LT |
1256 | { |
1257 | switch (codec->hardware) { | |
1258 | case OPTi9XX_HW_82C930: return "82C930"; | |
1259 | case OPTi9XX_HW_82C931: return "82C931"; | |
1260 | case OPTi9XX_HW_82C933: return "82C933"; | |
1261 | default: return "???"; | |
1262 | } | |
1263 | } | |
1264 | ||
346c7a68 | 1265 | static int snd_opti93x_create(struct snd_card *card, struct snd_opti9xx *chip, |
1da177e4 | 1266 | int dma1, int dma2, |
346c7a68 | 1267 | struct snd_opti93x **rcodec) |
1da177e4 | 1268 | { |
346c7a68 | 1269 | static struct snd_device_ops ops = { |
1da177e4 LT |
1270 | .dev_free = snd_opti93x_dev_free, |
1271 | }; | |
1272 | int error; | |
346c7a68 | 1273 | struct snd_opti93x *codec; |
1da177e4 LT |
1274 | |
1275 | *rcodec = NULL; | |
9e76a76e | 1276 | codec = kzalloc(sizeof(*codec), GFP_KERNEL); |
1da177e4 LT |
1277 | if (codec == NULL) |
1278 | return -ENOMEM; | |
1279 | codec->irq = -1; | |
1280 | codec->dma1 = -1; | |
1281 | codec->dma2 = -1; | |
1282 | ||
1283 | if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) { | |
1284 | snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4); | |
1285 | snd_opti93x_free(codec); | |
1286 | return -EBUSY; | |
1287 | } | |
1288 | if (request_dma(dma1, "OPTI93x - 1")) { | |
1289 | snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1); | |
1290 | snd_opti93x_free(codec); | |
1291 | return -EBUSY; | |
1292 | } | |
1293 | codec->dma1 = chip->dma1; | |
1294 | if (request_dma(dma2, "OPTI93x - 2")) { | |
1295 | snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2); | |
1296 | snd_opti93x_free(codec); | |
1297 | return -EBUSY; | |
1298 | } | |
1299 | codec->dma2 = chip->dma2; | |
1300 | ||
83c51c0a | 1301 | if (request_irq(chip->irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec)) { |
1da177e4 LT |
1302 | snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); |
1303 | snd_opti93x_free(codec); | |
1304 | return -EBUSY; | |
1305 | } | |
1306 | ||
1307 | codec->card = card; | |
1308 | codec->port = chip->wss_base + 4; | |
1309 | codec->irq = chip->irq; | |
1310 | ||
1311 | spin_lock_init(&codec->lock); | |
1312 | codec->hardware = chip->hardware; | |
1313 | codec->chip = chip; | |
1314 | ||
1315 | if ((error = snd_opti93x_probe(codec))) { | |
1316 | snd_opti93x_free(codec); | |
1317 | return error; | |
1318 | } | |
1319 | ||
1320 | snd_opti93x_init(codec); | |
1321 | ||
1322 | /* Register device */ | |
1323 | if ((error = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) { | |
1324 | snd_opti93x_free(codec); | |
1325 | return error; | |
1326 | } | |
1327 | ||
1328 | *rcodec = codec; | |
1329 | return 0; | |
1330 | } | |
1331 | ||
346c7a68 | 1332 | static struct snd_pcm_ops snd_opti93x_playback_ops = { |
1da177e4 LT |
1333 | .open = snd_opti93x_playback_open, |
1334 | .close = snd_opti93x_playback_close, | |
1335 | .ioctl = snd_pcm_lib_ioctl, | |
1336 | .hw_params = snd_opti93x_hw_params, | |
1337 | .hw_free = snd_opti93x_hw_free, | |
1338 | .prepare = snd_opti93x_playback_prepare, | |
1339 | .trigger = snd_opti93x_playback_trigger, | |
1340 | .pointer = snd_opti93x_playback_pointer, | |
1341 | }; | |
1342 | ||
346c7a68 | 1343 | static struct snd_pcm_ops snd_opti93x_capture_ops = { |
1da177e4 LT |
1344 | .open = snd_opti93x_capture_open, |
1345 | .close = snd_opti93x_capture_close, | |
1346 | .ioctl = snd_pcm_lib_ioctl, | |
1347 | .hw_params = snd_opti93x_hw_params, | |
1348 | .hw_free = snd_opti93x_hw_free, | |
1349 | .prepare = snd_opti93x_capture_prepare, | |
1350 | .trigger = snd_opti93x_capture_trigger, | |
1351 | .pointer = snd_opti93x_capture_pointer, | |
1352 | }; | |
1353 | ||
346c7a68 | 1354 | static int snd_opti93x_pcm(struct snd_opti93x *codec, int device, struct snd_pcm **rpcm) |
1da177e4 LT |
1355 | { |
1356 | int error; | |
346c7a68 | 1357 | struct snd_pcm *pcm; |
1da177e4 | 1358 | |
91134859 | 1359 | if ((error = snd_pcm_new(codec->card, "OPTi 82C93X", device, 1, 1, &pcm)) < 0) |
1da177e4 LT |
1360 | return error; |
1361 | ||
1362 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_opti93x_playback_ops); | |
1363 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_opti93x_capture_ops); | |
1364 | ||
1365 | pcm->private_data = codec; | |
1da177e4 LT |
1366 | pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; |
1367 | ||
1368 | strcpy(pcm->name, snd_opti93x_chip_id(codec)); | |
1369 | ||
1370 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | |
1371 | snd_dma_isa_data(), | |
1372 | 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024); | |
1373 | ||
1374 | codec->pcm = pcm; | |
1375 | if (rpcm) | |
1376 | *rpcm = pcm; | |
1377 | return 0; | |
1378 | } | |
1379 | ||
1380 | /* | |
1381 | * MIXER part | |
1382 | */ | |
1383 | ||
346c7a68 | 1384 | static int snd_opti93x_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1da177e4 LT |
1385 | { |
1386 | static char *texts[4] = { | |
1387 | "Line1", "Aux", "Mic", "Mix" | |
1388 | }; | |
1389 | ||
1390 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
1391 | uinfo->count = 2; | |
1392 | uinfo->value.enumerated.items = 4; | |
1393 | if (uinfo->value.enumerated.item > 3) | |
1394 | uinfo->value.enumerated.item = 3; | |
1395 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | |
1396 | return 0; | |
1397 | } | |
1398 | ||
346c7a68 | 1399 | static int snd_opti93x_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 1400 | { |
346c7a68 | 1401 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
1402 | unsigned long flags; |
1403 | ||
1404 | spin_lock_irqsave(&chip->lock, flags); | |
1405 | ucontrol->value.enumerated.item[0] = (chip->image[OPTi93X_MIXOUT_LEFT] & OPTi93X_MIXOUT_MIXER) >> 6; | |
1406 | ucontrol->value.enumerated.item[1] = (chip->image[OPTi93X_MIXOUT_RIGHT] & OPTi93X_MIXOUT_MIXER) >> 6; | |
1407 | spin_unlock_irqrestore(&chip->lock, flags); | |
1408 | return 0; | |
1409 | } | |
1410 | ||
346c7a68 | 1411 | static int snd_opti93x_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 1412 | { |
346c7a68 | 1413 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
1414 | unsigned long flags; |
1415 | unsigned short left, right; | |
1416 | int change; | |
1417 | ||
1418 | if (ucontrol->value.enumerated.item[0] > 3 || | |
1419 | ucontrol->value.enumerated.item[1] > 3) | |
1420 | return -EINVAL; | |
1421 | left = ucontrol->value.enumerated.item[0] << 6; | |
1422 | right = ucontrol->value.enumerated.item[1] << 6; | |
1423 | spin_lock_irqsave(&chip->lock, flags); | |
1424 | left = (chip->image[OPTi93X_MIXOUT_LEFT] & ~OPTi93X_MIXOUT_MIXER) | left; | |
1425 | right = (chip->image[OPTi93X_MIXOUT_RIGHT] & ~OPTi93X_MIXOUT_MIXER) | right; | |
1426 | change = left != chip->image[OPTi93X_MIXOUT_LEFT] || | |
1427 | right != chip->image[OPTi93X_MIXOUT_RIGHT]; | |
1428 | snd_opti93x_out_image(chip, OPTi93X_MIXOUT_LEFT, left); | |
1429 | snd_opti93x_out_image(chip, OPTi93X_MIXOUT_RIGHT, right); | |
1430 | spin_unlock_irqrestore(&chip->lock, flags); | |
1431 | return change; | |
1432 | } | |
1433 | ||
1434 | #if 0 | |
1435 | ||
1436 | #define OPTi93X_SINGLE(xname, xindex, reg, shift, mask, invert) \ | |
1437 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | |
1438 | .info = snd_opti93x_info_single, \ | |
1439 | .get = snd_opti93x_get_single, .put = snd_opti93x_put_single, \ | |
1440 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } | |
1441 | ||
346c7a68 | 1442 | static int snd_opti93x_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1da177e4 LT |
1443 | { |
1444 | int mask = (kcontrol->private_value >> 16) & 0xff; | |
1445 | ||
1446 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | |
1447 | uinfo->count = 1; | |
1448 | uinfo->value.integer.min = 0; | |
1449 | uinfo->value.integer.max = mask; | |
1450 | return 0; | |
1451 | } | |
1452 | ||
346c7a68 | 1453 | static int snd_opti93x_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 1454 | { |
346c7a68 | 1455 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
1456 | unsigned long flags; |
1457 | int reg = kcontrol->private_value & 0xff; | |
1458 | int shift = (kcontrol->private_value >> 8) & 0xff; | |
1459 | int mask = (kcontrol->private_value >> 16) & 0xff; | |
1460 | int invert = (kcontrol->private_value >> 24) & 0xff; | |
1461 | ||
1462 | spin_lock_irqsave(&chip->lock, flags); | |
1463 | ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; | |
1464 | spin_unlock_irqrestore(&chip->lock, flags); | |
1465 | if (invert) | |
1466 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | |
1467 | return 0; | |
1468 | } | |
1469 | ||
346c7a68 | 1470 | static int snd_opti93x_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 1471 | { |
346c7a68 | 1472 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
1473 | unsigned long flags; |
1474 | int reg = kcontrol->private_value & 0xff; | |
1475 | int shift = (kcontrol->private_value >> 8) & 0xff; | |
1476 | int mask = (kcontrol->private_value >> 16) & 0xff; | |
1477 | int invert = (kcontrol->private_value >> 24) & 0xff; | |
1478 | int change; | |
1479 | unsigned short val; | |
1480 | ||
1481 | val = (ucontrol->value.integer.value[0] & mask); | |
1482 | if (invert) | |
1483 | val = mask - val; | |
1484 | val <<= shift; | |
1485 | spin_lock_irqsave(&chip->lock, flags); | |
1486 | val = (chip->image[reg] & ~(mask << shift)) | val; | |
1487 | change = val != chip->image[reg]; | |
1488 | snd_opti93x_out(chip, reg, val); | |
1489 | spin_unlock_irqrestore(&chip->lock, flags); | |
1490 | return change; | |
1491 | } | |
1492 | ||
1493 | #endif /* single */ | |
1494 | ||
1495 | #define OPTi93X_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ | |
1496 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ | |
1497 | .info = snd_opti93x_info_double, \ | |
1498 | .get = snd_opti93x_get_double, .put = snd_opti93x_put_double, \ | |
1499 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } | |
1500 | ||
1501 | #define OPTi93X_DOUBLE_INVERT_INVERT(xctl) \ | |
1502 | do { xctl.private_value ^= 22; } while (0) | |
1503 | #define OPTi93X_DOUBLE_CHANGE_REGS(xctl, left_reg, right_reg) \ | |
1504 | do { xctl.private_value &= ~0x0000ffff; \ | |
1505 | xctl.private_value |= left_reg | (right_reg << 8); } while (0) | |
1506 | ||
346c7a68 | 1507 | static int snd_opti93x_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
1da177e4 LT |
1508 | { |
1509 | int mask = (kcontrol->private_value >> 24) & 0xff; | |
1510 | ||
1511 | uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; | |
1512 | uinfo->count = 2; | |
1513 | uinfo->value.integer.min = 0; | |
1514 | uinfo->value.integer.max = mask; | |
1515 | return 0; | |
1516 | } | |
1517 | ||
346c7a68 | 1518 | static int snd_opti93x_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 1519 | { |
346c7a68 | 1520 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
1521 | unsigned long flags; |
1522 | int left_reg = kcontrol->private_value & 0xff; | |
1523 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | |
1524 | int shift_left = (kcontrol->private_value >> 16) & 0x07; | |
1525 | int shift_right = (kcontrol->private_value >> 19) & 0x07; | |
1526 | int mask = (kcontrol->private_value >> 24) & 0xff; | |
1527 | int invert = (kcontrol->private_value >> 22) & 1; | |
1528 | ||
1529 | spin_lock_irqsave(&chip->lock, flags); | |
1530 | ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; | |
1531 | ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; | |
1532 | spin_unlock_irqrestore(&chip->lock, flags); | |
1533 | if (invert) { | |
1534 | ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; | |
1535 | ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; | |
1536 | } | |
1537 | return 0; | |
1538 | } | |
1539 | ||
346c7a68 | 1540 | static int snd_opti93x_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
1da177e4 | 1541 | { |
346c7a68 | 1542 | struct snd_opti93x *chip = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
1543 | unsigned long flags; |
1544 | int left_reg = kcontrol->private_value & 0xff; | |
1545 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | |
1546 | int shift_left = (kcontrol->private_value >> 16) & 0x07; | |
1547 | int shift_right = (kcontrol->private_value >> 19) & 0x07; | |
1548 | int mask = (kcontrol->private_value >> 24) & 0xff; | |
1549 | int invert = (kcontrol->private_value >> 22) & 1; | |
1550 | int change; | |
1551 | unsigned short val1, val2; | |
1552 | ||
1553 | val1 = ucontrol->value.integer.value[0] & mask; | |
1554 | val2 = ucontrol->value.integer.value[1] & mask; | |
1555 | if (invert) { | |
1556 | val1 = mask - val1; | |
1557 | val2 = mask - val2; | |
1558 | } | |
1559 | val1 <<= shift_left; | |
1560 | val2 <<= shift_right; | |
1561 | spin_lock_irqsave(&chip->lock, flags); | |
1562 | val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; | |
1563 | val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; | |
1564 | change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; | |
1565 | snd_opti93x_out_image(chip, left_reg, val1); | |
1566 | snd_opti93x_out_image(chip, right_reg, val2); | |
1567 | spin_unlock_irqrestore(&chip->lock, flags); | |
1568 | return change; | |
1569 | } | |
1570 | ||
5e24c1c1 | 1571 | static struct snd_kcontrol_new snd_opti93x_controls[] __devinitdata = { |
1da177e4 LT |
1572 | OPTi93X_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), |
1573 | OPTi93X_DOUBLE("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), | |
1574 | OPTi93X_DOUBLE("PCM Playback Switch", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 7, 7, 1, 1), | |
1575 | OPTi93X_DOUBLE("PCM Playback Volume", 0, OPTi93X_DAC_LEFT, OPTi93X_DAC_RIGHT, 0, 0, 31, 1), | |
1576 | OPTi93X_DOUBLE("FM Playback Switch", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 7, 7, 1, 1), | |
1577 | OPTi93X_DOUBLE("FM Playback Volume", 0, OPTi931_FM_LEFT_INPUT, OPTi931_FM_RIGHT_INPUT, 1, 1, 15, 1), | |
1578 | OPTi93X_DOUBLE("Line Playback Switch", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 7, 7, 1, 1), | |
1579 | OPTi93X_DOUBLE("Line Playback Volume", 0, OPTi93X_LINE_LEFT_INPUT, OPTi93X_LINE_RIGHT_INPUT, 1, 1, 15, 1), | |
1580 | OPTi93X_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | |
1581 | OPTi93X_DOUBLE("Mic Playback Volume", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), | |
1582 | OPTi93X_DOUBLE("Mic Boost", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 5, 5, 1, 1), | |
1583 | OPTi93X_DOUBLE("CD Playback Switch", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 7, 7, 1, 1), | |
1584 | OPTi93X_DOUBLE("CD Playback Volume", 0, OPTi93X_CD_LEFT_INPUT, OPTi93X_CD_RIGHT_INPUT, 1, 1, 15, 1), | |
1585 | OPTi93X_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | |
1586 | OPTi93X_DOUBLE("Aux Playback Volume", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), | |
1587 | OPTi93X_DOUBLE("Capture Volume", 0, OPTi93X_MIXOUT_LEFT, OPTi93X_MIXOUT_RIGHT, 0, 0, 15, 0), | |
1588 | { | |
1589 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
1590 | .name = "Capture Source", | |
1591 | .info = snd_opti93x_info_mux, | |
1592 | .get = snd_opti93x_get_mux, | |
1593 | .put = snd_opti93x_put_mux, | |
1594 | } | |
1595 | }; | |
1596 | ||
9478bc3b | 1597 | static int __devinit snd_opti93x_mixer(struct snd_opti93x *chip) |
1da177e4 | 1598 | { |
346c7a68 TI |
1599 | struct snd_card *card; |
1600 | struct snd_kcontrol_new knew; | |
1da177e4 LT |
1601 | int err; |
1602 | unsigned int idx; | |
1603 | ||
1604 | snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); | |
1605 | ||
1606 | card = chip->card; | |
1607 | ||
1608 | strcpy(card->mixername, snd_opti93x_chip_id(chip)); | |
1609 | ||
1610 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { | |
1611 | knew = snd_opti93x_controls[idx]; | |
1612 | if (chip->hardware == OPTi9XX_HW_82C930) { | |
1613 | if (strstr(knew.name, "FM")) /* skip FM controls */ | |
1614 | continue; | |
1615 | else if (strcmp(knew.name, "Mic Playback Volume")) | |
1616 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | |
1617 | else if (strstr(knew.name, "Aux")) | |
1618 | OPTi93X_DOUBLE_CHANGE_REGS(knew, OPTi930_AUX_LEFT_INPUT, OPTi930_AUX_RIGHT_INPUT); | |
1619 | else if (strcmp(knew.name, "PCM Playback Volume")) | |
1620 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | |
1621 | else if (strcmp(knew.name, "Master Playback Volume")) | |
1622 | OPTi93X_DOUBLE_INVERT_INVERT(knew); | |
1623 | } | |
1624 | if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_opti93x_controls[idx], chip))) < 0) | |
1625 | return err; | |
1626 | } | |
1627 | return 0; | |
1628 | } | |
1629 | ||
1630 | #endif /* OPTi93X */ | |
1631 | ||
5e24c1c1 TI |
1632 | static int __devinit snd_card_opti9xx_detect(struct snd_card *card, |
1633 | struct snd_opti9xx *chip) | |
1da177e4 LT |
1634 | { |
1635 | int i, err; | |
1636 | ||
1637 | #ifndef OPTi93X | |
1638 | for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) { | |
1639 | unsigned char value; | |
1640 | ||
1641 | if ((err = snd_opti9xx_init(chip, i)) < 0) | |
1642 | return err; | |
1643 | ||
1644 | if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) | |
1645 | continue; | |
1646 | ||
1647 | value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)); | |
1648 | if ((value != 0xff) && (value != inb(chip->mc_base + 1))) | |
1649 | if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1))) | |
1650 | return 1; | |
1651 | ||
b1d5776d | 1652 | release_and_free_resource(chip->res_mc_base); |
1da177e4 LT |
1653 | chip->res_mc_base = NULL; |
1654 | ||
1655 | } | |
1656 | #else /* OPTi93X */ | |
1657 | for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) { | |
1658 | unsigned long flags; | |
1659 | unsigned char value; | |
1660 | ||
1661 | if ((err = snd_opti9xx_init(chip, i)) < 0) | |
1662 | return err; | |
1663 | ||
1664 | if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) | |
1665 | continue; | |
1666 | ||
1667 | spin_lock_irqsave(&chip->lock, flags); | |
1668 | outb(chip->password, chip->mc_base + chip->pwd_reg); | |
1669 | outb(((chip->mc_indir_index & (1 << 8)) >> 4) | | |
1670 | ((chip->mc_indir_index & 0xf0) >> 4), chip->mc_base); | |
1671 | spin_unlock_irqrestore(&chip->lock, flags); | |
1672 | ||
1673 | value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)); | |
1674 | snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value); | |
1675 | if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value) | |
1676 | return 1; | |
1677 | ||
b1d5776d | 1678 | release_and_free_resource(chip->res_mc_base); |
1da177e4 LT |
1679 | chip->res_mc_base = NULL; |
1680 | } | |
1681 | #endif /* OPTi93X */ | |
1682 | ||
1683 | return -ENODEV; | |
1684 | } | |
1685 | ||
1686 | #ifdef CONFIG_PNP | |
5e24c1c1 TI |
1687 | static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, |
1688 | struct pnp_card_link *card, | |
1689 | const struct pnp_card_device_id *pid) | |
1da177e4 LT |
1690 | { |
1691 | struct pnp_dev *pdev; | |
1da177e4 LT |
1692 | int err; |
1693 | ||
1694 | chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); | |
109c53f8 | 1695 | if (chip->dev == NULL) |
1da177e4 | 1696 | return -EBUSY; |
109c53f8 | 1697 | |
1da177e4 LT |
1698 | chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); |
1699 | ||
1700 | pdev = chip->dev; | |
1da177e4 | 1701 | |
1da177e4 LT |
1702 | err = pnp_activate_dev(pdev); |
1703 | if (err < 0) { | |
1704 | snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); | |
1da177e4 LT |
1705 | return err; |
1706 | } | |
1707 | ||
1708 | #ifdef OPTi93X | |
1709 | port = pnp_port_start(pdev, 0) - 4; | |
1ea73412 | 1710 | fm_port = pnp_port_start(pdev, 1) + 8; |
1da177e4 LT |
1711 | #else |
1712 | if (pid->driver_data != 0x0924) | |
1713 | port = pnp_port_start(pdev, 1); | |
1ea73412 | 1714 | fm_port = pnp_port_start(pdev, 2) + 8; |
1da177e4 LT |
1715 | #endif /* OPTi93X */ |
1716 | irq = pnp_irq(pdev, 0); | |
1717 | dma1 = pnp_dma(pdev, 0); | |
1718 | #if defined(CS4231) || defined(OPTi93X) | |
1719 | dma2 = pnp_dma(pdev, 1); | |
1720 | #endif /* CS4231 || OPTi93X */ | |
1721 | ||
1722 | pdev = chip->devmpu; | |
1723 | if (pdev && mpu_port > 0) { | |
1da177e4 LT |
1724 | err = pnp_activate_dev(pdev); |
1725 | if (err < 0) { | |
1726 | snd_printk(KERN_ERR "AUDIO pnp configure failure\n"); | |
1727 | mpu_port = -1; | |
1728 | chip->devmpu = NULL; | |
1729 | } else { | |
1730 | mpu_port = pnp_port_start(pdev, 0); | |
1731 | mpu_irq = pnp_irq(pdev, 0); | |
1732 | } | |
1733 | } | |
1da177e4 LT |
1734 | return pid->driver_data; |
1735 | } | |
1736 | #endif /* CONFIG_PNP */ | |
1737 | ||
346c7a68 | 1738 | static void snd_card_opti9xx_free(struct snd_card *card) |
1da177e4 | 1739 | { |
99a0b768 | 1740 | struct snd_opti9xx *chip = card->private_data; |
1da177e4 | 1741 | |
b1d5776d TI |
1742 | if (chip) |
1743 | release_and_free_resource(chip->res_mc_base); | |
1da177e4 LT |
1744 | } |
1745 | ||
5e24c1c1 | 1746 | static int __devinit snd_opti9xx_probe(struct snd_card *card) |
1da177e4 LT |
1747 | { |
1748 | static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; | |
1da177e4 | 1749 | int error; |
99a0b768 | 1750 | struct snd_opti9xx *chip = card->private_data; |
1da177e4 | 1751 | #if defined(OPTi93X) |
346c7a68 | 1752 | struct snd_opti93x *codec; |
1da177e4 | 1753 | #elif defined(CS4231) |
346c7a68 TI |
1754 | struct snd_cs4231 *codec; |
1755 | struct snd_timer *timer; | |
1da177e4 | 1756 | #else |
346c7a68 | 1757 | struct snd_ad1848 *codec; |
1da177e4 | 1758 | #endif |
346c7a68 TI |
1759 | struct snd_pcm *pcm; |
1760 | struct snd_rawmidi *rmidi; | |
1761 | struct snd_hwdep *synth; | |
1da177e4 LT |
1762 | |
1763 | if (! chip->res_mc_base && | |
99a0b768 TI |
1764 | (chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, |
1765 | "OPTi9xx MC")) == NULL) | |
1da177e4 | 1766 | return -ENOMEM; |
1da177e4 LT |
1767 | |
1768 | chip->wss_base = port; | |
1769 | chip->fm_port = fm_port; | |
1770 | chip->mpu_port = mpu_port; | |
1771 | chip->irq = irq; | |
1772 | chip->mpu_irq = mpu_irq; | |
1773 | chip->dma1 = dma1; | |
1774 | #if defined(CS4231) || defined(OPTi93X) | |
1775 | chip->dma2 = dma2; | |
1776 | #endif | |
1777 | ||
1778 | if (chip->wss_base == SNDRV_AUTO_PORT) { | |
1779 | if ((chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) { | |
1da177e4 LT |
1780 | snd_printk("unable to find a free WSS port\n"); |
1781 | return -EBUSY; | |
1782 | } | |
1783 | } | |
99a0b768 | 1784 | if ((error = snd_opti9xx_configure(chip))) |
1da177e4 | 1785 | return error; |
1da177e4 LT |
1786 | |
1787 | #if defined(OPTi93X) | |
99a0b768 | 1788 | if ((error = snd_opti93x_create(card, chip, chip->dma1, chip->dma2, &codec))) |
1da177e4 | 1789 | return error; |
99a0b768 | 1790 | if ((error = snd_opti93x_pcm(codec, 0, &pcm)) < 0) |
1da177e4 | 1791 | return error; |
99a0b768 | 1792 | if ((error = snd_opti93x_mixer(codec)) < 0) |
1da177e4 | 1793 | return error; |
1da177e4 LT |
1794 | #elif defined(CS4231) |
1795 | if ((error = snd_cs4231_create(card, chip->wss_base + 4, -1, | |
1796 | chip->irq, chip->dma1, chip->dma2, | |
1797 | CS4231_HW_DETECT, | |
1798 | 0, | |
99a0b768 | 1799 | &codec)) < 0) |
1da177e4 | 1800 | return error; |
99a0b768 | 1801 | if ((error = snd_cs4231_pcm(codec, 0, &pcm)) < 0) |
1da177e4 | 1802 | return error; |
99a0b768 | 1803 | if ((error = snd_cs4231_mixer(codec)) < 0) |
1da177e4 | 1804 | return error; |
99a0b768 | 1805 | if ((error = snd_cs4231_timer(codec, 0, &timer)) < 0) |
1da177e4 | 1806 | return error; |
1da177e4 LT |
1807 | #else |
1808 | if ((error = snd_ad1848_create(card, chip->wss_base + 4, | |
1809 | chip->irq, chip->dma1, | |
99a0b768 | 1810 | AD1848_HW_DETECT, &codec)) < 0) |
1da177e4 | 1811 | return error; |
99a0b768 | 1812 | if ((error = snd_ad1848_pcm(codec, 0, &pcm)) < 0) |
1da177e4 | 1813 | return error; |
99a0b768 | 1814 | if ((error = snd_ad1848_mixer(codec)) < 0) |
1da177e4 | 1815 | return error; |
1da177e4 LT |
1816 | #endif |
1817 | strcpy(card->driver, chip->name); | |
1818 | sprintf(card->shortname, "OPTi %s", card->driver); | |
1819 | #if defined(CS4231) || defined(OPTi93X) | |
1820 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", | |
1821 | card->shortname, pcm->name, chip->wss_base + 4, | |
1822 | chip->irq, chip->dma1, chip->dma2); | |
1823 | #else | |
1824 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", | |
1825 | card->shortname, pcm->name, chip->wss_base + 4, | |
1826 | chip->irq, chip->dma1); | |
1827 | #endif /* CS4231 || OPTi93X */ | |
1828 | ||
1829 | if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT) | |
1830 | rmidi = NULL; | |
1831 | else | |
1832 | if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, | |
65ca68b3 | 1833 | chip->mpu_port, 0, chip->mpu_irq, IRQF_DISABLED, |
1da177e4 | 1834 | &rmidi))) |
99a0b768 TI |
1835 | snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", |
1836 | chip->mpu_port); | |
1da177e4 LT |
1837 | |
1838 | if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { | |
346c7a68 | 1839 | struct snd_opl3 *opl3 = NULL; |
1da177e4 LT |
1840 | #ifndef OPTi93X |
1841 | if (chip->hardware == OPTi9XX_HW_82C928 || | |
1842 | chip->hardware == OPTi9XX_HW_82C929 || | |
1843 | chip->hardware == OPTi9XX_HW_82C924) { | |
346c7a68 | 1844 | struct snd_opl4 *opl4; |
1da177e4 LT |
1845 | /* assume we have an OPL4 */ |
1846 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), | |
1847 | 0x20, 0x20); | |
1848 | if (snd_opl4_create(card, | |
1849 | chip->fm_port, | |
1850 | chip->fm_port - 8, | |
1851 | 2, &opl3, &opl4) < 0) { | |
1852 | /* no luck, use OPL3 instead */ | |
1853 | snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), | |
1854 | 0x00, 0x20); | |
1855 | } | |
1856 | } | |
1857 | #endif /* !OPTi93X */ | |
1858 | if (!opl3 && snd_opl3_create(card, | |
1859 | chip->fm_port, | |
1860 | chip->fm_port + 2, | |
1861 | OPL3_HW_AUTO, 0, &opl3) < 0) { | |
99a0b768 | 1862 | snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", |
1da177e4 LT |
1863 | chip->fm_port, chip->fm_port + 4 - 1); |
1864 | } | |
1865 | if (opl3) { | |
1da177e4 | 1866 | #ifdef CS4231 |
99a0b768 | 1867 | const int t1dev = 1; |
1da177e4 | 1868 | #else |
99a0b768 TI |
1869 | const int t1dev = 0; |
1870 | #endif | |
1871 | if ((error = snd_opl3_timer_new(opl3, t1dev, t1dev+1)) < 0) | |
1da177e4 | 1872 | return error; |
99a0b768 | 1873 | if ((error = snd_opl3_hwdep_new(opl3, 0, 1, &synth)) < 0) |
1da177e4 | 1874 | return error; |
1da177e4 LT |
1875 | } |
1876 | } | |
1877 | ||
99a0b768 TI |
1878 | return snd_card_register(card); |
1879 | } | |
1880 | ||
1881 | static struct snd_card *snd_opti9xx_card_new(void) | |
1882 | { | |
1883 | struct snd_card *card; | |
1884 | ||
1885 | card = snd_card_new(index, id, THIS_MODULE, sizeof(struct snd_opti9xx)); | |
1886 | if (! card) | |
1887 | return NULL; | |
1888 | card->private_free = snd_card_opti9xx_free; | |
1889 | return card; | |
1890 | } | |
1891 | ||
5e24c1c1 TI |
1892 | static int __devinit snd_opti9xx_isa_match(struct device *devptr, |
1893 | unsigned int dev) | |
1894 | { | |
101f6f4b | 1895 | #ifdef CONFIG_PNP |
5e24c1c1 TI |
1896 | if (snd_opti9xx_pnp_is_probed) |
1897 | return 0; | |
1898 | if (isapnp) | |
1899 | return 0; | |
101f6f4b | 1900 | #endif |
5e24c1c1 TI |
1901 | return 1; |
1902 | } | |
1903 | ||
1904 | static int __devinit snd_opti9xx_isa_probe(struct device *devptr, | |
1905 | unsigned int dev) | |
99a0b768 TI |
1906 | { |
1907 | struct snd_card *card; | |
1908 | int error; | |
1909 | static long possible_mpu_ports[] = {0x300, 0x310, 0x320, 0x330, -1}; | |
1910 | #ifdef OPTi93X | |
1911 | static int possible_irqs[] = {5, 9, 10, 11, 7, -1}; | |
1912 | #else | |
1913 | static int possible_irqs[] = {9, 10, 11, 7, -1}; | |
1914 | #endif /* OPTi93X */ | |
1915 | static int possible_mpu_irqs[] = {5, 9, 10, 7, -1}; | |
1916 | static int possible_dma1s[] = {3, 1, 0, -1}; | |
1917 | #if defined(CS4231) || defined(OPTi93X) | |
1918 | static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}}; | |
1919 | #endif /* CS4231 || OPTi93X */ | |
1920 | ||
99a0b768 TI |
1921 | if (mpu_port == SNDRV_AUTO_PORT) { |
1922 | if ((mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) { | |
1923 | snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); | |
1924 | return -EBUSY; | |
1925 | } | |
1926 | } | |
1927 | if (irq == SNDRV_AUTO_IRQ) { | |
1928 | if ((irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { | |
1929 | snd_printk(KERN_ERR "unable to find a free IRQ\n"); | |
1930 | return -EBUSY; | |
1931 | } | |
1932 | } | |
1933 | if (mpu_irq == SNDRV_AUTO_IRQ) { | |
1934 | if ((mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) { | |
1935 | snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n"); | |
1936 | return -EBUSY; | |
1937 | } | |
1938 | } | |
1939 | if (dma1 == SNDRV_AUTO_DMA) { | |
1940 | if ((dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) { | |
1941 | snd_printk(KERN_ERR "unable to find a free DMA1\n"); | |
1942 | return -EBUSY; | |
1943 | } | |
1944 | } | |
1945 | #if defined(CS4231) || defined(OPTi93X) | |
1946 | if (dma2 == SNDRV_AUTO_DMA) { | |
1947 | if ((dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4])) < 0) { | |
1948 | snd_printk("unable to find a free DMA2\n"); | |
1949 | return -EBUSY; | |
1950 | } | |
1951 | } | |
1952 | #endif | |
1953 | ||
1954 | card = snd_opti9xx_card_new(); | |
1955 | if (! card) | |
1956 | return -ENOMEM; | |
1957 | ||
1958 | if ((error = snd_card_opti9xx_detect(card, card->private_data)) < 0) { | |
1da177e4 LT |
1959 | snd_card_free(card); |
1960 | return error; | |
1961 | } | |
5e24c1c1 | 1962 | snd_card_set_dev(card, devptr); |
99a0b768 TI |
1963 | if ((error = snd_opti9xx_probe(card)) < 0) { |
1964 | snd_card_free(card); | |
1965 | return error; | |
1966 | } | |
5e24c1c1 | 1967 | dev_set_drvdata(devptr, card); |
99a0b768 TI |
1968 | return 0; |
1969 | } | |
1970 | ||
5e24c1c1 TI |
1971 | static int __devexit snd_opti9xx_isa_remove(struct device *devptr, |
1972 | unsigned int dev) | |
99a0b768 | 1973 | { |
5e24c1c1 TI |
1974 | snd_card_free(dev_get_drvdata(devptr)); |
1975 | dev_set_drvdata(devptr, NULL); | |
1da177e4 LT |
1976 | return 0; |
1977 | } | |
1978 | ||
5e24c1c1 TI |
1979 | static struct isa_driver snd_opti9xx_driver = { |
1980 | .match = snd_opti9xx_isa_match, | |
1981 | .probe = snd_opti9xx_isa_probe, | |
1982 | .remove = __devexit_p(snd_opti9xx_isa_remove), | |
99a0b768 TI |
1983 | /* FIXME: suspend/resume */ |
1984 | .driver = { | |
83c51c0a | 1985 | .name = DEV_NAME |
99a0b768 TI |
1986 | }, |
1987 | }; | |
1988 | ||
1da177e4 | 1989 | #ifdef CONFIG_PNP |
5e24c1c1 TI |
1990 | static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, |
1991 | const struct pnp_card_device_id *pid) | |
1da177e4 | 1992 | { |
99a0b768 TI |
1993 | struct snd_card *card; |
1994 | int error, hw; | |
1995 | struct snd_opti9xx *chip; | |
1996 | ||
1997 | if (snd_opti9xx_pnp_is_probed) | |
1998 | return -EBUSY; | |
1999 | if (! isapnp) | |
2000 | return -ENODEV; | |
2001 | card = snd_opti9xx_card_new(); | |
2002 | if (! card) | |
2003 | return -ENOMEM; | |
2004 | chip = card->private_data; | |
1da177e4 | 2005 | |
99a0b768 TI |
2006 | hw = snd_card_opti9xx_pnp(chip, pcard, pid); |
2007 | switch (hw) { | |
2008 | case 0x0924: | |
2009 | hw = OPTi9XX_HW_82C924; | |
2010 | break; | |
2011 | case 0x0925: | |
2012 | hw = OPTi9XX_HW_82C925; | |
2013 | break; | |
2014 | case 0x0931: | |
2015 | hw = OPTi9XX_HW_82C931; | |
2016 | break; | |
2017 | default: | |
2018 | snd_card_free(card); | |
2019 | return -ENODEV; | |
2020 | } | |
2021 | ||
2022 | if ((error = snd_opti9xx_init(chip, hw))) { | |
2023 | snd_card_free(card); | |
2024 | return error; | |
2025 | } | |
2026 | if (hw <= OPTi9XX_HW_82C930) | |
2027 | chip->mc_base -= 0x80; | |
2028 | snd_card_set_dev(card, &pcard->card->dev); | |
2029 | if ((error = snd_opti9xx_probe(card)) < 0) { | |
2030 | snd_card_free(card); | |
2031 | return error; | |
2032 | } | |
2033 | pnp_set_card_drvdata(pcard, card); | |
2034 | snd_opti9xx_pnp_is_probed = 1; | |
2035 | return 0; | |
2036 | } | |
2037 | ||
2038 | static void __devexit snd_opti9xx_pnp_remove(struct pnp_card_link * pcard) | |
2039 | { | |
2040 | snd_card_free(pnp_get_card_drvdata(pcard)); | |
2041 | pnp_set_card_drvdata(pcard, NULL); | |
2042 | snd_opti9xx_pnp_is_probed = 0; | |
1da177e4 LT |
2043 | } |
2044 | ||
2045 | static struct pnp_card_driver opti9xx_pnpc_driver = { | |
2046 | .flags = PNP_DRIVER_RES_DISABLE, | |
2047 | .name = "opti9xx", | |
2048 | .id_table = snd_opti9xx_pnpids, | |
99a0b768 | 2049 | .probe = snd_opti9xx_pnp_probe, |
1da177e4 LT |
2050 | .remove = __devexit_p(snd_opti9xx_pnp_remove), |
2051 | }; | |
2052 | #endif | |
2053 | ||
1da177e4 | 2054 | #ifdef OPTi93X |
99a0b768 | 2055 | #define CHIP_NAME "82C93x" |
1da177e4 | 2056 | #else |
99a0b768 | 2057 | #define CHIP_NAME "82C92x" |
1da177e4 | 2058 | #endif |
99a0b768 TI |
2059 | |
2060 | static int __init alsa_card_opti9xx_init(void) | |
2061 | { | |
0bbbc4ca | 2062 | #ifdef CONFIG_PNP |
99a0b768 TI |
2063 | pnp_register_card_driver(&opti9xx_pnpc_driver); |
2064 | if (snd_opti9xx_pnp_is_probed) | |
2065 | return 0; | |
101f6f4b | 2066 | pnp_unregister_card_driver(&opti9xx_pnpc_driver); |
0bbbc4ca | 2067 | #endif |
5e24c1c1 | 2068 | return isa_register_driver(&snd_opti9xx_driver, 1); |
1da177e4 LT |
2069 | } |
2070 | ||
2071 | static void __exit alsa_card_opti9xx_exit(void) | |
2072 | { | |
f7a9275d | 2073 | if (!snd_opti9xx_pnp_is_probed) { |
5e24c1c1 TI |
2074 | isa_unregister_driver(&snd_opti9xx_driver); |
2075 | return; | |
f7a9275d | 2076 | } |
0bbbc4ca | 2077 | #ifdef CONFIG_PNP |
1da177e4 | 2078 | pnp_unregister_card_driver(&opti9xx_pnpc_driver); |
0bbbc4ca | 2079 | #endif |
1da177e4 LT |
2080 | } |
2081 | ||
2082 | module_init(alsa_card_opti9xx_init) | |
2083 | module_exit(alsa_card_opti9xx_exit) |