diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/pci/emu10k1 |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/pci/emu10k1')
-rw-r--r-- | sound/pci/emu10k1/Makefile | 23 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1.c | 240 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_callback.c | 540 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_main.c | 875 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_patch.c | 223 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_synth.c | 120 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1_synth_local.h | 38 | ||||
-rw-r--r-- | sound/pci/emu10k1/emu10k1x.c | 1643 | ||||
-rw-r--r-- | sound/pci/emu10k1/emufx.c | 2320 | ||||
-rw-r--r-- | sound/pci/emu10k1/emumixer.c | 955 | ||||
-rw-r--r-- | sound/pci/emu10k1/emumpu401.c | 374 | ||||
-rw-r--r-- | sound/pci/emu10k1/emupcm.c | 1724 | ||||
-rw-r--r-- | sound/pci/emu10k1/emuproc.c | 568 | ||||
-rw-r--r-- | sound/pci/emu10k1/io.c | 404 | ||||
-rw-r--r-- | sound/pci/emu10k1/irq.c | 189 | ||||
-rw-r--r-- | sound/pci/emu10k1/memory.c | 564 | ||||
-rw-r--r-- | sound/pci/emu10k1/p16v.c | 736 | ||||
-rw-r--r-- | sound/pci/emu10k1/p16v.h | 299 | ||||
-rw-r--r-- | sound/pci/emu10k1/timer.c | 97 | ||||
-rw-r--r-- | sound/pci/emu10k1/voice.c | 152 |
20 files changed, 12084 insertions, 0 deletions
diff --git a/sound/pci/emu10k1/Makefile b/sound/pci/emu10k1/Makefile new file mode 100644 index 000000000000..e521c38cef45 --- /dev/null +++ b/sound/pci/emu10k1/Makefile | |||
@@ -0,0 +1,23 @@ | |||
1 | # | ||
2 | # Makefile for ALSA | ||
3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> | ||
4 | # | ||
5 | |||
6 | snd-emu10k1-objs := emu10k1.o emu10k1_main.o \ | ||
7 | irq.o memory.o voice.o emumpu401.o emupcm.o io.o \ | ||
8 | emuproc.o emumixer.o emufx.o timer.o p16v.o | ||
9 | snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o | ||
10 | snd-emu10k1x-objs := emu10k1x.o | ||
11 | |||
12 | # | ||
13 | # this function returns: | ||
14 | # "m" - CONFIG_SND_SEQUENCER is m | ||
15 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
16 | # otherwise parameter #1 value | ||
17 | # | ||
18 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
19 | |||
20 | # Toplevel Module Dependency | ||
21 | obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o | ||
22 | obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emu10k1-synth.o | ||
23 | obj-$(CONFIG_SND_EMU10K1X) += snd-emu10k1x.o | ||
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c new file mode 100644 index 000000000000..6446afe19d80 --- /dev/null +++ b/sound/pci/emu10k1/emu10k1.c | |||
@@ -0,0 +1,240 @@ | |||
1 | /* | ||
2 | * The driver for the EMU10K1 (SB Live!) based soundcards | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
4 | * | ||
5 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | ||
6 | * Added support for Audigy 2 Value. | ||
7 | * | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <sound/driver.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/time.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <sound/core.h> | ||
32 | #include <sound/emu10k1.h> | ||
33 | #include <sound/initval.h> | ||
34 | |||
35 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | ||
36 | MODULE_DESCRIPTION("EMU10K1"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS}," | ||
39 | "{Creative Labs,SB Audigy}}"); | ||
40 | |||
41 | #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) | ||
42 | #define ENABLE_SYNTH | ||
43 | #include <sound/emu10k1_synth.h> | ||
44 | #endif | ||
45 | |||
46 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
47 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
48 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | ||
49 | static int extin[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | ||
50 | static int extout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | ||
51 | static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; | ||
52 | static int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64}; | ||
53 | static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128}; | ||
54 | static int enable_ir[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | ||
55 | |||
56 | module_param_array(index, int, NULL, 0444); | ||
57 | MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard."); | ||
58 | module_param_array(id, charp, NULL, 0444); | ||
59 | MODULE_PARM_DESC(id, "ID string for the EMU10K1 soundcard."); | ||
60 | module_param_array(enable, bool, NULL, 0444); | ||
61 | MODULE_PARM_DESC(enable, "Enable the EMU10K1 soundcard."); | ||
62 | module_param_array(extin, int, NULL, 0444); | ||
63 | MODULE_PARM_DESC(extin, "Available external inputs for FX8010. Zero=default."); | ||
64 | module_param_array(extout, int, NULL, 0444); | ||
65 | MODULE_PARM_DESC(extout, "Available external outputs for FX8010. Zero=default."); | ||
66 | module_param_array(seq_ports, int, NULL, 0444); | ||
67 | MODULE_PARM_DESC(seq_ports, "Allocated sequencer ports for internal synthesizer."); | ||
68 | module_param_array(max_synth_voices, int, NULL, 0444); | ||
69 | MODULE_PARM_DESC(max_synth_voices, "Maximum number of voices for WaveTable."); | ||
70 | module_param_array(max_buffer_size, int, NULL, 0444); | ||
71 | MODULE_PARM_DESC(max_buffer_size, "Maximum sample buffer size in MB."); | ||
72 | module_param_array(enable_ir, bool, NULL, 0444); | ||
73 | MODULE_PARM_DESC(enable_ir, "Enable IR."); | ||
74 | |||
75 | /* | ||
76 | * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 | ||
77 | */ | ||
78 | static struct pci_device_id snd_emu10k1_ids[] = { | ||
79 | { 0x1102, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* EMU10K1 */ | ||
80 | { 0x1102, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, /* Audigy */ | ||
81 | { 0x1102, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, /* Audigy 2 Value SB0400 */ | ||
82 | { 0, } | ||
83 | }; | ||
84 | |||
85 | /* | ||
86 | * Audigy 2 Value notes: | ||
87 | * A_IOCFG Input (GPIO) | ||
88 | * 0x400 = Front analog jack plugged in. (Green socket) | ||
89 | * 0x1000 = Read analog jack plugged in. (Black socket) | ||
90 | * 0x2000 = Center/LFE analog jack plugged in. (Orange socket) | ||
91 | * A_IOCFG Output (GPIO) | ||
92 | * 0x60 = Sound out of front Left. | ||
93 | * Win sets it to 0xXX61 | ||
94 | */ | ||
95 | |||
96 | MODULE_DEVICE_TABLE(pci, snd_emu10k1_ids); | ||
97 | |||
98 | static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, | ||
99 | const struct pci_device_id *pci_id) | ||
100 | { | ||
101 | static int dev; | ||
102 | snd_card_t *card; | ||
103 | emu10k1_t *emu; | ||
104 | #ifdef ENABLE_SYNTH | ||
105 | snd_seq_device_t *wave = NULL; | ||
106 | #endif | ||
107 | int err; | ||
108 | |||
109 | if (dev >= SNDRV_CARDS) | ||
110 | return -ENODEV; | ||
111 | if (!enable[dev]) { | ||
112 | dev++; | ||
113 | return -ENOENT; | ||
114 | } | ||
115 | |||
116 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
117 | if (card == NULL) | ||
118 | return -ENOMEM; | ||
119 | if (max_buffer_size[dev] < 32) | ||
120 | max_buffer_size[dev] = 32; | ||
121 | else if (max_buffer_size[dev] > 1024) | ||
122 | max_buffer_size[dev] = 1024; | ||
123 | if ((err = snd_emu10k1_create(card, pci, extin[dev], extout[dev], | ||
124 | (long)max_buffer_size[dev] * 1024 * 1024, | ||
125 | enable_ir[dev], | ||
126 | &emu)) < 0) { | ||
127 | snd_card_free(card); | ||
128 | return err; | ||
129 | } | ||
130 | if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0) { | ||
131 | snd_card_free(card); | ||
132 | return err; | ||
133 | } | ||
134 | if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0) { | ||
135 | snd_card_free(card); | ||
136 | return err; | ||
137 | } | ||
138 | if ((err = snd_emu10k1_pcm_efx(emu, 2, NULL)) < 0) { | ||
139 | snd_card_free(card); | ||
140 | return err; | ||
141 | } | ||
142 | /* This stores the periods table. */ | ||
143 | if (emu->audigy && emu->revision == 4) { /* P16V */ | ||
144 | if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 1024, &emu->p16v_buffer) < 0) { | ||
145 | snd_p16v_free(emu); | ||
146 | return -ENOMEM; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | if ((err = snd_emu10k1_mixer(emu)) < 0) { | ||
151 | snd_card_free(card); | ||
152 | return err; | ||
153 | } | ||
154 | |||
155 | if ((err = snd_emu10k1_timer(emu, 0)) < 0) { | ||
156 | snd_card_free(card); | ||
157 | return err; | ||
158 | } | ||
159 | |||
160 | if ((err = snd_emu10k1_pcm_multi(emu, 3, NULL)) < 0) { | ||
161 | snd_card_free(card); | ||
162 | return err; | ||
163 | } | ||
164 | if (emu->audigy && emu->revision == 4) { /* P16V */ | ||
165 | if ((err = snd_p16v_pcm(emu, 4, NULL)) < 0) { | ||
166 | snd_card_free(card); | ||
167 | return err; | ||
168 | } | ||
169 | } | ||
170 | if (emu->audigy) { | ||
171 | if ((err = snd_emu10k1_audigy_midi(emu)) < 0) { | ||
172 | snd_card_free(card); | ||
173 | return err; | ||
174 | } | ||
175 | } else { | ||
176 | if ((err = snd_emu10k1_midi(emu)) < 0) { | ||
177 | snd_card_free(card); | ||
178 | return err; | ||
179 | } | ||
180 | } | ||
181 | if ((err = snd_emu10k1_fx8010_new(emu, 0, NULL)) < 0) { | ||
182 | snd_card_free(card); | ||
183 | return err; | ||
184 | } | ||
185 | #ifdef ENABLE_SYNTH | ||
186 | if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, | ||
187 | sizeof(snd_emu10k1_synth_arg_t), &wave) < 0 || | ||
188 | wave == NULL) { | ||
189 | snd_printk("can't initialize Emu10k1 wavetable synth\n"); | ||
190 | } else { | ||
191 | snd_emu10k1_synth_arg_t *arg; | ||
192 | arg = SNDRV_SEQ_DEVICE_ARGPTR(wave); | ||
193 | strcpy(wave->name, "Emu-10k1 Synth"); | ||
194 | arg->hwptr = emu; | ||
195 | arg->index = 1; | ||
196 | arg->seq_ports = seq_ports[dev]; | ||
197 | arg->max_voices = max_synth_voices[dev]; | ||
198 | } | ||
199 | #endif | ||
200 | |||
201 | strcpy(card->driver, emu->card_capabilities->driver); | ||
202 | strcpy(card->shortname, emu->card_capabilities->name); | ||
203 | snprintf(card->longname, sizeof(card->longname), | ||
204 | "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i", | ||
205 | card->shortname, emu->revision, emu->serial, emu->port, emu->irq); | ||
206 | |||
207 | if ((err = snd_card_register(card)) < 0) { | ||
208 | snd_card_free(card); | ||
209 | return err; | ||
210 | } | ||
211 | pci_set_drvdata(pci, card); | ||
212 | dev++; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci) | ||
217 | { | ||
218 | snd_card_free(pci_get_drvdata(pci)); | ||
219 | pci_set_drvdata(pci, NULL); | ||
220 | } | ||
221 | |||
222 | static struct pci_driver driver = { | ||
223 | .name = "EMU10K1_Audigy", | ||
224 | .id_table = snd_emu10k1_ids, | ||
225 | .probe = snd_card_emu10k1_probe, | ||
226 | .remove = __devexit_p(snd_card_emu10k1_remove), | ||
227 | }; | ||
228 | |||
229 | static int __init alsa_card_emu10k1_init(void) | ||
230 | { | ||
231 | return pci_module_init(&driver); | ||
232 | } | ||
233 | |||
234 | static void __exit alsa_card_emu10k1_exit(void) | ||
235 | { | ||
236 | pci_unregister_driver(&driver); | ||
237 | } | ||
238 | |||
239 | module_init(alsa_card_emu10k1_init) | ||
240 | module_exit(alsa_card_emu10k1_exit) | ||
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c new file mode 100644 index 000000000000..7cf2f908eed9 --- /dev/null +++ b/sound/pci/emu10k1/emu10k1_callback.c | |||
@@ -0,0 +1,540 @@ | |||
1 | /* | ||
2 | * synth callback routines for Emu10k1 | ||
3 | * | ||
4 | * Copyright (C) 2000 Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "emu10k1_synth_local.h" | ||
22 | #include <sound/asoundef.h> | ||
23 | |||
24 | /* voice status */ | ||
25 | enum { | ||
26 | V_FREE=0, V_OFF, V_RELEASED, V_PLAYING, V_END | ||
27 | }; | ||
28 | |||
29 | /* Keeps track of what we are finding */ | ||
30 | typedef struct best_voice { | ||
31 | unsigned int time; | ||
32 | int voice; | ||
33 | } best_voice_t; | ||
34 | |||
35 | /* | ||
36 | * prototypes | ||
37 | */ | ||
38 | static void lookup_voices(snd_emux_t *emu, emu10k1_t *hw, best_voice_t *best, int active_only); | ||
39 | static snd_emux_voice_t *get_voice(snd_emux_t *emu, snd_emux_port_t *port); | ||
40 | static int start_voice(snd_emux_voice_t *vp); | ||
41 | static void trigger_voice(snd_emux_voice_t *vp); | ||
42 | static void release_voice(snd_emux_voice_t *vp); | ||
43 | static void update_voice(snd_emux_voice_t *vp, int update); | ||
44 | static void terminate_voice(snd_emux_voice_t *vp); | ||
45 | static void free_voice(snd_emux_voice_t *vp); | ||
46 | |||
47 | static void set_fmmod(emu10k1_t *hw, snd_emux_voice_t *vp); | ||
48 | static void set_fm2frq2(emu10k1_t *hw, snd_emux_voice_t *vp); | ||
49 | static void set_filterQ(emu10k1_t *hw, snd_emux_voice_t *vp); | ||
50 | |||
51 | /* | ||
52 | * Ensure a value is between two points | ||
53 | * macro evaluates its args more than once, so changed to upper-case. | ||
54 | */ | ||
55 | #define LIMITVALUE(x, a, b) do { if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b); } while (0) | ||
56 | #define LIMITMAX(x, a) do {if ((x) > (a)) (x) = (a); } while (0) | ||
57 | |||
58 | |||
59 | /* | ||
60 | * set up operators | ||
61 | */ | ||
62 | static snd_emux_operators_t emu10k1_ops = { | ||
63 | .owner = THIS_MODULE, | ||
64 | .get_voice = get_voice, | ||
65 | .prepare = start_voice, | ||
66 | .trigger = trigger_voice, | ||
67 | .release = release_voice, | ||
68 | .update = update_voice, | ||
69 | .terminate = terminate_voice, | ||
70 | .free_voice = free_voice, | ||
71 | .sample_new = snd_emu10k1_sample_new, | ||
72 | .sample_free = snd_emu10k1_sample_free, | ||
73 | }; | ||
74 | |||
75 | void | ||
76 | snd_emu10k1_ops_setup(snd_emux_t *emu) | ||
77 | { | ||
78 | emu->ops = emu10k1_ops; | ||
79 | } | ||
80 | |||
81 | |||
82 | /* | ||
83 | * get more voice for pcm | ||
84 | * | ||
85 | * terminate most inactive voice and give it as a pcm voice. | ||
86 | */ | ||
87 | int | ||
88 | snd_emu10k1_synth_get_voice(emu10k1_t *hw) | ||
89 | { | ||
90 | snd_emux_t *emu; | ||
91 | snd_emux_voice_t *vp; | ||
92 | best_voice_t best[V_END]; | ||
93 | unsigned long flags; | ||
94 | int i; | ||
95 | |||
96 | emu = hw->synth; | ||
97 | |||
98 | spin_lock_irqsave(&emu->voice_lock, flags); | ||
99 | lookup_voices(emu, hw, best, 1); /* no OFF voices */ | ||
100 | for (i = 0; i < V_END; i++) { | ||
101 | if (best[i].voice >= 0) { | ||
102 | int ch; | ||
103 | vp = &emu->voices[best[i].voice]; | ||
104 | if ((ch = vp->ch) < 0) { | ||
105 | //printk("synth_get_voice: ch < 0 (%d) ??", i); | ||
106 | continue; | ||
107 | } | ||
108 | vp->emu->num_voices--; | ||
109 | vp->ch = -1; | ||
110 | vp->state = SNDRV_EMUX_ST_OFF; | ||
111 | spin_unlock_irqrestore(&emu->voice_lock, flags); | ||
112 | return ch; | ||
113 | } | ||
114 | } | ||
115 | spin_unlock_irqrestore(&emu->voice_lock, flags); | ||
116 | |||
117 | /* not found */ | ||
118 | return -ENOMEM; | ||
119 | } | ||
120 | |||
121 | |||
122 | /* | ||
123 | * turn off the voice (not terminated) | ||
124 | */ | ||
125 | static void | ||
126 | release_voice(snd_emux_voice_t *vp) | ||
127 | { | ||
128 | int dcysusv; | ||
129 | emu10k1_t *hw; | ||
130 | |||
131 | hw = vp->hw; | ||
132 | dcysusv = 0x8000 | (unsigned char)vp->reg.parm.modrelease; | ||
133 | snd_emu10k1_ptr_write(hw, DCYSUSM, vp->ch, dcysusv); | ||
134 | dcysusv = 0x8000 | (unsigned char)vp->reg.parm.volrelease | DCYSUSV_CHANNELENABLE_MASK; | ||
135 | snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, dcysusv); | ||
136 | } | ||
137 | |||
138 | |||
139 | /* | ||
140 | * terminate the voice | ||
141 | */ | ||
142 | static void | ||
143 | terminate_voice(snd_emux_voice_t *vp) | ||
144 | { | ||
145 | emu10k1_t *hw; | ||
146 | |||
147 | snd_assert(vp, return); | ||
148 | hw = vp->hw; | ||
149 | snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); | ||
150 | if (vp->block) { | ||
151 | emu10k1_memblk_t *emem; | ||
152 | emem = (emu10k1_memblk_t *)vp->block; | ||
153 | if (emem->map_locked > 0) | ||
154 | emem->map_locked--; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * release the voice to system | ||
160 | */ | ||
161 | static void | ||
162 | free_voice(snd_emux_voice_t *vp) | ||
163 | { | ||
164 | emu10k1_t *hw; | ||
165 | |||
166 | hw = vp->hw; | ||
167 | if (vp->ch >= 0) { | ||
168 | snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00); | ||
169 | snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); | ||
170 | // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0); | ||
171 | snd_emu10k1_ptr_write(hw, VTFT, vp->ch, 0xffff); | ||
172 | snd_emu10k1_ptr_write(hw, CVCF, vp->ch, 0xffff); | ||
173 | snd_emu10k1_voice_free(hw, &hw->voices[vp->ch]); | ||
174 | vp->emu->num_voices--; | ||
175 | vp->ch = -1; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | |||
180 | /* | ||
181 | * update registers | ||
182 | */ | ||
183 | static void | ||
184 | update_voice(snd_emux_voice_t *vp, int update) | ||
185 | { | ||
186 | emu10k1_t *hw; | ||
187 | |||
188 | hw = vp->hw; | ||
189 | if (update & SNDRV_EMUX_UPDATE_VOLUME) | ||
190 | snd_emu10k1_ptr_write(hw, IFATN_ATTENUATION, vp->ch, vp->avol); | ||
191 | if (update & SNDRV_EMUX_UPDATE_PITCH) | ||
192 | snd_emu10k1_ptr_write(hw, IP, vp->ch, vp->apitch); | ||
193 | if (update & SNDRV_EMUX_UPDATE_PAN) { | ||
194 | snd_emu10k1_ptr_write(hw, PTRX_FXSENDAMOUNT_A, vp->ch, vp->apan); | ||
195 | snd_emu10k1_ptr_write(hw, PTRX_FXSENDAMOUNT_B, vp->ch, vp->aaux); | ||
196 | } | ||
197 | if (update & SNDRV_EMUX_UPDATE_FMMOD) | ||
198 | set_fmmod(hw, vp); | ||
199 | if (update & SNDRV_EMUX_UPDATE_TREMFREQ) | ||
200 | snd_emu10k1_ptr_write(hw, TREMFRQ, vp->ch, vp->reg.parm.tremfrq); | ||
201 | if (update & SNDRV_EMUX_UPDATE_FM2FRQ2) | ||
202 | set_fm2frq2(hw, vp); | ||
203 | if (update & SNDRV_EMUX_UPDATE_Q) | ||
204 | set_filterQ(hw, vp); | ||
205 | } | ||
206 | |||
207 | |||
208 | /* | ||
209 | * look up voice table - get the best voice in order of preference | ||
210 | */ | ||
211 | /* spinlock held! */ | ||
212 | static void | ||
213 | lookup_voices(snd_emux_t *emu, emu10k1_t *hw, best_voice_t *best, int active_only) | ||
214 | { | ||
215 | snd_emux_voice_t *vp; | ||
216 | best_voice_t *bp; | ||
217 | int i; | ||
218 | |||
219 | for (i = 0; i < V_END; i++) { | ||
220 | best[i].time = (unsigned int)-1; /* XXX MAX_?INT really */; | ||
221 | best[i].voice = -1; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Go through them all and get a best one to use. | ||
226 | * NOTE: could also look at volume and pick the quietest one. | ||
227 | */ | ||
228 | for (i = 0; i < emu->max_voices; i++) { | ||
229 | int state, val; | ||
230 | |||
231 | vp = &emu->voices[i]; | ||
232 | state = vp->state; | ||
233 | if (state == SNDRV_EMUX_ST_OFF) { | ||
234 | if (vp->ch < 0) { | ||
235 | if (active_only) | ||
236 | continue; | ||
237 | bp = best + V_FREE; | ||
238 | } else | ||
239 | bp = best + V_OFF; | ||
240 | } | ||
241 | else if (state == SNDRV_EMUX_ST_RELEASED || | ||
242 | state == SNDRV_EMUX_ST_PENDING) { | ||
243 | bp = best + V_RELEASED; | ||
244 | #if 0 | ||
245 | val = snd_emu10k1_ptr_read(hw, CVCF_CURRENTVOL, vp->ch); | ||
246 | if (! val) | ||
247 | bp = best + V_OFF; | ||
248 | #endif | ||
249 | } | ||
250 | else if (state == SNDRV_EMUX_ST_STANDBY) | ||
251 | continue; | ||
252 | else if (state & SNDRV_EMUX_ST_ON) | ||
253 | bp = best + V_PLAYING; | ||
254 | else | ||
255 | continue; | ||
256 | |||
257 | /* check if sample is finished playing (non-looping only) */ | ||
258 | if (bp != best + V_OFF && bp != best + V_FREE && | ||
259 | (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) { | ||
260 | val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch); | ||
261 | if (val >= vp->reg.loopstart) | ||
262 | bp = best + V_OFF; | ||
263 | } | ||
264 | |||
265 | if (vp->time < bp->time) { | ||
266 | bp->time = vp->time; | ||
267 | bp->voice = i; | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * get an empty voice | ||
274 | * | ||
275 | * emu->voice_lock is already held. | ||
276 | */ | ||
277 | static snd_emux_voice_t * | ||
278 | get_voice(snd_emux_t *emu, snd_emux_port_t *port) | ||
279 | { | ||
280 | emu10k1_t *hw; | ||
281 | snd_emux_voice_t *vp; | ||
282 | best_voice_t best[V_END]; | ||
283 | int i; | ||
284 | |||
285 | hw = emu->hw; | ||
286 | |||
287 | lookup_voices(emu, hw, best, 0); | ||
288 | for (i = 0; i < V_END; i++) { | ||
289 | if (best[i].voice >= 0) { | ||
290 | vp = &emu->voices[best[i].voice]; | ||
291 | if (vp->ch < 0) { | ||
292 | /* allocate a voice */ | ||
293 | emu10k1_voice_t *hwvoice; | ||
294 | if (snd_emu10k1_voice_alloc(hw, EMU10K1_SYNTH, 1, &hwvoice) < 0 || hwvoice == NULL) | ||
295 | continue; | ||
296 | vp->ch = hwvoice->number; | ||
297 | emu->num_voices++; | ||
298 | } | ||
299 | return vp; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | /* not found */ | ||
304 | return NULL; | ||
305 | } | ||
306 | |||
307 | /* | ||
308 | * prepare envelopes and LFOs | ||
309 | */ | ||
310 | static int | ||
311 | start_voice(snd_emux_voice_t *vp) | ||
312 | { | ||
313 | unsigned int temp; | ||
314 | int ch; | ||
315 | unsigned int addr, mapped_offset; | ||
316 | snd_midi_channel_t *chan; | ||
317 | emu10k1_t *hw; | ||
318 | emu10k1_memblk_t *emem; | ||
319 | |||
320 | hw = vp->hw; | ||
321 | ch = vp->ch; | ||
322 | snd_assert(ch >= 0, return -EINVAL); | ||
323 | chan = vp->chan; | ||
324 | |||
325 | emem = (emu10k1_memblk_t *)vp->block; | ||
326 | if (emem == NULL) | ||
327 | return -EINVAL; | ||
328 | emem->map_locked++; | ||
329 | if (snd_emu10k1_memblk_map(hw, emem) < 0) { | ||
330 | // printk("emu: cannot map!\n"); | ||
331 | return -ENOMEM; | ||
332 | } | ||
333 | mapped_offset = snd_emu10k1_memblk_offset(emem) >> 1; | ||
334 | vp->reg.start += mapped_offset; | ||
335 | vp->reg.end += mapped_offset; | ||
336 | vp->reg.loopstart += mapped_offset; | ||
337 | vp->reg.loopend += mapped_offset; | ||
338 | |||
339 | /* set channel routing */ | ||
340 | /* A = left(0), B = right(1), C = reverb(c), D = chorus(d) */ | ||
341 | if (hw->audigy) { | ||
342 | temp = FXBUS_MIDI_LEFT | (FXBUS_MIDI_RIGHT << 8) | | ||
343 | (FXBUS_MIDI_REVERB << 16) | (FXBUS_MIDI_CHORUS << 24); | ||
344 | snd_emu10k1_ptr_write(hw, A_FXRT1, ch, temp); | ||
345 | } else { | ||
346 | temp = (FXBUS_MIDI_LEFT << 16) | (FXBUS_MIDI_RIGHT << 20) | | ||
347 | (FXBUS_MIDI_REVERB << 24) | (FXBUS_MIDI_CHORUS << 28); | ||
348 | snd_emu10k1_ptr_write(hw, FXRT, ch, temp); | ||
349 | } | ||
350 | |||
351 | /* channel to be silent and idle */ | ||
352 | snd_emu10k1_ptr_write(hw, DCYSUSV, ch, 0x0080); | ||
353 | snd_emu10k1_ptr_write(hw, VTFT, ch, 0x0000FFFF); | ||
354 | snd_emu10k1_ptr_write(hw, CVCF, ch, 0x0000FFFF); | ||
355 | snd_emu10k1_ptr_write(hw, PTRX, ch, 0); | ||
356 | snd_emu10k1_ptr_write(hw, CPF, ch, 0); | ||
357 | |||
358 | /* set pitch offset */ | ||
359 | snd_emu10k1_ptr_write(hw, IP, vp->ch, vp->apitch); | ||
360 | |||
361 | /* set envelope parameters */ | ||
362 | snd_emu10k1_ptr_write(hw, ENVVAL, ch, vp->reg.parm.moddelay); | ||
363 | snd_emu10k1_ptr_write(hw, ATKHLDM, ch, vp->reg.parm.modatkhld); | ||
364 | snd_emu10k1_ptr_write(hw, DCYSUSM, ch, vp->reg.parm.moddcysus); | ||
365 | snd_emu10k1_ptr_write(hw, ENVVOL, ch, vp->reg.parm.voldelay); | ||
366 | snd_emu10k1_ptr_write(hw, ATKHLDV, ch, vp->reg.parm.volatkhld); | ||
367 | /* decay/sustain parameter for volume envelope is used | ||
368 | for triggerg the voice */ | ||
369 | |||
370 | /* cutoff and volume */ | ||
371 | temp = (unsigned int)vp->acutoff << 8 | (unsigned char)vp->avol; | ||
372 | snd_emu10k1_ptr_write(hw, IFATN, vp->ch, temp); | ||
373 | |||
374 | /* modulation envelope heights */ | ||
375 | snd_emu10k1_ptr_write(hw, PEFE, ch, vp->reg.parm.pefe); | ||
376 | |||
377 | /* lfo1/2 delay */ | ||
378 | snd_emu10k1_ptr_write(hw, LFOVAL1, ch, vp->reg.parm.lfo1delay); | ||
379 | snd_emu10k1_ptr_write(hw, LFOVAL2, ch, vp->reg.parm.lfo2delay); | ||
380 | |||
381 | /* lfo1 pitch & cutoff shift */ | ||
382 | set_fmmod(hw, vp); | ||
383 | /* lfo1 volume & freq */ | ||
384 | snd_emu10k1_ptr_write(hw, TREMFRQ, vp->ch, vp->reg.parm.tremfrq); | ||
385 | /* lfo2 pitch & freq */ | ||
386 | set_fm2frq2(hw, vp); | ||
387 | |||
388 | /* reverb and loop start (reverb 8bit, MSB) */ | ||
389 | temp = vp->reg.parm.reverb; | ||
390 | temp += (int)vp->chan->control[MIDI_CTL_E1_REVERB_DEPTH] * 9 / 10; | ||
391 | LIMITMAX(temp, 255); | ||
392 | addr = vp->reg.loopstart; | ||
393 | snd_emu10k1_ptr_write(hw, PSST, vp->ch, (temp << 24) | addr); | ||
394 | |||
395 | /* chorus & loop end (chorus 8bit, MSB) */ | ||
396 | addr = vp->reg.loopend; | ||
397 | temp = vp->reg.parm.chorus; | ||
398 | temp += (int)chan->control[MIDI_CTL_E3_CHORUS_DEPTH] * 9 / 10; | ||
399 | LIMITMAX(temp, 255); | ||
400 | temp = (temp <<24) | addr; | ||
401 | snd_emu10k1_ptr_write(hw, DSL, ch, temp); | ||
402 | |||
403 | /* clear filter delay memory */ | ||
404 | snd_emu10k1_ptr_write(hw, Z1, ch, 0); | ||
405 | snd_emu10k1_ptr_write(hw, Z2, ch, 0); | ||
406 | |||
407 | /* invalidate maps */ | ||
408 | temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK; | ||
409 | snd_emu10k1_ptr_write(hw, MAPA, ch, temp); | ||
410 | snd_emu10k1_ptr_write(hw, MAPB, ch, temp); | ||
411 | #if 0 | ||
412 | /* cache */ | ||
413 | { | ||
414 | unsigned int val, sample; | ||
415 | val = 32; | ||
416 | if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS) | ||
417 | sample = 0x80808080; | ||
418 | else { | ||
419 | sample = 0; | ||
420 | val *= 2; | ||
421 | } | ||
422 | |||
423 | /* cache */ | ||
424 | snd_emu10k1_ptr_write(hw, CCR, ch, 0x1c << 16); | ||
425 | snd_emu10k1_ptr_write(hw, CDE, ch, sample); | ||
426 | snd_emu10k1_ptr_write(hw, CDF, ch, sample); | ||
427 | |||
428 | /* invalidate maps */ | ||
429 | temp = ((unsigned int)hw->silent_page.addr << 1) | MAP_PTI_MASK; | ||
430 | snd_emu10k1_ptr_write(hw, MAPA, ch, temp); | ||
431 | snd_emu10k1_ptr_write(hw, MAPB, ch, temp); | ||
432 | |||
433 | /* fill cache */ | ||
434 | val -= 4; | ||
435 | val <<= 25; | ||
436 | val |= 0x1c << 16; | ||
437 | snd_emu10k1_ptr_write(hw, CCR, ch, val); | ||
438 | } | ||
439 | #endif | ||
440 | |||
441 | /* Q & current address (Q 4bit value, MSB) */ | ||
442 | addr = vp->reg.start; | ||
443 | temp = vp->reg.parm.filterQ; | ||
444 | temp = (temp<<28) | addr; | ||
445 | if (vp->apitch < 0xe400) | ||
446 | temp |= CCCA_INTERPROM_0; | ||
447 | else { | ||
448 | unsigned int shift = (vp->apitch - 0xe000) >> 10; | ||
449 | temp |= shift << 25; | ||
450 | } | ||
451 | if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS) | ||
452 | temp |= CCCA_8BITSELECT; | ||
453 | snd_emu10k1_ptr_write(hw, CCCA, ch, temp); | ||
454 | |||
455 | /* reset volume */ | ||
456 | temp = (unsigned int)vp->vtarget << 16; | ||
457 | snd_emu10k1_ptr_write(hw, VTFT, ch, temp | vp->ftarget); | ||
458 | snd_emu10k1_ptr_write(hw, CVCF, ch, temp | 0xff00); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | /* | ||
463 | * Start envelope | ||
464 | */ | ||
465 | static void | ||
466 | trigger_voice(snd_emux_voice_t *vp) | ||
467 | { | ||
468 | unsigned int temp, ptarget; | ||
469 | emu10k1_t *hw; | ||
470 | emu10k1_memblk_t *emem; | ||
471 | |||
472 | hw = vp->hw; | ||
473 | |||
474 | emem = (emu10k1_memblk_t *)vp->block; | ||
475 | if (! emem || emem->mapped_page < 0) | ||
476 | return; /* not mapped */ | ||
477 | |||
478 | #if 0 | ||
479 | ptarget = (unsigned int)vp->ptarget << 16; | ||
480 | #else | ||
481 | ptarget = IP_TO_CP(vp->apitch); | ||
482 | #endif | ||
483 | /* set pitch target and pan (volume) */ | ||
484 | temp = ptarget | (vp->apan << 8) | vp->aaux; | ||
485 | snd_emu10k1_ptr_write(hw, PTRX, vp->ch, temp); | ||
486 | |||
487 | /* pitch target */ | ||
488 | snd_emu10k1_ptr_write(hw, CPF, vp->ch, ptarget); | ||
489 | |||
490 | /* trigger voice */ | ||
491 | snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, vp->reg.parm.voldcysus|DCYSUSV_CHANNELENABLE_MASK); | ||
492 | } | ||
493 | |||
494 | #define MOD_SENSE 18 | ||
495 | |||
496 | /* set lfo1 modulation height and cutoff */ | ||
497 | static void | ||
498 | set_fmmod(emu10k1_t *hw, snd_emux_voice_t *vp) | ||
499 | { | ||
500 | unsigned short fmmod; | ||
501 | short pitch; | ||
502 | unsigned char cutoff; | ||
503 | int modulation; | ||
504 | |||
505 | pitch = (char)(vp->reg.parm.fmmod>>8); | ||
506 | cutoff = (vp->reg.parm.fmmod & 0xff); | ||
507 | modulation = vp->chan->gm_modulation + vp->chan->midi_pressure; | ||
508 | pitch += (MOD_SENSE * modulation) / 1200; | ||
509 | LIMITVALUE(pitch, -128, 127); | ||
510 | fmmod = ((unsigned char)pitch<<8) | cutoff; | ||
511 | snd_emu10k1_ptr_write(hw, FMMOD, vp->ch, fmmod); | ||
512 | } | ||
513 | |||
514 | /* set lfo2 pitch & frequency */ | ||
515 | static void | ||
516 | set_fm2frq2(emu10k1_t *hw, snd_emux_voice_t *vp) | ||
517 | { | ||
518 | unsigned short fm2frq2; | ||
519 | short pitch; | ||
520 | unsigned char freq; | ||
521 | int modulation; | ||
522 | |||
523 | pitch = (char)(vp->reg.parm.fm2frq2>>8); | ||
524 | freq = vp->reg.parm.fm2frq2 & 0xff; | ||
525 | modulation = vp->chan->gm_modulation + vp->chan->midi_pressure; | ||
526 | pitch += (MOD_SENSE * modulation) / 1200; | ||
527 | LIMITVALUE(pitch, -128, 127); | ||
528 | fm2frq2 = ((unsigned char)pitch<<8) | freq; | ||
529 | snd_emu10k1_ptr_write(hw, FM2FRQ2, vp->ch, fm2frq2); | ||
530 | } | ||
531 | |||
532 | /* set filterQ */ | ||
533 | static void | ||
534 | set_filterQ(emu10k1_t *hw, snd_emux_voice_t *vp) | ||
535 | { | ||
536 | unsigned int val; | ||
537 | val = snd_emu10k1_ptr_read(hw, CCCA, vp->ch) & ~CCCA_RESONANCE; | ||
538 | val |= (vp->reg.parm.filterQ << 28); | ||
539 | snd_emu10k1_ptr_write(hw, CCCA, vp->ch, val); | ||
540 | } | ||
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c new file mode 100644 index 000000000000..c3c96f9f2c7f --- /dev/null +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -0,0 +1,875 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Creative Labs, Inc. | ||
4 | * Routines for control of EMU10K1 chips | ||
5 | * | ||
6 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | ||
7 | * Added support for Audigy 2 Value. | ||
8 | * | ||
9 | * | ||
10 | * BUGS: | ||
11 | * -- | ||
12 | * | ||
13 | * TODO: | ||
14 | * -- | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * (at your option) any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <sound/driver.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/pci.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/vmalloc.h> | ||
39 | |||
40 | #include <sound/core.h> | ||
41 | #include <sound/emu10k1.h> | ||
42 | #include "p16v.h" | ||
43 | |||
44 | #if 0 | ||
45 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Creative Labs, Inc."); | ||
46 | MODULE_DESCRIPTION("Routines for control of EMU10K1 chips"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | #endif | ||
49 | |||
50 | /************************************************************************* | ||
51 | * EMU10K1 init / done | ||
52 | *************************************************************************/ | ||
53 | |||
54 | void snd_emu10k1_voice_init(emu10k1_t * emu, int ch) | ||
55 | { | ||
56 | snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); | ||
57 | snd_emu10k1_ptr_write(emu, IP, ch, 0); | ||
58 | snd_emu10k1_ptr_write(emu, VTFT, ch, 0xffff); | ||
59 | snd_emu10k1_ptr_write(emu, CVCF, ch, 0xffff); | ||
60 | snd_emu10k1_ptr_write(emu, PTRX, ch, 0); | ||
61 | snd_emu10k1_ptr_write(emu, CPF, ch, 0); | ||
62 | snd_emu10k1_ptr_write(emu, CCR, ch, 0); | ||
63 | |||
64 | snd_emu10k1_ptr_write(emu, PSST, ch, 0); | ||
65 | snd_emu10k1_ptr_write(emu, DSL, ch, 0x10); | ||
66 | snd_emu10k1_ptr_write(emu, CCCA, ch, 0); | ||
67 | snd_emu10k1_ptr_write(emu, Z1, ch, 0); | ||
68 | snd_emu10k1_ptr_write(emu, Z2, ch, 0); | ||
69 | snd_emu10k1_ptr_write(emu, FXRT, ch, 0x32100000); | ||
70 | |||
71 | snd_emu10k1_ptr_write(emu, ATKHLDM, ch, 0); | ||
72 | snd_emu10k1_ptr_write(emu, DCYSUSM, ch, 0); | ||
73 | snd_emu10k1_ptr_write(emu, IFATN, ch, 0xffff); | ||
74 | snd_emu10k1_ptr_write(emu, PEFE, ch, 0); | ||
75 | snd_emu10k1_ptr_write(emu, FMMOD, ch, 0); | ||
76 | snd_emu10k1_ptr_write(emu, TREMFRQ, ch, 24); /* 1 Hz */ | ||
77 | snd_emu10k1_ptr_write(emu, FM2FRQ2, ch, 24); /* 1 Hz */ | ||
78 | snd_emu10k1_ptr_write(emu, TEMPENV, ch, 0); | ||
79 | |||
80 | /*** these are last so OFF prevents writing ***/ | ||
81 | snd_emu10k1_ptr_write(emu, LFOVAL2, ch, 0); | ||
82 | snd_emu10k1_ptr_write(emu, LFOVAL1, ch, 0); | ||
83 | snd_emu10k1_ptr_write(emu, ATKHLDV, ch, 0); | ||
84 | snd_emu10k1_ptr_write(emu, ENVVOL, ch, 0); | ||
85 | snd_emu10k1_ptr_write(emu, ENVVAL, ch, 0); | ||
86 | |||
87 | /* Audigy extra stuffs */ | ||
88 | if (emu->audigy) { | ||
89 | snd_emu10k1_ptr_write(emu, 0x4c, ch, 0); /* ?? */ | ||
90 | snd_emu10k1_ptr_write(emu, 0x4d, ch, 0); /* ?? */ | ||
91 | snd_emu10k1_ptr_write(emu, 0x4e, ch, 0); /* ?? */ | ||
92 | snd_emu10k1_ptr_write(emu, 0x4f, ch, 0); /* ?? */ | ||
93 | snd_emu10k1_ptr_write(emu, A_FXRT1, ch, 0x03020100); | ||
94 | snd_emu10k1_ptr_write(emu, A_FXRT2, ch, 0x3f3f3f3f); | ||
95 | snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, ch, 0); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | static int __devinit snd_emu10k1_init(emu10k1_t * emu, int enable_ir) | ||
100 | { | ||
101 | int ch, idx, err; | ||
102 | unsigned int silent_page; | ||
103 | |||
104 | emu->fx8010.itram_size = (16 * 1024)/2; | ||
105 | emu->fx8010.etram_pages.area = NULL; | ||
106 | emu->fx8010.etram_pages.bytes = 0; | ||
107 | |||
108 | /* disable audio and lock cache */ | ||
109 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); | ||
110 | |||
111 | /* reset recording buffers */ | ||
112 | snd_emu10k1_ptr_write(emu, MICBS, 0, ADCBS_BUFSIZE_NONE); | ||
113 | snd_emu10k1_ptr_write(emu, MICBA, 0, 0); | ||
114 | snd_emu10k1_ptr_write(emu, FXBS, 0, ADCBS_BUFSIZE_NONE); | ||
115 | snd_emu10k1_ptr_write(emu, FXBA, 0, 0); | ||
116 | snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE); | ||
117 | snd_emu10k1_ptr_write(emu, ADCBA, 0, 0); | ||
118 | |||
119 | /* disable channel interrupt */ | ||
120 | outl(0, emu->port + INTE); | ||
121 | snd_emu10k1_ptr_write(emu, CLIEL, 0, 0); | ||
122 | snd_emu10k1_ptr_write(emu, CLIEH, 0, 0); | ||
123 | snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); | ||
124 | snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); | ||
125 | |||
126 | if (emu->audigy){ | ||
127 | /* set SPDIF bypass mode */ | ||
128 | snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT); | ||
129 | /* enable rear left + rear right AC97 slots */ | ||
130 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_REAR_RIGHT | AC97SLOT_REAR_LEFT); | ||
131 | } | ||
132 | |||
133 | /* init envelope engine */ | ||
134 | for (ch = 0; ch < NUM_G; ch++) { | ||
135 | emu->voices[ch].emu = emu; | ||
136 | emu->voices[ch].number = ch; | ||
137 | snd_emu10k1_voice_init(emu, ch); | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | * Init to 0x02109204 : | ||
142 | * Clock accuracy = 0 (1000ppm) | ||
143 | * Sample Rate = 2 (48kHz) | ||
144 | * Audio Channel = 1 (Left of 2) | ||
145 | * Source Number = 0 (Unspecified) | ||
146 | * Generation Status = 1 (Original for Cat Code 12) | ||
147 | * Cat Code = 12 (Digital Signal Mixer) | ||
148 | * Mode = 0 (Mode 0) | ||
149 | * Emphasis = 0 (None) | ||
150 | * CP = 1 (Copyright unasserted) | ||
151 | * AN = 0 (Audio data) | ||
152 | * P = 0 (Consumer) | ||
153 | */ | ||
154 | snd_emu10k1_ptr_write(emu, SPCS0, 0, | ||
155 | emu->spdif_bits[0] = | ||
156 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
157 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
158 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
159 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
160 | snd_emu10k1_ptr_write(emu, SPCS1, 0, | ||
161 | emu->spdif_bits[1] = | ||
162 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
163 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
164 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
165 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
166 | snd_emu10k1_ptr_write(emu, SPCS2, 0, | ||
167 | emu->spdif_bits[2] = | ||
168 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
169 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
170 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
171 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
172 | |||
173 | if (emu->audigy && emu->revision == 4) { /* audigy2 */ | ||
174 | /* Hacks for Alice3 to work independent of haP16V driver */ | ||
175 | u32 tmp; | ||
176 | |||
177 | //Setup SRCMulti_I2S SamplingRate | ||
178 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | ||
179 | tmp &= 0xfffff1ff; | ||
180 | tmp |= (0x2<<9); | ||
181 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); | ||
182 | |||
183 | /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ | ||
184 | snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14); | ||
185 | /* Setup SRCMulti Input Audio Enable */ | ||
186 | /* Use 0xFFFFFFFF to enable P16V sounds. */ | ||
187 | snd_emu10k1_ptr20_write(emu, SRCMULTI_ENABLE, 0, 0xFFFFFFFF); | ||
188 | |||
189 | /* Enabled Phased (8-channel) P16V playback */ | ||
190 | outl(0x0201, emu->port + HCFG2); | ||
191 | /* Set playback routing. */ | ||
192 | snd_emu10k1_ptr_write(emu, CAPTURE_P16V_SOURCE, 0, 78e4); | ||
193 | } | ||
194 | if (emu->audigy && (emu->serial == 0x10011102) ) { /* audigy2 Value */ | ||
195 | /* Hacks for Alice3 to work independent of haP16V driver */ | ||
196 | u32 tmp; | ||
197 | |||
198 | snd_printk(KERN_ERR "Audigy2 value:Special config.\n"); | ||
199 | //Setup SRCMulti_I2S SamplingRate | ||
200 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | ||
201 | tmp &= 0xfffff1ff; | ||
202 | tmp |= (0x2<<9); | ||
203 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); | ||
204 | |||
205 | /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */ | ||
206 | outl(0x600000, emu->port + 0x20); | ||
207 | outl(0x14, emu->port + 0x24); | ||
208 | |||
209 | /* Setup SRCMulti Input Audio Enable */ | ||
210 | outl(0x7b0000, emu->port + 0x20); | ||
211 | outl(0xFF000000, emu->port + 0x24); | ||
212 | |||
213 | /* Setup SPDIF Out Audio Enable */ | ||
214 | /* The Audigy 2 Value has a separate SPDIF out, | ||
215 | * so no need for a mixer switch | ||
216 | */ | ||
217 | outl(0x7a0000, emu->port + 0x20); | ||
218 | outl(0xFF000000, emu->port + 0x24); | ||
219 | tmp = inl(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */ | ||
220 | outl(tmp, emu->port + A_IOCFG); | ||
221 | } | ||
222 | |||
223 | |||
224 | /* | ||
225 | * Clear page with silence & setup all pointers to this page | ||
226 | */ | ||
227 | memset(emu->silent_page.area, 0, PAGE_SIZE); | ||
228 | silent_page = emu->silent_page.addr << 1; | ||
229 | for (idx = 0; idx < MAXPAGES; idx++) | ||
230 | ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); | ||
231 | snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); | ||
232 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ | ||
233 | snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ | ||
234 | |||
235 | silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK; | ||
236 | for (ch = 0; ch < NUM_G; ch++) { | ||
237 | snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page); | ||
238 | snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * Hokay, setup HCFG | ||
243 | * Mute Disable Audio = 0 | ||
244 | * Lock Tank Memory = 1 | ||
245 | * Lock Sound Memory = 0 | ||
246 | * Auto Mute = 1 | ||
247 | */ | ||
248 | if (emu->audigy) { | ||
249 | if (emu->revision == 4) /* audigy2 */ | ||
250 | outl(HCFG_AUDIOENABLE | | ||
251 | HCFG_AC3ENABLE_CDSPDIF | | ||
252 | HCFG_AC3ENABLE_GPSPDIF | | ||
253 | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); | ||
254 | else | ||
255 | outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); | ||
256 | } else if (emu->model == 0x20 || | ||
257 | emu->model == 0xc400 || | ||
258 | (emu->model == 0x21 && emu->revision < 6)) | ||
259 | outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG); | ||
260 | else | ||
261 | // With on-chip joystick | ||
262 | outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG); | ||
263 | |||
264 | if (enable_ir) { /* enable IR for SB Live */ | ||
265 | if (emu->audigy) { | ||
266 | unsigned int reg = inl(emu->port + A_IOCFG); | ||
267 | outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); | ||
268 | udelay(500); | ||
269 | outl(reg | A_IOCFG_GPOUT1 | A_IOCFG_GPOUT2, emu->port + A_IOCFG); | ||
270 | udelay(100); | ||
271 | outl(reg, emu->port + A_IOCFG); | ||
272 | } else { | ||
273 | unsigned int reg = inl(emu->port + HCFG); | ||
274 | outl(reg | HCFG_GPOUT2, emu->port + HCFG); | ||
275 | udelay(500); | ||
276 | outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG); | ||
277 | udelay(100); | ||
278 | outl(reg, emu->port + HCFG); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | if (emu->audigy) { /* enable analog output */ | ||
283 | unsigned int reg = inl(emu->port + A_IOCFG); | ||
284 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Initialize the effect engine | ||
289 | */ | ||
290 | if ((err = snd_emu10k1_init_efx(emu)) < 0) | ||
291 | return err; | ||
292 | |||
293 | /* | ||
294 | * Enable the audio bit | ||
295 | */ | ||
296 | outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG); | ||
297 | |||
298 | /* Enable analog/digital outs on audigy */ | ||
299 | if (emu->audigy) { | ||
300 | outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); | ||
301 | |||
302 | if (emu->revision == 4) { /* audigy2 */ | ||
303 | /* Unmute Analog now. Set GPO6 to 1 for Apollo. | ||
304 | * This has to be done after init ALice3 I2SOut beyond 48KHz. | ||
305 | * So, sequence is important. */ | ||
306 | outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG); | ||
307 | } else if (emu->serial == 0x10011102) { /* audigy2 value */ | ||
308 | /* Unmute Analog now. */ | ||
309 | outl(inl(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG); | ||
310 | } else { | ||
311 | /* Disable routing from AC97 line out to Front speakers */ | ||
312 | outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | #if 0 | ||
317 | { | ||
318 | unsigned int tmp; | ||
319 | /* FIXME: the following routine disables LiveDrive-II !! */ | ||
320 | // TOSLink detection | ||
321 | emu->tos_link = 0; | ||
322 | tmp = inl(emu->port + HCFG); | ||
323 | if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) { | ||
324 | outl(tmp|0x800, emu->port + HCFG); | ||
325 | udelay(50); | ||
326 | if (tmp != (inl(emu->port + HCFG) & ~0x800)) { | ||
327 | emu->tos_link = 1; | ||
328 | outl(tmp, emu->port + HCFG); | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | #endif | ||
333 | |||
334 | snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE); | ||
335 | |||
336 | emu->reserved_page = (emu10k1_memblk_t *)snd_emu10k1_synth_alloc(emu, 4096); | ||
337 | if (emu->reserved_page) | ||
338 | emu->reserved_page->map_locked = 1; | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int snd_emu10k1_done(emu10k1_t * emu) | ||
344 | { | ||
345 | int ch; | ||
346 | |||
347 | outl(0, emu->port + INTE); | ||
348 | |||
349 | /* | ||
350 | * Shutdown the chip | ||
351 | */ | ||
352 | for (ch = 0; ch < NUM_G; ch++) | ||
353 | snd_emu10k1_ptr_write(emu, DCYSUSV, ch, 0); | ||
354 | for (ch = 0; ch < NUM_G; ch++) { | ||
355 | snd_emu10k1_ptr_write(emu, VTFT, ch, 0); | ||
356 | snd_emu10k1_ptr_write(emu, CVCF, ch, 0); | ||
357 | snd_emu10k1_ptr_write(emu, PTRX, ch, 0); | ||
358 | snd_emu10k1_ptr_write(emu, CPF, ch, 0); | ||
359 | } | ||
360 | |||
361 | /* reset recording buffers */ | ||
362 | snd_emu10k1_ptr_write(emu, MICBS, 0, 0); | ||
363 | snd_emu10k1_ptr_write(emu, MICBA, 0, 0); | ||
364 | snd_emu10k1_ptr_write(emu, FXBS, 0, 0); | ||
365 | snd_emu10k1_ptr_write(emu, FXBA, 0, 0); | ||
366 | snd_emu10k1_ptr_write(emu, FXWC, 0, 0); | ||
367 | snd_emu10k1_ptr_write(emu, ADCBS, 0, ADCBS_BUFSIZE_NONE); | ||
368 | snd_emu10k1_ptr_write(emu, ADCBA, 0, 0); | ||
369 | snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_16K); | ||
370 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); | ||
371 | if (emu->audigy) | ||
372 | snd_emu10k1_ptr_write(emu, A_DBG, 0, A_DBG_SINGLE_STEP); | ||
373 | else | ||
374 | snd_emu10k1_ptr_write(emu, DBG, 0, EMU10K1_DBG_SINGLE_STEP); | ||
375 | |||
376 | /* disable channel interrupt */ | ||
377 | snd_emu10k1_ptr_write(emu, CLIEL, 0, 0); | ||
378 | snd_emu10k1_ptr_write(emu, CLIEH, 0, 0); | ||
379 | snd_emu10k1_ptr_write(emu, SOLEL, 0, 0); | ||
380 | snd_emu10k1_ptr_write(emu, SOLEH, 0, 0); | ||
381 | |||
382 | /* remove reserved page */ | ||
383 | if (emu->reserved_page != NULL) { | ||
384 | snd_emu10k1_synth_free(emu, (snd_util_memblk_t *)emu->reserved_page); | ||
385 | emu->reserved_page = NULL; | ||
386 | } | ||
387 | |||
388 | /* disable audio and lock cache */ | ||
389 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); | ||
390 | snd_emu10k1_ptr_write(emu, PTB, 0, 0); | ||
391 | |||
392 | snd_emu10k1_free_efx(emu); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | /************************************************************************* | ||
398 | * ECARD functional implementation | ||
399 | *************************************************************************/ | ||
400 | |||
401 | /* In A1 Silicon, these bits are in the HC register */ | ||
402 | #define HOOKN_BIT (1L << 12) | ||
403 | #define HANDN_BIT (1L << 11) | ||
404 | #define PULSEN_BIT (1L << 10) | ||
405 | |||
406 | #define EC_GDI1 (1 << 13) | ||
407 | #define EC_GDI0 (1 << 14) | ||
408 | |||
409 | #define EC_NUM_CONTROL_BITS 20 | ||
410 | |||
411 | #define EC_AC3_DATA_SELN 0x0001L | ||
412 | #define EC_EE_DATA_SEL 0x0002L | ||
413 | #define EC_EE_CNTRL_SELN 0x0004L | ||
414 | #define EC_EECLK 0x0008L | ||
415 | #define EC_EECS 0x0010L | ||
416 | #define EC_EESDO 0x0020L | ||
417 | #define EC_TRIM_CSN 0x0040L | ||
418 | #define EC_TRIM_SCLK 0x0080L | ||
419 | #define EC_TRIM_SDATA 0x0100L | ||
420 | #define EC_TRIM_MUTEN 0x0200L | ||
421 | #define EC_ADCCAL 0x0400L | ||
422 | #define EC_ADCRSTN 0x0800L | ||
423 | #define EC_DACCAL 0x1000L | ||
424 | #define EC_DACMUTEN 0x2000L | ||
425 | #define EC_LEDN 0x4000L | ||
426 | |||
427 | #define EC_SPDIF0_SEL_SHIFT 15 | ||
428 | #define EC_SPDIF1_SEL_SHIFT 17 | ||
429 | #define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT) | ||
430 | #define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT) | ||
431 | #define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK) | ||
432 | #define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK) | ||
433 | #define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory. This should | ||
434 | * be incremented any time the EEPROM's | ||
435 | * format is changed. */ | ||
436 | |||
437 | #define EC_EEPROM_SIZE 0x40 /* ECARD EEPROM has 64 16-bit words */ | ||
438 | |||
439 | /* Addresses for special values stored in to EEPROM */ | ||
440 | #define EC_PROM_VERSION_ADDR 0x20 /* Address of the current prom version */ | ||
441 | #define EC_BOARDREV0_ADDR 0x21 /* LSW of board rev */ | ||
442 | #define EC_BOARDREV1_ADDR 0x22 /* MSW of board rev */ | ||
443 | |||
444 | #define EC_LAST_PROMFILE_ADDR 0x2f | ||
445 | |||
446 | #define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The | ||
447 | * can be up to 30 characters in length | ||
448 | * and is stored as a NULL-terminated | ||
449 | * ASCII string. Any unused bytes must be | ||
450 | * filled with zeros */ | ||
451 | #define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */ | ||
452 | |||
453 | |||
454 | /* Most of this stuff is pretty self-evident. According to the hardware | ||
455 | * dudes, we need to leave the ADCCAL bit low in order to avoid a DC | ||
456 | * offset problem. Weird. | ||
457 | */ | ||
458 | #define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | \ | ||
459 | EC_TRIM_CSN) | ||
460 | |||
461 | |||
462 | #define EC_DEFAULT_ADC_GAIN 0xC4C4 | ||
463 | #define EC_DEFAULT_SPDIF0_SEL 0x0 | ||
464 | #define EC_DEFAULT_SPDIF1_SEL 0x4 | ||
465 | |||
466 | /************************************************************************** | ||
467 | * @func Clock bits into the Ecard's control latch. The Ecard uses a | ||
468 | * control latch will is loaded bit-serially by toggling the Modem control | ||
469 | * lines from function 2 on the E8010. This function hides these details | ||
470 | * and presents the illusion that we are actually writing to a distinct | ||
471 | * register. | ||
472 | */ | ||
473 | |||
474 | static void snd_emu10k1_ecard_write(emu10k1_t * emu, unsigned int value) | ||
475 | { | ||
476 | unsigned short count; | ||
477 | unsigned int data; | ||
478 | unsigned long hc_port; | ||
479 | unsigned int hc_value; | ||
480 | |||
481 | hc_port = emu->port + HCFG; | ||
482 | hc_value = inl(hc_port) & ~(HOOKN_BIT | HANDN_BIT | PULSEN_BIT); | ||
483 | outl(hc_value, hc_port); | ||
484 | |||
485 | for (count = 0; count < EC_NUM_CONTROL_BITS; count++) { | ||
486 | |||
487 | /* Set up the value */ | ||
488 | data = ((value & 0x1) ? PULSEN_BIT : 0); | ||
489 | value >>= 1; | ||
490 | |||
491 | outl(hc_value | data, hc_port); | ||
492 | |||
493 | /* Clock the shift register */ | ||
494 | outl(hc_value | data | HANDN_BIT, hc_port); | ||
495 | outl(hc_value | data, hc_port); | ||
496 | } | ||
497 | |||
498 | /* Latch the bits */ | ||
499 | outl(hc_value | HOOKN_BIT, hc_port); | ||
500 | outl(hc_value, hc_port); | ||
501 | } | ||
502 | |||
503 | /************************************************************************** | ||
504 | * @func Set the gain of the ECARD's CS3310 Trim/gain controller. The | ||
505 | * trim value consists of a 16bit value which is composed of two | ||
506 | * 8 bit gain/trim values, one for the left channel and one for the | ||
507 | * right channel. The following table maps from the Gain/Attenuation | ||
508 | * value in decibels into the corresponding bit pattern for a single | ||
509 | * channel. | ||
510 | */ | ||
511 | |||
512 | static void snd_emu10k1_ecard_setadcgain(emu10k1_t * emu, | ||
513 | unsigned short gain) | ||
514 | { | ||
515 | unsigned int bit; | ||
516 | |||
517 | /* Enable writing to the TRIM registers */ | ||
518 | snd_emu10k1_ecard_write(emu, emu->ecard_ctrl & ~EC_TRIM_CSN); | ||
519 | |||
520 | /* Do it again to insure that we meet hold time requirements */ | ||
521 | snd_emu10k1_ecard_write(emu, emu->ecard_ctrl & ~EC_TRIM_CSN); | ||
522 | |||
523 | for (bit = (1 << 15); bit; bit >>= 1) { | ||
524 | unsigned int value; | ||
525 | |||
526 | value = emu->ecard_ctrl & ~(EC_TRIM_CSN | EC_TRIM_SDATA); | ||
527 | |||
528 | if (gain & bit) | ||
529 | value |= EC_TRIM_SDATA; | ||
530 | |||
531 | /* Clock the bit */ | ||
532 | snd_emu10k1_ecard_write(emu, value); | ||
533 | snd_emu10k1_ecard_write(emu, value | EC_TRIM_SCLK); | ||
534 | snd_emu10k1_ecard_write(emu, value); | ||
535 | } | ||
536 | |||
537 | snd_emu10k1_ecard_write(emu, emu->ecard_ctrl); | ||
538 | } | ||
539 | |||
540 | static int __devinit snd_emu10k1_ecard_init(emu10k1_t * emu) | ||
541 | { | ||
542 | unsigned int hc_value; | ||
543 | |||
544 | /* Set up the initial settings */ | ||
545 | emu->ecard_ctrl = EC_RAW_RUN_MODE | | ||
546 | EC_SPDIF0_SELECT(EC_DEFAULT_SPDIF0_SEL) | | ||
547 | EC_SPDIF1_SELECT(EC_DEFAULT_SPDIF1_SEL); | ||
548 | |||
549 | /* Step 0: Set the codec type in the hardware control register | ||
550 | * and enable audio output */ | ||
551 | hc_value = inl(emu->port + HCFG); | ||
552 | outl(hc_value | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S, emu->port + HCFG); | ||
553 | inl(emu->port + HCFG); | ||
554 | |||
555 | /* Step 1: Turn off the led and deassert TRIM_CS */ | ||
556 | snd_emu10k1_ecard_write(emu, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN); | ||
557 | |||
558 | /* Step 2: Calibrate the ADC and DAC */ | ||
559 | snd_emu10k1_ecard_write(emu, EC_DACCAL | EC_LEDN | EC_TRIM_CSN); | ||
560 | |||
561 | /* Step 3: Wait for awhile; XXX We can't get away with this | ||
562 | * under a real operating system; we'll need to block and wait that | ||
563 | * way. */ | ||
564 | snd_emu10k1_wait(emu, 48000); | ||
565 | |||
566 | /* Step 4: Switch off the DAC and ADC calibration. Note | ||
567 | * That ADC_CAL is actually an inverted signal, so we assert | ||
568 | * it here to stop calibration. */ | ||
569 | snd_emu10k1_ecard_write(emu, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN); | ||
570 | |||
571 | /* Step 4: Switch into run mode */ | ||
572 | snd_emu10k1_ecard_write(emu, emu->ecard_ctrl); | ||
573 | |||
574 | /* Step 5: Set the analog input gain */ | ||
575 | snd_emu10k1_ecard_setadcgain(emu, EC_DEFAULT_ADC_GAIN); | ||
576 | |||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | /* | ||
581 | * Create the EMU10K1 instance | ||
582 | */ | ||
583 | |||
584 | static int snd_emu10k1_free(emu10k1_t *emu) | ||
585 | { | ||
586 | if (emu->port) { /* avoid access to already used hardware */ | ||
587 | snd_emu10k1_fx8010_tram_setup(emu, 0); | ||
588 | snd_emu10k1_done(emu); | ||
589 | } | ||
590 | if (emu->memhdr) | ||
591 | snd_util_memhdr_free(emu->memhdr); | ||
592 | if (emu->silent_page.area) | ||
593 | snd_dma_free_pages(&emu->silent_page); | ||
594 | if (emu->ptb_pages.area) | ||
595 | snd_dma_free_pages(&emu->ptb_pages); | ||
596 | vfree(emu->page_ptr_table); | ||
597 | vfree(emu->page_addr_table); | ||
598 | if (emu->irq >= 0) | ||
599 | free_irq(emu->irq, (void *)emu); | ||
600 | if (emu->port) | ||
601 | pci_release_regions(emu->pci); | ||
602 | pci_disable_device(emu->pci); | ||
603 | if (emu->audigy && emu->revision == 4) /* P16V */ | ||
604 | snd_p16v_free(emu); | ||
605 | kfree(emu); | ||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | static int snd_emu10k1_dev_free(snd_device_t *device) | ||
610 | { | ||
611 | emu10k1_t *emu = device->device_data; | ||
612 | return snd_emu10k1_free(emu); | ||
613 | } | ||
614 | |||
615 | /* vendor, device, subsystem, emu10k1_chip, emu10k2_chip, ca0102_chip, ca0108_chip, ca0151_chip, spk71, spdif_bug, ac97_chip, ecard, driver, name */ | ||
616 | |||
617 | static emu_chip_details_t emu_chip_details[] = { | ||
618 | /* Audigy 2 Value AC3 out does not work yet. Need to find out how to turn off interpolators.*/ | ||
619 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102, | ||
620 | .driver = "Audigy2", .name = "Audigy 2 Value [SB0400]", | ||
621 | .emu10k2_chip = 1, | ||
622 | .ca0108_chip = 1, | ||
623 | .spk71 = 1} , | ||
624 | {.vendor = 0x1102, .device = 0x0008, | ||
625 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", | ||
626 | .emu10k2_chip = 1, | ||
627 | .ca0108_chip = 1} , | ||
628 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102, | ||
629 | .driver = "Audigy2", .name = "Audigy 4 PRO [SB0380]", | ||
630 | .emu10k2_chip = 1, | ||
631 | .ca0102_chip = 1, | ||
632 | .ca0151_chip = 1, | ||
633 | .spk71 = 1, | ||
634 | .spdif_bug = 1, | ||
635 | .ac97_chip = 1} , | ||
636 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102, | ||
637 | .driver = "Audigy2", .name = "Audigy 2 ZS [SB0350]", | ||
638 | .emu10k2_chip = 1, | ||
639 | .ca0102_chip = 1, | ||
640 | .ca0151_chip = 1, | ||
641 | .spk71 = 1, | ||
642 | .spdif_bug = 1, | ||
643 | .ac97_chip = 1} , | ||
644 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102, | ||
645 | .driver = "Audigy2", .name = "Audigy 2 ZS [2001]", | ||
646 | .emu10k2_chip = 1, | ||
647 | .ca0102_chip = 1, | ||
648 | .ca0151_chip = 1, | ||
649 | .spk71 = 1, | ||
650 | .spdif_bug = 1, | ||
651 | .ac97_chip = 1} , | ||
652 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102, | ||
653 | .driver = "Audigy2", .name = "Audigy 2 [SB0240]", | ||
654 | .emu10k2_chip = 1, | ||
655 | .ca0102_chip = 1, | ||
656 | .ca0151_chip = 1, | ||
657 | .spk71 = 1, | ||
658 | .spdif_bug = 1, | ||
659 | .ac97_chip = 1} , | ||
660 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102, | ||
661 | .driver = "Audigy2", .name = "Audigy 2 EX [1005]", | ||
662 | .emu10k2_chip = 1, | ||
663 | .ca0102_chip = 1, | ||
664 | .ca0151_chip = 1, | ||
665 | .spdif_bug = 1} , | ||
666 | {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102, | ||
667 | .driver = "Audigy2", .name = "Audigy 2 Platinum [SB0240P]", | ||
668 | .emu10k2_chip = 1, | ||
669 | .ca0102_chip = 1, | ||
670 | .ca0151_chip = 1, | ||
671 | .spk71 = 1, | ||
672 | .spdif_bug = 1, | ||
673 | .ac97_chip = 1} , | ||
674 | {.vendor = 0x1102, .device = 0x0004, | ||
675 | .driver = "Audigy", .name = "Audigy 1 or 2 [Unknown]", | ||
676 | .emu10k2_chip = 1, | ||
677 | .ca0102_chip = 1, | ||
678 | .spdif_bug = 1} , | ||
679 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102, | ||
680 | .driver = "EMU10K1", .name = "E-mu APS [4001]", | ||
681 | .emu10k1_chip = 1, | ||
682 | .ecard = 1} , | ||
683 | {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102, | ||
684 | .driver = "EMU10K1", .name = "SB Live 5.1", | ||
685 | .emu10k1_chip = 1, | ||
686 | .ac97_chip = 1} , | ||
687 | {.vendor = 0x1102, .device = 0x0002, | ||
688 | .driver = "EMU10K1", .name = "SB Live [Unknown]", | ||
689 | .emu10k1_chip = 1, | ||
690 | .ac97_chip = 1} , | ||
691 | { } /* terminator */ | ||
692 | }; | ||
693 | |||
694 | int __devinit snd_emu10k1_create(snd_card_t * card, | ||
695 | struct pci_dev * pci, | ||
696 | unsigned short extin_mask, | ||
697 | unsigned short extout_mask, | ||
698 | long max_cache_bytes, | ||
699 | int enable_ir, | ||
700 | emu10k1_t ** remu) | ||
701 | { | ||
702 | emu10k1_t *emu; | ||
703 | int err; | ||
704 | int is_audigy; | ||
705 | unsigned char revision; | ||
706 | const emu_chip_details_t *c; | ||
707 | static snd_device_ops_t ops = { | ||
708 | .dev_free = snd_emu10k1_dev_free, | ||
709 | }; | ||
710 | |||
711 | *remu = NULL; | ||
712 | |||
713 | /* enable PCI device */ | ||
714 | if ((err = pci_enable_device(pci)) < 0) | ||
715 | return err; | ||
716 | |||
717 | emu = kcalloc(1, sizeof(*emu), GFP_KERNEL); | ||
718 | if (emu == NULL) { | ||
719 | pci_disable_device(pci); | ||
720 | return -ENOMEM; | ||
721 | } | ||
722 | emu->card = card; | ||
723 | spin_lock_init(&emu->reg_lock); | ||
724 | spin_lock_init(&emu->emu_lock); | ||
725 | spin_lock_init(&emu->voice_lock); | ||
726 | spin_lock_init(&emu->synth_lock); | ||
727 | spin_lock_init(&emu->memblk_lock); | ||
728 | init_MUTEX(&emu->ptb_lock); | ||
729 | init_MUTEX(&emu->fx8010.lock); | ||
730 | INIT_LIST_HEAD(&emu->mapped_link_head); | ||
731 | INIT_LIST_HEAD(&emu->mapped_order_link_head); | ||
732 | emu->pci = pci; | ||
733 | emu->irq = -1; | ||
734 | emu->synth = NULL; | ||
735 | emu->get_synth_voice = NULL; | ||
736 | /* read revision & serial */ | ||
737 | pci_read_config_byte(pci, PCI_REVISION_ID, &revision); | ||
738 | emu->revision = revision; | ||
739 | pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); | ||
740 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); | ||
741 | emu->card_type = EMU10K1_CARD_CREATIVE; | ||
742 | snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model); | ||
743 | |||
744 | for (c = emu_chip_details; c->vendor; c++) { | ||
745 | if (c->vendor == pci->vendor && c->device == pci->device) { | ||
746 | if (c->subsystem == emu->serial) break; | ||
747 | if (c->subsystem == 0) break; | ||
748 | } | ||
749 | } | ||
750 | if (c->vendor == 0) { | ||
751 | snd_printk(KERN_ERR "emu10k1: Card not recognised\n"); | ||
752 | kfree(emu); | ||
753 | pci_disable_device(pci); | ||
754 | return -ENOENT; | ||
755 | } | ||
756 | emu->card_capabilities = c; | ||
757 | if (c->subsystem != 0) | ||
758 | snd_printdd("Sound card name=%s\n", c->name); | ||
759 | else | ||
760 | snd_printdd("Sound card name=%s, vendor=0x%x, device=0x%x, subsystem=0x%x\n", c->name, pci->vendor, pci->device, emu->serial); | ||
761 | |||
762 | is_audigy = emu->audigy = c->emu10k2_chip; | ||
763 | |||
764 | /* set the DMA transfer mask */ | ||
765 | emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; | ||
766 | if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || | ||
767 | pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { | ||
768 | snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); | ||
769 | kfree(emu); | ||
770 | pci_disable_device(pci); | ||
771 | return -ENXIO; | ||
772 | } | ||
773 | if (is_audigy) | ||
774 | emu->gpr_base = A_FXGPREGBASE; | ||
775 | else | ||
776 | emu->gpr_base = FXGPREGBASE; | ||
777 | |||
778 | if ((err = pci_request_regions(pci, "EMU10K1")) < 0) { | ||
779 | kfree(emu); | ||
780 | pci_disable_device(pci); | ||
781 | return err; | ||
782 | } | ||
783 | emu->port = pci_resource_start(pci, 0); | ||
784 | |||
785 | if (request_irq(pci->irq, snd_emu10k1_interrupt, SA_INTERRUPT|SA_SHIRQ, "EMU10K1", (void *)emu)) { | ||
786 | snd_emu10k1_free(emu); | ||
787 | return -EBUSY; | ||
788 | } | ||
789 | emu->irq = pci->irq; | ||
790 | |||
791 | emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; | ||
792 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
793 | 32 * 1024, &emu->ptb_pages) < 0) { | ||
794 | snd_emu10k1_free(emu); | ||
795 | return -ENOMEM; | ||
796 | } | ||
797 | |||
798 | emu->page_ptr_table = (void **)vmalloc(emu->max_cache_pages * sizeof(void*)); | ||
799 | emu->page_addr_table = (unsigned long*)vmalloc(emu->max_cache_pages * sizeof(unsigned long)); | ||
800 | if (emu->page_ptr_table == NULL || emu->page_addr_table == NULL) { | ||
801 | snd_emu10k1_free(emu); | ||
802 | return -ENOMEM; | ||
803 | } | ||
804 | |||
805 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
806 | EMUPAGESIZE, &emu->silent_page) < 0) { | ||
807 | snd_emu10k1_free(emu); | ||
808 | return -ENOMEM; | ||
809 | } | ||
810 | emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE); | ||
811 | if (emu->memhdr == NULL) { | ||
812 | snd_emu10k1_free(emu); | ||
813 | return -ENOMEM; | ||
814 | } | ||
815 | emu->memhdr->block_extra_size = sizeof(emu10k1_memblk_t) - sizeof(snd_util_memblk_t); | ||
816 | |||
817 | pci_set_master(pci); | ||
818 | |||
819 | if (c->ecard) { | ||
820 | emu->card_type = EMU10K1_CARD_EMUAPS; | ||
821 | emu->APS = 1; | ||
822 | } | ||
823 | if (! c->ac97_chip) | ||
824 | emu->no_ac97 = 1; | ||
825 | |||
826 | emu->spk71 = c->spk71; | ||
827 | |||
828 | emu->fx8010.fxbus_mask = 0x303f; | ||
829 | if (extin_mask == 0) | ||
830 | extin_mask = 0x3fcf; | ||
831 | if (extout_mask == 0) | ||
832 | extout_mask = 0x7fff; | ||
833 | emu->fx8010.extin_mask = extin_mask; | ||
834 | emu->fx8010.extout_mask = extout_mask; | ||
835 | |||
836 | if (emu->APS) { | ||
837 | if ((err = snd_emu10k1_ecard_init(emu)) < 0) { | ||
838 | snd_emu10k1_free(emu); | ||
839 | return err; | ||
840 | } | ||
841 | } else { | ||
842 | /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version | ||
843 | does not support this, it shouldn't do any harm */ | ||
844 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE); | ||
845 | } | ||
846 | |||
847 | if ((err = snd_emu10k1_init(emu, enable_ir)) < 0) { | ||
848 | snd_emu10k1_free(emu); | ||
849 | return err; | ||
850 | } | ||
851 | |||
852 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, emu, &ops)) < 0) { | ||
853 | snd_emu10k1_free(emu); | ||
854 | return err; | ||
855 | } | ||
856 | |||
857 | snd_emu10k1_proc_init(emu); | ||
858 | |||
859 | snd_card_set_dev(card, &pci->dev); | ||
860 | *remu = emu; | ||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | /* memory.c */ | ||
865 | EXPORT_SYMBOL(snd_emu10k1_synth_alloc); | ||
866 | EXPORT_SYMBOL(snd_emu10k1_synth_free); | ||
867 | EXPORT_SYMBOL(snd_emu10k1_synth_bzero); | ||
868 | EXPORT_SYMBOL(snd_emu10k1_synth_copy_from_user); | ||
869 | EXPORT_SYMBOL(snd_emu10k1_memblk_map); | ||
870 | /* voice.c */ | ||
871 | EXPORT_SYMBOL(snd_emu10k1_voice_alloc); | ||
872 | EXPORT_SYMBOL(snd_emu10k1_voice_free); | ||
873 | /* io.c */ | ||
874 | EXPORT_SYMBOL(snd_emu10k1_ptr_read); | ||
875 | EXPORT_SYMBOL(snd_emu10k1_ptr_write); | ||
diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c new file mode 100644 index 000000000000..4df668eb32b4 --- /dev/null +++ b/sound/pci/emu10k1/emu10k1_patch.c | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * Patch transfer callback for Emu10k1 | ||
3 | * | ||
4 | * Copyright (C) 2000 Takashi iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | /* | ||
21 | * All the code for loading in a patch. There is very little that is | ||
22 | * chip specific here. Just the actual writing to the board. | ||
23 | */ | ||
24 | |||
25 | #include "emu10k1_synth_local.h" | ||
26 | |||
27 | /* | ||
28 | */ | ||
29 | #define BLANK_LOOP_START 4 | ||
30 | #define BLANK_LOOP_END 8 | ||
31 | #define BLANK_LOOP_SIZE 12 | ||
32 | #define BLANK_HEAD_SIZE 32 | ||
33 | |||
34 | /* | ||
35 | * allocate a sample block and copy data from userspace | ||
36 | */ | ||
37 | int | ||
38 | snd_emu10k1_sample_new(snd_emux_t *rec, snd_sf_sample_t *sp, | ||
39 | snd_util_memhdr_t *hdr, const void __user *data, long count) | ||
40 | { | ||
41 | int offset; | ||
42 | int truesize, size, loopsize, blocksize; | ||
43 | int loopend, sampleend; | ||
44 | unsigned int start_addr; | ||
45 | emu10k1_t *emu; | ||
46 | |||
47 | emu = rec->hw; | ||
48 | snd_assert(sp != NULL, return -EINVAL); | ||
49 | snd_assert(hdr != NULL, return -EINVAL); | ||
50 | |||
51 | if (sp->v.size == 0) { | ||
52 | snd_printd("emu: rom font for sample %d\n", sp->v.sample); | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | /* recalculate address offset */ | ||
57 | sp->v.end -= sp->v.start; | ||
58 | sp->v.loopstart -= sp->v.start; | ||
59 | sp->v.loopend -= sp->v.start; | ||
60 | sp->v.start = 0; | ||
61 | |||
62 | /* some samples have invalid data. the addresses are corrected in voice info */ | ||
63 | sampleend = sp->v.end; | ||
64 | if (sampleend > sp->v.size) | ||
65 | sampleend = sp->v.size; | ||
66 | loopend = sp->v.loopend; | ||
67 | if (loopend > sampleend) | ||
68 | loopend = sampleend; | ||
69 | |||
70 | /* be sure loop points start < end */ | ||
71 | if (sp->v.loopstart >= sp->v.loopend) { | ||
72 | int tmp = sp->v.loopstart; | ||
73 | sp->v.loopstart = sp->v.loopend; | ||
74 | sp->v.loopend = tmp; | ||
75 | } | ||
76 | |||
77 | /* compute true data size to be loaded */ | ||
78 | truesize = sp->v.size + BLANK_HEAD_SIZE; | ||
79 | loopsize = 0; | ||
80 | #if 0 /* not supported */ | ||
81 | if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) | ||
82 | loopsize = sp->v.loopend - sp->v.loopstart; | ||
83 | truesize += loopsize; | ||
84 | #endif | ||
85 | if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) | ||
86 | truesize += BLANK_LOOP_SIZE; | ||
87 | |||
88 | /* try to allocate a memory block */ | ||
89 | blocksize = truesize; | ||
90 | if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) | ||
91 | blocksize *= 2; | ||
92 | sp->block = snd_emu10k1_synth_alloc(emu, blocksize); | ||
93 | if (sp->block == NULL) { | ||
94 | snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize); | ||
95 | /* not ENOMEM (for compatibility with OSS) */ | ||
96 | return -ENOSPC; | ||
97 | } | ||
98 | /* set the total size */ | ||
99 | sp->v.truesize = blocksize; | ||
100 | |||
101 | /* write blank samples at head */ | ||
102 | offset = 0; | ||
103 | size = BLANK_HEAD_SIZE; | ||
104 | if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) | ||
105 | size *= 2; | ||
106 | snd_assert(offset + size <= blocksize, return -EINVAL); | ||
107 | snd_emu10k1_synth_bzero(emu, sp->block, offset, size); | ||
108 | offset += size; | ||
109 | |||
110 | /* copy start->loopend */ | ||
111 | size = loopend; | ||
112 | if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) | ||
113 | size *= 2; | ||
114 | snd_assert(offset + size <= blocksize, return -EINVAL); | ||
115 | if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { | ||
116 | snd_emu10k1_synth_free(emu, sp->block); | ||
117 | sp->block = NULL; | ||
118 | return -EFAULT; | ||
119 | } | ||
120 | offset += size; | ||
121 | data += size; | ||
122 | |||
123 | #if 0 /* not suppported yet */ | ||
124 | /* handle reverse (or bidirectional) loop */ | ||
125 | if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) { | ||
126 | /* copy loop in reverse */ | ||
127 | if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) { | ||
128 | int woffset; | ||
129 | unsigned short *wblock = (unsigned short*)block; | ||
130 | woffset = offset / 2; | ||
131 | snd_assert(offset + loopsize*2 <= blocksize, return -EINVAL); | ||
132 | for (i = 0; i < loopsize; i++) | ||
133 | wblock[woffset + i] = wblock[woffset - i -1]; | ||
134 | offset += loopsize * 2; | ||
135 | } else { | ||
136 | snd_assert(offset + loopsize <= blocksize, return -EINVAL); | ||
137 | for (i = 0; i < loopsize; i++) | ||
138 | block[offset + i] = block[offset - i -1]; | ||
139 | offset += loopsize; | ||
140 | } | ||
141 | |||
142 | /* modify loop pointers */ | ||
143 | if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) { | ||
144 | sp->v.loopend += loopsize; | ||
145 | } else { | ||
146 | sp->v.loopstart += loopsize; | ||
147 | sp->v.loopend += loopsize; | ||
148 | } | ||
149 | /* add sample pointer */ | ||
150 | sp->v.end += loopsize; | ||
151 | } | ||
152 | #endif | ||
153 | |||
154 | /* loopend -> sample end */ | ||
155 | size = sp->v.size - loopend; | ||
156 | snd_assert(size >= 0, return -EINVAL); | ||
157 | if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) | ||
158 | size *= 2; | ||
159 | if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) { | ||
160 | snd_emu10k1_synth_free(emu, sp->block); | ||
161 | sp->block = NULL; | ||
162 | return -EFAULT; | ||
163 | } | ||
164 | offset += size; | ||
165 | |||
166 | /* clear rest of samples (if any) */ | ||
167 | if (offset < blocksize) | ||
168 | snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset); | ||
169 | |||
170 | if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) { | ||
171 | /* if no blank loop is attached in the sample, add it */ | ||
172 | if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) { | ||
173 | sp->v.loopstart = sp->v.end + BLANK_LOOP_START; | ||
174 | sp->v.loopend = sp->v.end + BLANK_LOOP_END; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | #if 0 /* not supported yet */ | ||
179 | if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) { | ||
180 | /* unsigned -> signed */ | ||
181 | if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) { | ||
182 | unsigned short *wblock = (unsigned short*)block; | ||
183 | for (i = 0; i < truesize; i++) | ||
184 | wblock[i] ^= 0x8000; | ||
185 | } else { | ||
186 | for (i = 0; i < truesize; i++) | ||
187 | block[i] ^= 0x80; | ||
188 | } | ||
189 | } | ||
190 | #endif | ||
191 | |||
192 | /* recalculate offset */ | ||
193 | start_addr = BLANK_HEAD_SIZE * 2; | ||
194 | if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) | ||
195 | start_addr >>= 1; | ||
196 | sp->v.start += start_addr; | ||
197 | sp->v.end += start_addr; | ||
198 | sp->v.loopstart += start_addr; | ||
199 | sp->v.loopend += start_addr; | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * free a sample block | ||
206 | */ | ||
207 | int | ||
208 | snd_emu10k1_sample_free(snd_emux_t *rec, snd_sf_sample_t *sp, | ||
209 | snd_util_memhdr_t *hdr) | ||
210 | { | ||
211 | emu10k1_t *emu; | ||
212 | |||
213 | emu = rec->hw; | ||
214 | snd_assert(sp != NULL, return -EINVAL); | ||
215 | snd_assert(hdr != NULL, return -EINVAL); | ||
216 | |||
217 | if (sp->block) { | ||
218 | snd_emu10k1_synth_free(emu, sp->block); | ||
219 | sp->block = NULL; | ||
220 | } | ||
221 | return 0; | ||
222 | } | ||
223 | |||
diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c new file mode 100644 index 000000000000..8bd58d1dcc26 --- /dev/null +++ b/sound/pci/emu10k1/emu10k1_synth.c | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000 Takashi Iwai <tiwai@suse.de> | ||
3 | * | ||
4 | * Routines for control of EMU10K1 WaveTable synth | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "emu10k1_synth_local.h" | ||
22 | #include <linux/init.h> | ||
23 | |||
24 | MODULE_AUTHOR("Takashi Iwai"); | ||
25 | MODULE_DESCRIPTION("Routines for control of EMU10K1 WaveTable synth"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | /* | ||
29 | * create a new hardware dependent device for Emu10k1 | ||
30 | */ | ||
31 | static int snd_emu10k1_synth_new_device(snd_seq_device_t *dev) | ||
32 | { | ||
33 | snd_emux_t *emu; | ||
34 | emu10k1_t *hw; | ||
35 | snd_emu10k1_synth_arg_t *arg; | ||
36 | unsigned long flags; | ||
37 | |||
38 | arg = SNDRV_SEQ_DEVICE_ARGPTR(dev); | ||
39 | if (arg == NULL) | ||
40 | return -EINVAL; | ||
41 | |||
42 | if (arg->seq_ports <= 0) | ||
43 | return 0; /* nothing */ | ||
44 | if (arg->max_voices < 1) | ||
45 | arg->max_voices = 1; | ||
46 | else if (arg->max_voices > 64) | ||
47 | arg->max_voices = 64; | ||
48 | |||
49 | if (snd_emux_new(&emu) < 0) | ||
50 | return -ENOMEM; | ||
51 | |||
52 | snd_emu10k1_ops_setup(emu); | ||
53 | emu->hw = hw = arg->hwptr; | ||
54 | emu->max_voices = arg->max_voices; | ||
55 | emu->num_ports = arg->seq_ports; | ||
56 | emu->pitch_shift = -501; | ||
57 | emu->memhdr = hw->memhdr; | ||
58 | emu->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; /* maximum two ports */ | ||
59 | emu->midi_devidx = hw->audigy ? 2 : 1; /* audigy has two external midis */ | ||
60 | emu->linear_panning = 0; | ||
61 | emu->hwdep_idx = 2; /* FIXED */ | ||
62 | |||
63 | if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) { | ||
64 | snd_emux_free(emu); | ||
65 | emu->hw = NULL; | ||
66 | return -ENOMEM; | ||
67 | } | ||
68 | |||
69 | spin_lock_irqsave(&hw->voice_lock, flags); | ||
70 | hw->synth = emu; | ||
71 | hw->get_synth_voice = snd_emu10k1_synth_get_voice; | ||
72 | spin_unlock_irqrestore(&hw->voice_lock, flags); | ||
73 | |||
74 | dev->driver_data = emu; | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int snd_emu10k1_synth_delete_device(snd_seq_device_t *dev) | ||
80 | { | ||
81 | snd_emux_t *emu; | ||
82 | emu10k1_t *hw; | ||
83 | unsigned long flags; | ||
84 | |||
85 | if (dev->driver_data == NULL) | ||
86 | return 0; /* not registered actually */ | ||
87 | |||
88 | emu = dev->driver_data; | ||
89 | |||
90 | hw = emu->hw; | ||
91 | spin_lock_irqsave(&hw->voice_lock, flags); | ||
92 | hw->synth = NULL; | ||
93 | hw->get_synth_voice = NULL; | ||
94 | spin_unlock_irqrestore(&hw->voice_lock, flags); | ||
95 | |||
96 | snd_emux_free(emu); | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * INIT part | ||
102 | */ | ||
103 | |||
104 | static int __init alsa_emu10k1_synth_init(void) | ||
105 | { | ||
106 | |||
107 | static snd_seq_dev_ops_t ops = { | ||
108 | snd_emu10k1_synth_new_device, | ||
109 | snd_emu10k1_synth_delete_device, | ||
110 | }; | ||
111 | return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, &ops, sizeof(snd_emu10k1_synth_arg_t)); | ||
112 | } | ||
113 | |||
114 | static void __exit alsa_emu10k1_synth_exit(void) | ||
115 | { | ||
116 | snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH); | ||
117 | } | ||
118 | |||
119 | module_init(alsa_emu10k1_synth_init) | ||
120 | module_exit(alsa_emu10k1_synth_exit) | ||
diff --git a/sound/pci/emu10k1/emu10k1_synth_local.h b/sound/pci/emu10k1/emu10k1_synth_local.h new file mode 100644 index 000000000000..7f50b01ddb76 --- /dev/null +++ b/sound/pci/emu10k1/emu10k1_synth_local.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef __EMU10K1_SYNTH_LOCAL_H | ||
2 | #define __EMU10K1_SYNTH_LOCAL_H | ||
3 | /* | ||
4 | * Local defininitons for Emu10k1 wavetable | ||
5 | * | ||
6 | * Copyright (C) 2000 Takashi Iwai <tiwai@suse.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <sound/driver.h> | ||
24 | #include <linux/time.h> | ||
25 | #include <sound/core.h> | ||
26 | #include <sound/emu10k1_synth.h> | ||
27 | |||
28 | /* emu10k1_patch.c */ | ||
29 | int snd_emu10k1_sample_new(snd_emux_t *private_data, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr, const void __user *_data, long count); | ||
30 | int snd_emu10k1_sample_free(snd_emux_t *private_data, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr); | ||
31 | int snd_emu10k1_memhdr_init(snd_emux_t *emu); | ||
32 | |||
33 | /* emu10k1_callback.c */ | ||
34 | void snd_emu10k1_ops_setup(snd_emux_t *emu); | ||
35 | int snd_emu10k1_synth_get_voice(emu10k1_t *hw); | ||
36 | |||
37 | |||
38 | #endif /* __EMU10K1_SYNTH_LOCAL_H */ | ||
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c new file mode 100644 index 000000000000..27dfd8ddddf4 --- /dev/null +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -0,0 +1,1643 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> | ||
3 | * Driver EMU10K1X chips | ||
4 | * | ||
5 | * Parts of this code were adapted from audigyls.c driver which is | ||
6 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | ||
7 | * | ||
8 | * BUGS: | ||
9 | * -- | ||
10 | * | ||
11 | * TODO: | ||
12 | * | ||
13 | * Chips (SB0200 model): | ||
14 | * - EMU10K1X-DBQ | ||
15 | * - STAC 9708T | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * GNU General Public License for more details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License | ||
28 | * along with this program; if not, write to the Free Software | ||
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
30 | * | ||
31 | */ | ||
32 | #include <sound/driver.h> | ||
33 | #include <linux/init.h> | ||
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/pci.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/moduleparam.h> | ||
38 | #include <sound/core.h> | ||
39 | #include <sound/initval.h> | ||
40 | #include <sound/pcm.h> | ||
41 | #include <sound/ac97_codec.h> | ||
42 | #include <sound/info.h> | ||
43 | #include <sound/rawmidi.h> | ||
44 | |||
45 | MODULE_AUTHOR("Francisco Moraes <fmoraes@nc.rr.com>"); | ||
46 | MODULE_DESCRIPTION("EMU10K1X"); | ||
47 | MODULE_LICENSE("GPL"); | ||
48 | MODULE_SUPPORTED_DEVICE("{{Dell Creative Labs,SB Live!}"); | ||
49 | |||
50 | // module parameters (see "Module Parameters") | ||
51 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
52 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
53 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
54 | |||
55 | module_param_array(index, int, NULL, 0444); | ||
56 | MODULE_PARM_DESC(index, "Index value for the EMU10K1X soundcard."); | ||
57 | module_param_array(id, charp, NULL, 0444); | ||
58 | MODULE_PARM_DESC(id, "ID string for the EMU10K1X soundcard."); | ||
59 | module_param_array(enable, bool, NULL, 0444); | ||
60 | MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard."); | ||
61 | |||
62 | |||
63 | // some definitions were borrowed from emu10k1 driver as they seem to be the same | ||
64 | /************************************************************************************************/ | ||
65 | /* PCI function 0 registers, address = <val> + PCIBASE0 */ | ||
66 | /************************************************************************************************/ | ||
67 | |||
68 | #define PTR 0x00 /* Indexed register set pointer register */ | ||
69 | /* NOTE: The CHANNELNUM and ADDRESS words can */ | ||
70 | /* be modified independently of each other. */ | ||
71 | |||
72 | #define DATA 0x04 /* Indexed register set data register */ | ||
73 | |||
74 | #define IPR 0x08 /* Global interrupt pending register */ | ||
75 | /* Clear pending interrupts by writing a 1 to */ | ||
76 | /* the relevant bits and zero to the other bits */ | ||
77 | #define IPR_MIDITRANSBUFEMPTY 0x00000001 /* MIDI UART transmit buffer empty */ | ||
78 | #define IPR_MIDIRECVBUFEMPTY 0x00000002 /* MIDI UART receive buffer empty */ | ||
79 | #define IPR_CH_0_LOOP 0x00000800 /* Channel 0 loop */ | ||
80 | #define IPR_CH_0_HALF_LOOP 0x00000100 /* Channel 0 half loop */ | ||
81 | #define IPR_CAP_0_LOOP 0x00080000 /* Channel capture loop */ | ||
82 | #define IPR_CAP_0_HALF_LOOP 0x00010000 /* Channel capture half loop */ | ||
83 | |||
84 | #define INTE 0x0c /* Interrupt enable register */ | ||
85 | #define INTE_MIDITXENABLE 0x00000001 /* Enable MIDI transmit-buffer-empty interrupts */ | ||
86 | #define INTE_MIDIRXENABLE 0x00000002 /* Enable MIDI receive-buffer-empty interrupts */ | ||
87 | #define INTE_CH_0_LOOP 0x00000800 /* Channel 0 loop */ | ||
88 | #define INTE_CH_0_HALF_LOOP 0x00000100 /* Channel 0 half loop */ | ||
89 | #define INTE_CAP_0_LOOP 0x00080000 /* Channel capture loop */ | ||
90 | #define INTE_CAP_0_HALF_LOOP 0x00010000 /* Channel capture half loop */ | ||
91 | |||
92 | #define HCFG 0x14 /* Hardware config register */ | ||
93 | |||
94 | #define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */ | ||
95 | /* NOTE: This should generally never be used. */ | ||
96 | #define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */ | ||
97 | /* Should be set to 1 when the EMU10K1 is */ | ||
98 | /* completely initialized. */ | ||
99 | #define GPIO 0x18 /* Defaults: 00001080-Analog, 00001000-SPDIF. */ | ||
100 | |||
101 | |||
102 | #define AC97DATA 0x1c /* AC97 register set data register (16 bit) */ | ||
103 | |||
104 | #define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */ | ||
105 | |||
106 | /********************************************************************************************************/ | ||
107 | /* Emu10k1x pointer-offset register set, accessed through the PTR and DATA registers */ | ||
108 | /********************************************************************************************************/ | ||
109 | #define PLAYBACK_LIST_ADDR 0x00 /* Base DMA address of a list of pointers to each period/size */ | ||
110 | /* One list entry: 4 bytes for DMA address, | ||
111 | * 4 bytes for period_size << 16. | ||
112 | * One list entry is 8 bytes long. | ||
113 | * One list entry for each period in the buffer. | ||
114 | */ | ||
115 | #define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */ | ||
116 | #define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */ | ||
117 | #define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */ | ||
118 | #define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size */ | ||
119 | #define PLAYBACK_POINTER 0x06 /* Playback period pointer. Sample currently in DAC */ | ||
120 | #define PLAYBACK_UNKNOWN1 0x07 | ||
121 | #define PLAYBACK_UNKNOWN2 0x08 | ||
122 | |||
123 | /* Only one capture channel supported */ | ||
124 | #define CAPTURE_DMA_ADDR 0x10 /* Capture DMA address */ | ||
125 | #define CAPTURE_BUFFER_SIZE 0x11 /* Capture buffer size */ | ||
126 | #define CAPTURE_POINTER 0x12 /* Capture buffer pointer. Sample currently in ADC */ | ||
127 | #define CAPTURE_UNKNOWN 0x13 | ||
128 | |||
129 | /* From 0x20 - 0x3f, last samples played on each channel */ | ||
130 | |||
131 | #define TRIGGER_CHANNEL 0x40 /* Trigger channel playback */ | ||
132 | #define TRIGGER_CHANNEL_0 0x00000001 /* Trigger channel 0 */ | ||
133 | #define TRIGGER_CHANNEL_1 0x00000002 /* Trigger channel 1 */ | ||
134 | #define TRIGGER_CHANNEL_2 0x00000004 /* Trigger channel 2 */ | ||
135 | #define TRIGGER_CAPTURE 0x00000100 /* Trigger capture channel */ | ||
136 | |||
137 | #define ROUTING 0x41 /* Setup sound routing ? */ | ||
138 | #define ROUTING_FRONT_LEFT 0x00000001 | ||
139 | #define ROUTING_FRONT_RIGHT 0x00000002 | ||
140 | #define ROUTING_REAR_LEFT 0x00000004 | ||
141 | #define ROUTING_REAR_RIGHT 0x00000008 | ||
142 | #define ROUTING_CENTER_LFE 0x00010000 | ||
143 | |||
144 | #define SPCS0 0x42 /* SPDIF output Channel Status 0 register */ | ||
145 | |||
146 | #define SPCS1 0x43 /* SPDIF output Channel Status 1 register */ | ||
147 | |||
148 | #define SPCS2 0x44 /* SPDIF output Channel Status 2 register */ | ||
149 | |||
150 | #define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */ | ||
151 | #define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */ | ||
152 | #define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */ | ||
153 | #define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */ | ||
154 | #define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */ | ||
155 | #define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */ | ||
156 | #define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */ | ||
157 | #define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */ | ||
158 | #define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */ | ||
159 | #define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */ | ||
160 | #define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */ | ||
161 | #define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */ | ||
162 | #define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */ | ||
163 | #define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */ | ||
164 | #define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */ | ||
165 | #define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */ | ||
166 | #define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */ | ||
167 | #define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */ | ||
168 | #define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */ | ||
169 | #define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */ | ||
170 | #define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */ | ||
171 | #define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */ | ||
172 | #define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */ | ||
173 | |||
174 | #define SPDIF_SELECT 0x45 /* Enables SPDIF or Analogue outputs 0-Analogue, 0x700-SPDIF */ | ||
175 | |||
176 | /* This is the MPU port on the card */ | ||
177 | #define MUDATA 0x47 | ||
178 | #define MUCMD 0x48 | ||
179 | #define MUSTAT MUCMD | ||
180 | |||
181 | /* From 0x50 - 0x5f, last samples captured */ | ||
182 | |||
183 | /** | ||
184 | * The hardware has 3 channels for playback and 1 for capture. | ||
185 | * - channel 0 is the front channel | ||
186 | * - channel 1 is the rear channel | ||
187 | * - channel 2 is the center/lfe chanel | ||
188 | * Volume is controlled by the AC97 for the front and rear channels by | ||
189 | * the PCM Playback Volume, Sigmatel Surround Playback Volume and | ||
190 | * Surround Playback Volume. The Sigmatel 4-Speaker Stereo switch affects | ||
191 | * the front/rear channel mixing in the REAR OUT jack. When using the | ||
192 | * 4-Speaker Stereo, both front and rear channels will be mixed in the | ||
193 | * REAR OUT. | ||
194 | * The center/lfe channel has no volume control and cannot be muted during | ||
195 | * playback. | ||
196 | */ | ||
197 | |||
198 | typedef struct snd_emu10k1x_voice emu10k1x_voice_t; | ||
199 | typedef struct snd_emu10k1x emu10k1x_t; | ||
200 | typedef struct snd_emu10k1x_pcm emu10k1x_pcm_t; | ||
201 | |||
202 | struct snd_emu10k1x_voice { | ||
203 | emu10k1x_t *emu; | ||
204 | int number; | ||
205 | int use; | ||
206 | |||
207 | emu10k1x_pcm_t *epcm; | ||
208 | }; | ||
209 | |||
210 | struct snd_emu10k1x_pcm { | ||
211 | emu10k1x_t *emu; | ||
212 | snd_pcm_substream_t *substream; | ||
213 | emu10k1x_voice_t *voice; | ||
214 | unsigned short running; | ||
215 | }; | ||
216 | |||
217 | typedef struct { | ||
218 | struct snd_emu10k1x *emu; | ||
219 | snd_rawmidi_t *rmidi; | ||
220 | snd_rawmidi_substream_t *substream_input; | ||
221 | snd_rawmidi_substream_t *substream_output; | ||
222 | unsigned int midi_mode; | ||
223 | spinlock_t input_lock; | ||
224 | spinlock_t output_lock; | ||
225 | spinlock_t open_lock; | ||
226 | int tx_enable, rx_enable; | ||
227 | int port; | ||
228 | int ipr_tx, ipr_rx; | ||
229 | void (*interrupt)(emu10k1x_t *emu, unsigned int status); | ||
230 | } emu10k1x_midi_t; | ||
231 | |||
232 | // definition of the chip-specific record | ||
233 | struct snd_emu10k1x { | ||
234 | snd_card_t *card; | ||
235 | struct pci_dev *pci; | ||
236 | |||
237 | unsigned long port; | ||
238 | struct resource *res_port; | ||
239 | int irq; | ||
240 | |||
241 | unsigned int revision; /* chip revision */ | ||
242 | unsigned int serial; /* serial number */ | ||
243 | unsigned short model; /* subsystem id */ | ||
244 | |||
245 | spinlock_t emu_lock; | ||
246 | spinlock_t voice_lock; | ||
247 | |||
248 | ac97_t *ac97; | ||
249 | snd_pcm_t *pcm; | ||
250 | |||
251 | emu10k1x_voice_t voices[3]; | ||
252 | emu10k1x_voice_t capture_voice; | ||
253 | u32 spdif_bits[3]; // SPDIF out setup | ||
254 | |||
255 | struct snd_dma_buffer dma_buffer; | ||
256 | |||
257 | emu10k1x_midi_t midi; | ||
258 | }; | ||
259 | |||
260 | /* hardware definition */ | ||
261 | static snd_pcm_hardware_t snd_emu10k1x_playback_hw = { | ||
262 | .info = (SNDRV_PCM_INFO_MMAP | | ||
263 | SNDRV_PCM_INFO_INTERLEAVED | | ||
264 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
265 | SNDRV_PCM_INFO_MMAP_VALID), | ||
266 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
267 | .rates = SNDRV_PCM_RATE_48000, | ||
268 | .rate_min = 48000, | ||
269 | .rate_max = 48000, | ||
270 | .channels_min = 2, | ||
271 | .channels_max = 2, | ||
272 | .buffer_bytes_max = (32*1024), | ||
273 | .period_bytes_min = 64, | ||
274 | .period_bytes_max = (16*1024), | ||
275 | .periods_min = 2, | ||
276 | .periods_max = 8, | ||
277 | .fifo_size = 0, | ||
278 | }; | ||
279 | |||
280 | static snd_pcm_hardware_t snd_emu10k1x_capture_hw = { | ||
281 | .info = (SNDRV_PCM_INFO_MMAP | | ||
282 | SNDRV_PCM_INFO_INTERLEAVED | | ||
283 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
284 | SNDRV_PCM_INFO_MMAP_VALID), | ||
285 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
286 | .rates = SNDRV_PCM_RATE_48000, | ||
287 | .rate_min = 48000, | ||
288 | .rate_max = 48000, | ||
289 | .channels_min = 2, | ||
290 | .channels_max = 2, | ||
291 | .buffer_bytes_max = (32*1024), | ||
292 | .period_bytes_min = 64, | ||
293 | .period_bytes_max = (16*1024), | ||
294 | .periods_min = 2, | ||
295 | .periods_max = 2, | ||
296 | .fifo_size = 0, | ||
297 | }; | ||
298 | |||
299 | static unsigned int snd_emu10k1x_ptr_read(emu10k1x_t * emu, | ||
300 | unsigned int reg, | ||
301 | unsigned int chn) | ||
302 | { | ||
303 | unsigned long flags; | ||
304 | unsigned int regptr, val; | ||
305 | |||
306 | regptr = (reg << 16) | chn; | ||
307 | |||
308 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
309 | outl(regptr, emu->port + PTR); | ||
310 | val = inl(emu->port + DATA); | ||
311 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
312 | return val; | ||
313 | } | ||
314 | |||
315 | static void snd_emu10k1x_ptr_write(emu10k1x_t *emu, | ||
316 | unsigned int reg, | ||
317 | unsigned int chn, | ||
318 | unsigned int data) | ||
319 | { | ||
320 | unsigned int regptr; | ||
321 | unsigned long flags; | ||
322 | |||
323 | regptr = (reg << 16) | chn; | ||
324 | |||
325 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
326 | outl(regptr, emu->port + PTR); | ||
327 | outl(data, emu->port + DATA); | ||
328 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
329 | } | ||
330 | |||
331 | static void snd_emu10k1x_intr_enable(emu10k1x_t *emu, unsigned int intrenb) | ||
332 | { | ||
333 | unsigned long flags; | ||
334 | unsigned int enable; | ||
335 | |||
336 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
337 | enable = inl(emu->port + INTE) | intrenb; | ||
338 | outl(enable, emu->port + INTE); | ||
339 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
340 | } | ||
341 | |||
342 | static void snd_emu10k1x_intr_disable(emu10k1x_t *emu, unsigned int intrenb) | ||
343 | { | ||
344 | unsigned long flags; | ||
345 | unsigned int enable; | ||
346 | |||
347 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
348 | enable = inl(emu->port + INTE) & ~intrenb; | ||
349 | outl(enable, emu->port + INTE); | ||
350 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
351 | } | ||
352 | |||
353 | static void snd_emu10k1x_gpio_write(emu10k1x_t *emu, unsigned int value) | ||
354 | { | ||
355 | unsigned long flags; | ||
356 | |||
357 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
358 | outl(value, emu->port + GPIO); | ||
359 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
360 | } | ||
361 | |||
362 | static void snd_emu10k1x_pcm_free_substream(snd_pcm_runtime_t *runtime) | ||
363 | { | ||
364 | emu10k1x_pcm_t *epcm = runtime->private_data; | ||
365 | |||
366 | if (epcm) | ||
367 | kfree(epcm); | ||
368 | } | ||
369 | |||
370 | static void snd_emu10k1x_pcm_interrupt(emu10k1x_t *emu, emu10k1x_voice_t *voice) | ||
371 | { | ||
372 | emu10k1x_pcm_t *epcm; | ||
373 | |||
374 | if ((epcm = voice->epcm) == NULL) | ||
375 | return; | ||
376 | if (epcm->substream == NULL) | ||
377 | return; | ||
378 | #if 0 | ||
379 | snd_printk(KERN_INFO "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n", | ||
380 | epcm->substream->ops->pointer(epcm->substream), | ||
381 | snd_pcm_lib_period_bytes(epcm->substream), | ||
382 | snd_pcm_lib_buffer_bytes(epcm->substream)); | ||
383 | #endif | ||
384 | snd_pcm_period_elapsed(epcm->substream); | ||
385 | } | ||
386 | |||
387 | /* open callback */ | ||
388 | static int snd_emu10k1x_playback_open(snd_pcm_substream_t *substream) | ||
389 | { | ||
390 | emu10k1x_t *chip = snd_pcm_substream_chip(substream); | ||
391 | emu10k1x_pcm_t *epcm; | ||
392 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
393 | int err; | ||
394 | |||
395 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { | ||
396 | return err; | ||
397 | } | ||
398 | if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) | ||
399 | return err; | ||
400 | |||
401 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
402 | if (epcm == NULL) | ||
403 | return -ENOMEM; | ||
404 | epcm->emu = chip; | ||
405 | epcm->substream = substream; | ||
406 | |||
407 | runtime->private_data = epcm; | ||
408 | runtime->private_free = snd_emu10k1x_pcm_free_substream; | ||
409 | |||
410 | runtime->hw = snd_emu10k1x_playback_hw; | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | /* close callback */ | ||
416 | static int snd_emu10k1x_playback_close(snd_pcm_substream_t *substream) | ||
417 | { | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | /* hw_params callback */ | ||
422 | static int snd_emu10k1x_pcm_hw_params(snd_pcm_substream_t *substream, | ||
423 | snd_pcm_hw_params_t * hw_params) | ||
424 | { | ||
425 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
426 | emu10k1x_pcm_t *epcm = runtime->private_data; | ||
427 | |||
428 | if (! epcm->voice) { | ||
429 | epcm->voice = &epcm->emu->voices[substream->pcm->device]; | ||
430 | epcm->voice->use = 1; | ||
431 | epcm->voice->epcm = epcm; | ||
432 | } | ||
433 | |||
434 | return snd_pcm_lib_malloc_pages(substream, | ||
435 | params_buffer_bytes(hw_params)); | ||
436 | } | ||
437 | |||
438 | /* hw_free callback */ | ||
439 | static int snd_emu10k1x_pcm_hw_free(snd_pcm_substream_t *substream) | ||
440 | { | ||
441 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
442 | emu10k1x_pcm_t *epcm; | ||
443 | |||
444 | if (runtime->private_data == NULL) | ||
445 | return 0; | ||
446 | |||
447 | epcm = runtime->private_data; | ||
448 | |||
449 | if (epcm->voice) { | ||
450 | epcm->voice->use = 0; | ||
451 | epcm->voice->epcm = NULL; | ||
452 | epcm->voice = NULL; | ||
453 | } | ||
454 | |||
455 | return snd_pcm_lib_free_pages(substream); | ||
456 | } | ||
457 | |||
458 | /* prepare callback */ | ||
459 | static int snd_emu10k1x_pcm_prepare(snd_pcm_substream_t *substream) | ||
460 | { | ||
461 | emu10k1x_t *emu = snd_pcm_substream_chip(substream); | ||
462 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
463 | emu10k1x_pcm_t *epcm = runtime->private_data; | ||
464 | int voice = epcm->voice->number; | ||
465 | u32 *table_base = (u32 *)(emu->dma_buffer.area+1024*voice); | ||
466 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); | ||
467 | int i; | ||
468 | |||
469 | for(i=0; i < runtime->periods; i++) { | ||
470 | *table_base++=runtime->dma_addr+(i*period_size_bytes); | ||
471 | *table_base++=period_size_bytes<<16; | ||
472 | } | ||
473 | |||
474 | snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_ADDR, voice, emu->dma_buffer.addr+1024*voice); | ||
475 | snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_SIZE, voice, (runtime->periods - 1) << 19); | ||
476 | snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_PTR, voice, 0); | ||
477 | snd_emu10k1x_ptr_write(emu, PLAYBACK_POINTER, voice, 0); | ||
478 | snd_emu10k1x_ptr_write(emu, PLAYBACK_UNKNOWN1, voice, 0); | ||
479 | snd_emu10k1x_ptr_write(emu, PLAYBACK_UNKNOWN2, voice, 0); | ||
480 | snd_emu10k1x_ptr_write(emu, PLAYBACK_DMA_ADDR, voice, runtime->dma_addr); | ||
481 | |||
482 | snd_emu10k1x_ptr_write(emu, PLAYBACK_PERIOD_SIZE, voice, frames_to_bytes(runtime, runtime->period_size)<<16); | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | /* trigger callback */ | ||
488 | static int snd_emu10k1x_pcm_trigger(snd_pcm_substream_t *substream, | ||
489 | int cmd) | ||
490 | { | ||
491 | emu10k1x_t *emu = snd_pcm_substream_chip(substream); | ||
492 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
493 | emu10k1x_pcm_t *epcm = runtime->private_data; | ||
494 | int channel = epcm->voice->number; | ||
495 | int result = 0; | ||
496 | |||
497 | // snd_printk(KERN_INFO "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n", (int)emu, cmd, (int)substream->ops->pointer(substream)); | ||
498 | |||
499 | switch (cmd) { | ||
500 | case SNDRV_PCM_TRIGGER_START: | ||
501 | if(runtime->periods == 2) | ||
502 | snd_emu10k1x_intr_enable(emu, (INTE_CH_0_LOOP | INTE_CH_0_HALF_LOOP) << channel); | ||
503 | else | ||
504 | snd_emu10k1x_intr_enable(emu, INTE_CH_0_LOOP << channel); | ||
505 | epcm->running = 1; | ||
506 | snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0)|(TRIGGER_CHANNEL_0<<channel)); | ||
507 | break; | ||
508 | case SNDRV_PCM_TRIGGER_STOP: | ||
509 | epcm->running = 0; | ||
510 | snd_emu10k1x_intr_disable(emu, (INTE_CH_0_LOOP | INTE_CH_0_HALF_LOOP) << channel); | ||
511 | snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0) & ~(TRIGGER_CHANNEL_0<<channel)); | ||
512 | break; | ||
513 | default: | ||
514 | result = -EINVAL; | ||
515 | break; | ||
516 | } | ||
517 | return result; | ||
518 | } | ||
519 | |||
520 | /* pointer callback */ | ||
521 | static snd_pcm_uframes_t | ||
522 | snd_emu10k1x_pcm_pointer(snd_pcm_substream_t *substream) | ||
523 | { | ||
524 | emu10k1x_t *emu = snd_pcm_substream_chip(substream); | ||
525 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
526 | emu10k1x_pcm_t *epcm = runtime->private_data; | ||
527 | int channel = epcm->voice->number; | ||
528 | snd_pcm_uframes_t ptr = 0, ptr1 = 0, ptr2= 0,ptr3 = 0,ptr4 = 0; | ||
529 | |||
530 | if (!epcm->running) | ||
531 | return 0; | ||
532 | |||
533 | ptr3 = snd_emu10k1x_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | ||
534 | ptr1 = snd_emu10k1x_ptr_read(emu, PLAYBACK_POINTER, channel); | ||
535 | ptr4 = snd_emu10k1x_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | ||
536 | |||
537 | if(ptr4 == 0 && ptr1 == frames_to_bytes(runtime, runtime->buffer_size)) | ||
538 | return 0; | ||
539 | |||
540 | if (ptr3 != ptr4) | ||
541 | ptr1 = snd_emu10k1x_ptr_read(emu, PLAYBACK_POINTER, channel); | ||
542 | ptr2 = bytes_to_frames(runtime, ptr1); | ||
543 | ptr2 += (ptr4 >> 3) * runtime->period_size; | ||
544 | ptr = ptr2; | ||
545 | |||
546 | if (ptr >= runtime->buffer_size) | ||
547 | ptr -= runtime->buffer_size; | ||
548 | |||
549 | return ptr; | ||
550 | } | ||
551 | |||
552 | /* operators */ | ||
553 | static snd_pcm_ops_t snd_emu10k1x_playback_ops = { | ||
554 | .open = snd_emu10k1x_playback_open, | ||
555 | .close = snd_emu10k1x_playback_close, | ||
556 | .ioctl = snd_pcm_lib_ioctl, | ||
557 | .hw_params = snd_emu10k1x_pcm_hw_params, | ||
558 | .hw_free = snd_emu10k1x_pcm_hw_free, | ||
559 | .prepare = snd_emu10k1x_pcm_prepare, | ||
560 | .trigger = snd_emu10k1x_pcm_trigger, | ||
561 | .pointer = snd_emu10k1x_pcm_pointer, | ||
562 | }; | ||
563 | |||
564 | /* open_capture callback */ | ||
565 | static int snd_emu10k1x_pcm_open_capture(snd_pcm_substream_t *substream) | ||
566 | { | ||
567 | emu10k1x_t *chip = snd_pcm_substream_chip(substream); | ||
568 | emu10k1x_pcm_t *epcm; | ||
569 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
570 | int err; | ||
571 | |||
572 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | ||
573 | return err; | ||
574 | if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) | ||
575 | return err; | ||
576 | |||
577 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
578 | if (epcm == NULL) | ||
579 | return -ENOMEM; | ||
580 | |||
581 | epcm->emu = chip; | ||
582 | epcm->substream = substream; | ||
583 | |||
584 | runtime->private_data = epcm; | ||
585 | runtime->private_free = snd_emu10k1x_pcm_free_substream; | ||
586 | |||
587 | runtime->hw = snd_emu10k1x_capture_hw; | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | /* close callback */ | ||
593 | static int snd_emu10k1x_pcm_close_capture(snd_pcm_substream_t *substream) | ||
594 | { | ||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | /* hw_params callback */ | ||
599 | static int snd_emu10k1x_pcm_hw_params_capture(snd_pcm_substream_t *substream, | ||
600 | snd_pcm_hw_params_t * hw_params) | ||
601 | { | ||
602 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
603 | emu10k1x_pcm_t *epcm = runtime->private_data; | ||
604 | |||
605 | if (! epcm->voice) { | ||
606 | if (epcm->emu->capture_voice.use) | ||
607 | return -EBUSY; | ||
608 | epcm->voice = &epcm->emu->capture_voice; | ||
609 | epcm->voice->epcm = epcm; | ||
610 | epcm->voice->use = 1; | ||
611 | } | ||
612 | |||
613 | return snd_pcm_lib_malloc_pages(substream, | ||
614 | params_buffer_bytes(hw_params)); | ||
615 | } | ||
616 | |||
617 | /* hw_free callback */ | ||
618 | static int snd_emu10k1x_pcm_hw_free_capture(snd_pcm_substream_t *substream) | ||
619 | { | ||
620 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
621 | |||
622 | emu10k1x_pcm_t *epcm; | ||
623 | |||
624 | if (runtime->private_data == NULL) | ||
625 | return 0; | ||
626 | epcm = runtime->private_data; | ||
627 | |||
628 | if (epcm->voice) { | ||
629 | epcm->voice->use = 0; | ||
630 | epcm->voice->epcm = NULL; | ||
631 | epcm->voice = NULL; | ||
632 | } | ||
633 | |||
634 | return snd_pcm_lib_free_pages(substream); | ||
635 | } | ||
636 | |||
637 | /* prepare capture callback */ | ||
638 | static int snd_emu10k1x_pcm_prepare_capture(snd_pcm_substream_t *substream) | ||
639 | { | ||
640 | emu10k1x_t *emu = snd_pcm_substream_chip(substream); | ||
641 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
642 | |||
643 | snd_emu10k1x_ptr_write(emu, CAPTURE_DMA_ADDR, 0, runtime->dma_addr); | ||
644 | snd_emu10k1x_ptr_write(emu, CAPTURE_BUFFER_SIZE, 0, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes | ||
645 | snd_emu10k1x_ptr_write(emu, CAPTURE_POINTER, 0, 0); | ||
646 | snd_emu10k1x_ptr_write(emu, CAPTURE_UNKNOWN, 0, 0); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | /* trigger_capture callback */ | ||
652 | static int snd_emu10k1x_pcm_trigger_capture(snd_pcm_substream_t *substream, | ||
653 | int cmd) | ||
654 | { | ||
655 | emu10k1x_t *emu = snd_pcm_substream_chip(substream); | ||
656 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
657 | emu10k1x_pcm_t *epcm = runtime->private_data; | ||
658 | int result = 0; | ||
659 | |||
660 | switch (cmd) { | ||
661 | case SNDRV_PCM_TRIGGER_START: | ||
662 | snd_emu10k1x_intr_enable(emu, INTE_CAP_0_LOOP | | ||
663 | INTE_CAP_0_HALF_LOOP); | ||
664 | snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0)|TRIGGER_CAPTURE); | ||
665 | epcm->running = 1; | ||
666 | break; | ||
667 | case SNDRV_PCM_TRIGGER_STOP: | ||
668 | epcm->running = 0; | ||
669 | snd_emu10k1x_intr_disable(emu, INTE_CAP_0_LOOP | | ||
670 | INTE_CAP_0_HALF_LOOP); | ||
671 | snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0) & ~(TRIGGER_CAPTURE)); | ||
672 | break; | ||
673 | default: | ||
674 | result = -EINVAL; | ||
675 | break; | ||
676 | } | ||
677 | return result; | ||
678 | } | ||
679 | |||
680 | /* pointer_capture callback */ | ||
681 | static snd_pcm_uframes_t | ||
682 | snd_emu10k1x_pcm_pointer_capture(snd_pcm_substream_t *substream) | ||
683 | { | ||
684 | emu10k1x_t *emu = snd_pcm_substream_chip(substream); | ||
685 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
686 | emu10k1x_pcm_t *epcm = runtime->private_data; | ||
687 | snd_pcm_uframes_t ptr; | ||
688 | |||
689 | if (!epcm->running) | ||
690 | return 0; | ||
691 | |||
692 | ptr = bytes_to_frames(runtime, snd_emu10k1x_ptr_read(emu, CAPTURE_POINTER, 0)); | ||
693 | if (ptr >= runtime->buffer_size) | ||
694 | ptr -= runtime->buffer_size; | ||
695 | |||
696 | return ptr; | ||
697 | } | ||
698 | |||
699 | static snd_pcm_ops_t snd_emu10k1x_capture_ops = { | ||
700 | .open = snd_emu10k1x_pcm_open_capture, | ||
701 | .close = snd_emu10k1x_pcm_close_capture, | ||
702 | .ioctl = snd_pcm_lib_ioctl, | ||
703 | .hw_params = snd_emu10k1x_pcm_hw_params_capture, | ||
704 | .hw_free = snd_emu10k1x_pcm_hw_free_capture, | ||
705 | .prepare = snd_emu10k1x_pcm_prepare_capture, | ||
706 | .trigger = snd_emu10k1x_pcm_trigger_capture, | ||
707 | .pointer = snd_emu10k1x_pcm_pointer_capture, | ||
708 | }; | ||
709 | |||
710 | static unsigned short snd_emu10k1x_ac97_read(ac97_t *ac97, | ||
711 | unsigned short reg) | ||
712 | { | ||
713 | emu10k1x_t *emu = ac97->private_data; | ||
714 | unsigned long flags; | ||
715 | unsigned short val; | ||
716 | |||
717 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
718 | outb(reg, emu->port + AC97ADDRESS); | ||
719 | val = inw(emu->port + AC97DATA); | ||
720 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
721 | return val; | ||
722 | } | ||
723 | |||
724 | static void snd_emu10k1x_ac97_write(ac97_t *ac97, | ||
725 | unsigned short reg, unsigned short val) | ||
726 | { | ||
727 | emu10k1x_t *emu = ac97->private_data; | ||
728 | unsigned long flags; | ||
729 | |||
730 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
731 | outb(reg, emu->port + AC97ADDRESS); | ||
732 | outw(val, emu->port + AC97DATA); | ||
733 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
734 | } | ||
735 | |||
736 | static int snd_emu10k1x_ac97(emu10k1x_t *chip) | ||
737 | { | ||
738 | ac97_bus_t *pbus; | ||
739 | ac97_template_t ac97; | ||
740 | int err; | ||
741 | static ac97_bus_ops_t ops = { | ||
742 | .write = snd_emu10k1x_ac97_write, | ||
743 | .read = snd_emu10k1x_ac97_read, | ||
744 | }; | ||
745 | |||
746 | if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) | ||
747 | return err; | ||
748 | pbus->no_vra = 1; /* we don't need VRA */ | ||
749 | |||
750 | memset(&ac97, 0, sizeof(ac97)); | ||
751 | ac97.private_data = chip; | ||
752 | ac97.scaps = AC97_SCAP_NO_SPDIF; | ||
753 | return snd_ac97_mixer(pbus, &ac97, &chip->ac97); | ||
754 | } | ||
755 | |||
756 | static int snd_emu10k1x_free(emu10k1x_t *chip) | ||
757 | { | ||
758 | snd_emu10k1x_ptr_write(chip, TRIGGER_CHANNEL, 0, 0); | ||
759 | // disable interrupts | ||
760 | outl(0, chip->port + INTE); | ||
761 | // disable audio | ||
762 | outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); | ||
763 | |||
764 | // release the i/o port | ||
765 | if (chip->res_port) { | ||
766 | release_resource(chip->res_port); | ||
767 | kfree_nocheck(chip->res_port); | ||
768 | } | ||
769 | // release the irq | ||
770 | if (chip->irq >= 0) | ||
771 | free_irq(chip->irq, (void *)chip); | ||
772 | |||
773 | // release the DMA | ||
774 | if (chip->dma_buffer.area) { | ||
775 | snd_dma_free_pages(&chip->dma_buffer); | ||
776 | } | ||
777 | |||
778 | pci_disable_device(chip->pci); | ||
779 | |||
780 | // release the data | ||
781 | kfree(chip); | ||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static int snd_emu10k1x_dev_free(snd_device_t *device) | ||
786 | { | ||
787 | emu10k1x_t *chip = device->device_data; | ||
788 | return snd_emu10k1x_free(chip); | ||
789 | } | ||
790 | |||
791 | static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id, | ||
792 | struct pt_regs *regs) | ||
793 | { | ||
794 | unsigned int status; | ||
795 | |||
796 | emu10k1x_t *chip = dev_id; | ||
797 | emu10k1x_voice_t *pvoice = chip->voices; | ||
798 | int i; | ||
799 | int mask; | ||
800 | |||
801 | status = inl(chip->port + IPR); | ||
802 | |||
803 | if(status) { | ||
804 | // capture interrupt | ||
805 | if(status & (IPR_CAP_0_LOOP | IPR_CAP_0_HALF_LOOP)) { | ||
806 | emu10k1x_voice_t *pvoice = &chip->capture_voice; | ||
807 | if(pvoice->use) | ||
808 | snd_emu10k1x_pcm_interrupt(chip, pvoice); | ||
809 | else | ||
810 | snd_emu10k1x_intr_disable(chip, | ||
811 | INTE_CAP_0_LOOP | | ||
812 | INTE_CAP_0_HALF_LOOP); | ||
813 | } | ||
814 | |||
815 | mask = IPR_CH_0_LOOP|IPR_CH_0_HALF_LOOP; | ||
816 | for(i = 0; i < 3; i++) { | ||
817 | if(status & mask) { | ||
818 | if(pvoice->use) | ||
819 | snd_emu10k1x_pcm_interrupt(chip, pvoice); | ||
820 | else | ||
821 | snd_emu10k1x_intr_disable(chip, mask); | ||
822 | } | ||
823 | pvoice++; | ||
824 | mask <<= 1; | ||
825 | } | ||
826 | |||
827 | if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) { | ||
828 | if (chip->midi.interrupt) | ||
829 | chip->midi.interrupt(chip, status); | ||
830 | else | ||
831 | snd_emu10k1x_intr_disable(chip, INTE_MIDITXENABLE|INTE_MIDIRXENABLE); | ||
832 | } | ||
833 | |||
834 | // acknowledge the interrupt if necessary | ||
835 | if(status) | ||
836 | outl(status, chip->port+IPR); | ||
837 | |||
838 | // snd_printk(KERN_INFO "interrupt %08x\n", status); | ||
839 | } | ||
840 | |||
841 | return IRQ_HANDLED; | ||
842 | } | ||
843 | |||
844 | static void snd_emu10k1x_pcm_free(snd_pcm_t *pcm) | ||
845 | { | ||
846 | emu10k1x_t *emu = pcm->private_data; | ||
847 | emu->pcm = NULL; | ||
848 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
849 | } | ||
850 | |||
851 | static int __devinit snd_emu10k1x_pcm(emu10k1x_t *emu, int device, snd_pcm_t **rpcm) | ||
852 | { | ||
853 | snd_pcm_t *pcm; | ||
854 | int err; | ||
855 | int capture = 0; | ||
856 | |||
857 | if (rpcm) | ||
858 | *rpcm = NULL; | ||
859 | if (device == 0) | ||
860 | capture = 1; | ||
861 | |||
862 | if ((err = snd_pcm_new(emu->card, "emu10k1x", device, 1, capture, &pcm)) < 0) | ||
863 | return err; | ||
864 | |||
865 | pcm->private_data = emu; | ||
866 | pcm->private_free = snd_emu10k1x_pcm_free; | ||
867 | |||
868 | switch(device) { | ||
869 | case 0: | ||
870 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1x_playback_ops); | ||
871 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1x_capture_ops); | ||
872 | break; | ||
873 | case 1: | ||
874 | case 2: | ||
875 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1x_playback_ops); | ||
876 | break; | ||
877 | } | ||
878 | |||
879 | pcm->info_flags = 0; | ||
880 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | ||
881 | switch(device) { | ||
882 | case 0: | ||
883 | strcpy(pcm->name, "EMU10K1X Front"); | ||
884 | break; | ||
885 | case 1: | ||
886 | strcpy(pcm->name, "EMU10K1X Rear"); | ||
887 | break; | ||
888 | case 2: | ||
889 | strcpy(pcm->name, "EMU10K1X Center/LFE"); | ||
890 | break; | ||
891 | } | ||
892 | emu->pcm = pcm; | ||
893 | |||
894 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
895 | snd_dma_pci_data(emu->pci), | ||
896 | 32*1024, 32*1024); | ||
897 | |||
898 | if (rpcm) | ||
899 | *rpcm = pcm; | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static int __devinit snd_emu10k1x_create(snd_card_t *card, | ||
905 | struct pci_dev *pci, | ||
906 | emu10k1x_t **rchip) | ||
907 | { | ||
908 | emu10k1x_t *chip; | ||
909 | int err; | ||
910 | int ch; | ||
911 | static snd_device_ops_t ops = { | ||
912 | .dev_free = snd_emu10k1x_dev_free, | ||
913 | }; | ||
914 | |||
915 | *rchip = NULL; | ||
916 | |||
917 | if ((err = pci_enable_device(pci)) < 0) | ||
918 | return err; | ||
919 | if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || | ||
920 | pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { | ||
921 | snd_printk(KERN_ERR "error to set 28bit mask DMA\n"); | ||
922 | pci_disable_device(pci); | ||
923 | return -ENXIO; | ||
924 | } | ||
925 | |||
926 | chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); | ||
927 | if (chip == NULL) { | ||
928 | pci_disable_device(pci); | ||
929 | return -ENOMEM; | ||
930 | } | ||
931 | |||
932 | chip->card = card; | ||
933 | chip->pci = pci; | ||
934 | chip->irq = -1; | ||
935 | |||
936 | spin_lock_init(&chip->emu_lock); | ||
937 | spin_lock_init(&chip->voice_lock); | ||
938 | |||
939 | chip->port = pci_resource_start(pci, 0); | ||
940 | if ((chip->res_port = request_region(chip->port, 8, | ||
941 | "EMU10K1X")) == NULL) { | ||
942 | snd_printk(KERN_ERR "emu10k1x: cannot allocate the port 0x%lx\n", chip->port); | ||
943 | snd_emu10k1x_free(chip); | ||
944 | return -EBUSY; | ||
945 | } | ||
946 | |||
947 | if (request_irq(pci->irq, snd_emu10k1x_interrupt, | ||
948 | SA_INTERRUPT|SA_SHIRQ, "EMU10K1X", | ||
949 | (void *)chip)) { | ||
950 | snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq); | ||
951 | snd_emu10k1x_free(chip); | ||
952 | return -EBUSY; | ||
953 | } | ||
954 | chip->irq = pci->irq; | ||
955 | |||
956 | if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), | ||
957 | 4 * 1024, &chip->dma_buffer) < 0) { | ||
958 | snd_emu10k1x_free(chip); | ||
959 | return -ENOMEM; | ||
960 | } | ||
961 | |||
962 | pci_set_master(pci); | ||
963 | /* read revision & serial */ | ||
964 | pci_read_config_byte(pci, PCI_REVISION_ID, (char *)&chip->revision); | ||
965 | pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); | ||
966 | pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); | ||
967 | snd_printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model, | ||
968 | chip->revision, chip->serial); | ||
969 | |||
970 | outl(0, chip->port + INTE); | ||
971 | |||
972 | for(ch = 0; ch < 3; ch++) { | ||
973 | chip->voices[ch].emu = chip; | ||
974 | chip->voices[ch].number = ch; | ||
975 | } | ||
976 | |||
977 | /* | ||
978 | * Init to 0x02109204 : | ||
979 | * Clock accuracy = 0 (1000ppm) | ||
980 | * Sample Rate = 2 (48kHz) | ||
981 | * Audio Channel = 1 (Left of 2) | ||
982 | * Source Number = 0 (Unspecified) | ||
983 | * Generation Status = 1 (Original for Cat Code 12) | ||
984 | * Cat Code = 12 (Digital Signal Mixer) | ||
985 | * Mode = 0 (Mode 0) | ||
986 | * Emphasis = 0 (None) | ||
987 | * CP = 1 (Copyright unasserted) | ||
988 | * AN = 0 (Audio data) | ||
989 | * P = 0 (Consumer) | ||
990 | */ | ||
991 | snd_emu10k1x_ptr_write(chip, SPCS0, 0, | ||
992 | chip->spdif_bits[0] = | ||
993 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
994 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
995 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
996 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
997 | snd_emu10k1x_ptr_write(chip, SPCS1, 0, | ||
998 | chip->spdif_bits[1] = | ||
999 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
1000 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
1001 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
1002 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
1003 | snd_emu10k1x_ptr_write(chip, SPCS2, 0, | ||
1004 | chip->spdif_bits[2] = | ||
1005 | SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
1006 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | | ||
1007 | SPCS_GENERATIONSTATUS | 0x00001200 | | ||
1008 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); | ||
1009 | |||
1010 | snd_emu10k1x_ptr_write(chip, SPDIF_SELECT, 0, 0x700); // disable SPDIF | ||
1011 | snd_emu10k1x_ptr_write(chip, ROUTING, 0, 0x1003F); // routing | ||
1012 | snd_emu10k1x_gpio_write(chip, 0x1080); // analog mode | ||
1013 | |||
1014 | outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); | ||
1015 | |||
1016 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, | ||
1017 | chip, &ops)) < 0) { | ||
1018 | snd_emu10k1x_free(chip); | ||
1019 | return err; | ||
1020 | } | ||
1021 | *rchip = chip; | ||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | static void snd_emu10k1x_proc_reg_read(snd_info_entry_t *entry, | ||
1026 | snd_info_buffer_t * buffer) | ||
1027 | { | ||
1028 | emu10k1x_t *emu = entry->private_data; | ||
1029 | unsigned long value,value1,value2; | ||
1030 | unsigned long flags; | ||
1031 | int i; | ||
1032 | |||
1033 | snd_iprintf(buffer, "Registers:\n\n"); | ||
1034 | for(i = 0; i < 0x20; i+=4) { | ||
1035 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
1036 | value = inl(emu->port + i); | ||
1037 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
1038 | snd_iprintf(buffer, "Register %02X: %08lX\n", i, value); | ||
1039 | } | ||
1040 | snd_iprintf(buffer, "\nRegisters\n\n"); | ||
1041 | for(i = 0; i <= 0x48; i++) { | ||
1042 | value = snd_emu10k1x_ptr_read(emu, i, 0); | ||
1043 | if(i < 0x10 || (i >= 0x20 && i < 0x40)) { | ||
1044 | value1 = snd_emu10k1x_ptr_read(emu, i, 1); | ||
1045 | value2 = snd_emu10k1x_ptr_read(emu, i, 2); | ||
1046 | snd_iprintf(buffer, "%02X: %08lX %08lX %08lX\n", i, value, value1, value2); | ||
1047 | } else { | ||
1048 | snd_iprintf(buffer, "%02X: %08lX\n", i, value); | ||
1049 | } | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | static void snd_emu10k1x_proc_reg_write(snd_info_entry_t *entry, | ||
1054 | snd_info_buffer_t *buffer) | ||
1055 | { | ||
1056 | emu10k1x_t *emu = entry->private_data; | ||
1057 | char line[64]; | ||
1058 | unsigned int reg, channel_id , val; | ||
1059 | |||
1060 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | ||
1061 | if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) | ||
1062 | continue; | ||
1063 | |||
1064 | if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff) | ||
1065 | && (channel_id >=0) && (channel_id <= 2) ) | ||
1066 | snd_emu10k1x_ptr_write(emu, reg, channel_id, val); | ||
1067 | } | ||
1068 | } | ||
1069 | |||
1070 | static int __devinit snd_emu10k1x_proc_init(emu10k1x_t * emu) | ||
1071 | { | ||
1072 | snd_info_entry_t *entry; | ||
1073 | |||
1074 | if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) { | ||
1075 | snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read); | ||
1076 | entry->c.text.write_size = 64; | ||
1077 | entry->c.text.write = snd_emu10k1x_proc_reg_write; | ||
1078 | entry->private_data = emu; | ||
1079 | } | ||
1080 | |||
1081 | return 0; | ||
1082 | } | ||
1083 | |||
1084 | static int snd_emu10k1x_shared_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
1085 | { | ||
1086 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1087 | uinfo->count = 1; | ||
1088 | uinfo->value.integer.min = 0; | ||
1089 | uinfo->value.integer.max = 1; | ||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | static int snd_emu10k1x_shared_spdif_get(snd_kcontrol_t * kcontrol, | ||
1094 | snd_ctl_elem_value_t * ucontrol) | ||
1095 | { | ||
1096 | emu10k1x_t *emu = snd_kcontrol_chip(kcontrol); | ||
1097 | |||
1098 | ucontrol->value.integer.value[0] = (snd_emu10k1x_ptr_read(emu, SPDIF_SELECT, 0) == 0x700) ? 0 : 1; | ||
1099 | |||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static int snd_emu10k1x_shared_spdif_put(snd_kcontrol_t * kcontrol, | ||
1104 | snd_ctl_elem_value_t * ucontrol) | ||
1105 | { | ||
1106 | emu10k1x_t *emu = snd_kcontrol_chip(kcontrol); | ||
1107 | unsigned int val; | ||
1108 | int change = 0; | ||
1109 | |||
1110 | val = ucontrol->value.integer.value[0] ; | ||
1111 | |||
1112 | if (val) { | ||
1113 | // enable spdif output | ||
1114 | snd_emu10k1x_ptr_write(emu, SPDIF_SELECT, 0, 0x000); | ||
1115 | snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x700); | ||
1116 | snd_emu10k1x_gpio_write(emu, 0x1000); | ||
1117 | } else { | ||
1118 | // disable spdif output | ||
1119 | snd_emu10k1x_ptr_write(emu, SPDIF_SELECT, 0, 0x700); | ||
1120 | snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x1003F); | ||
1121 | snd_emu10k1x_gpio_write(emu, 0x1080); | ||
1122 | } | ||
1123 | return change; | ||
1124 | } | ||
1125 | |||
1126 | static snd_kcontrol_new_t snd_emu10k1x_shared_spdif __devinitdata = | ||
1127 | { | ||
1128 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1129 | .name = "Analog/Digital Output Jack", | ||
1130 | .info = snd_emu10k1x_shared_spdif_info, | ||
1131 | .get = snd_emu10k1x_shared_spdif_get, | ||
1132 | .put = snd_emu10k1x_shared_spdif_put | ||
1133 | }; | ||
1134 | |||
1135 | static int snd_emu10k1x_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
1136 | { | ||
1137 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
1138 | uinfo->count = 1; | ||
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static int snd_emu10k1x_spdif_get(snd_kcontrol_t * kcontrol, | ||
1143 | snd_ctl_elem_value_t * ucontrol) | ||
1144 | { | ||
1145 | emu10k1x_t *emu = snd_kcontrol_chip(kcontrol); | ||
1146 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
1147 | |||
1148 | ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; | ||
1149 | ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; | ||
1150 | ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; | ||
1151 | ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | static int snd_emu10k1x_spdif_get_mask(snd_kcontrol_t * kcontrol, | ||
1156 | snd_ctl_elem_value_t * ucontrol) | ||
1157 | { | ||
1158 | ucontrol->value.iec958.status[0] = 0xff; | ||
1159 | ucontrol->value.iec958.status[1] = 0xff; | ||
1160 | ucontrol->value.iec958.status[2] = 0xff; | ||
1161 | ucontrol->value.iec958.status[3] = 0xff; | ||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | static int snd_emu10k1x_spdif_put(snd_kcontrol_t * kcontrol, | ||
1166 | snd_ctl_elem_value_t * ucontrol) | ||
1167 | { | ||
1168 | emu10k1x_t *emu = snd_kcontrol_chip(kcontrol); | ||
1169 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
1170 | int change; | ||
1171 | unsigned int val; | ||
1172 | |||
1173 | val = (ucontrol->value.iec958.status[0] << 0) | | ||
1174 | (ucontrol->value.iec958.status[1] << 8) | | ||
1175 | (ucontrol->value.iec958.status[2] << 16) | | ||
1176 | (ucontrol->value.iec958.status[3] << 24); | ||
1177 | change = val != emu->spdif_bits[idx]; | ||
1178 | if (change) { | ||
1179 | snd_emu10k1x_ptr_write(emu, SPCS0 + idx, 0, val); | ||
1180 | emu->spdif_bits[idx] = val; | ||
1181 | } | ||
1182 | return change; | ||
1183 | } | ||
1184 | |||
1185 | static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control = | ||
1186 | { | ||
1187 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
1188 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1189 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), | ||
1190 | .count = 3, | ||
1191 | .info = snd_emu10k1x_spdif_info, | ||
1192 | .get = snd_emu10k1x_spdif_get_mask | ||
1193 | }; | ||
1194 | |||
1195 | static snd_kcontrol_new_t snd_emu10k1x_spdif_control = | ||
1196 | { | ||
1197 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1198 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | ||
1199 | .count = 3, | ||
1200 | .info = snd_emu10k1x_spdif_info, | ||
1201 | .get = snd_emu10k1x_spdif_get, | ||
1202 | .put = snd_emu10k1x_spdif_put | ||
1203 | }; | ||
1204 | |||
1205 | static int __devinit snd_emu10k1x_mixer(emu10k1x_t *emu) | ||
1206 | { | ||
1207 | int err; | ||
1208 | snd_kcontrol_t *kctl; | ||
1209 | snd_card_t *card = emu->card; | ||
1210 | |||
1211 | if ((kctl = snd_ctl_new1(&snd_emu10k1x_spdif_mask_control, emu)) == NULL) | ||
1212 | return -ENOMEM; | ||
1213 | if ((err = snd_ctl_add(card, kctl))) | ||
1214 | return err; | ||
1215 | if ((kctl = snd_ctl_new1(&snd_emu10k1x_shared_spdif, emu)) == NULL) | ||
1216 | return -ENOMEM; | ||
1217 | if ((err = snd_ctl_add(card, kctl))) | ||
1218 | return err; | ||
1219 | if ((kctl = snd_ctl_new1(&snd_emu10k1x_spdif_control, emu)) == NULL) | ||
1220 | return -ENOMEM; | ||
1221 | if ((err = snd_ctl_add(card, kctl))) | ||
1222 | return err; | ||
1223 | |||
1224 | return 0; | ||
1225 | } | ||
1226 | |||
1227 | #define EMU10K1X_MIDI_MODE_INPUT (1<<0) | ||
1228 | #define EMU10K1X_MIDI_MODE_OUTPUT (1<<1) | ||
1229 | |||
1230 | static inline unsigned char mpu401_read(emu10k1x_t *emu, emu10k1x_midi_t *mpu, int idx) | ||
1231 | { | ||
1232 | return (unsigned char)snd_emu10k1x_ptr_read(emu, mpu->port + idx, 0); | ||
1233 | } | ||
1234 | |||
1235 | static inline void mpu401_write(emu10k1x_t *emu, emu10k1x_midi_t *mpu, int data, int idx) | ||
1236 | { | ||
1237 | snd_emu10k1x_ptr_write(emu, mpu->port + idx, 0, data); | ||
1238 | } | ||
1239 | |||
1240 | #define mpu401_write_data(emu, mpu, data) mpu401_write(emu, mpu, data, 0) | ||
1241 | #define mpu401_write_cmd(emu, mpu, data) mpu401_write(emu, mpu, data, 1) | ||
1242 | #define mpu401_read_data(emu, mpu) mpu401_read(emu, mpu, 0) | ||
1243 | #define mpu401_read_stat(emu, mpu) mpu401_read(emu, mpu, 1) | ||
1244 | |||
1245 | #define mpu401_input_avail(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x80)) | ||
1246 | #define mpu401_output_ready(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x40)) | ||
1247 | |||
1248 | #define MPU401_RESET 0xff | ||
1249 | #define MPU401_ENTER_UART 0x3f | ||
1250 | #define MPU401_ACK 0xfe | ||
1251 | |||
1252 | static void mpu401_clear_rx(emu10k1x_t *emu, emu10k1x_midi_t *mpu) | ||
1253 | { | ||
1254 | int timeout = 100000; | ||
1255 | for (; timeout > 0 && mpu401_input_avail(emu, mpu); timeout--) | ||
1256 | mpu401_read_data(emu, mpu); | ||
1257 | #ifdef CONFIG_SND_DEBUG | ||
1258 | if (timeout <= 0) | ||
1259 | snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu)); | ||
1260 | #endif | ||
1261 | } | ||
1262 | |||
1263 | /* | ||
1264 | |||
1265 | */ | ||
1266 | |||
1267 | static void do_emu10k1x_midi_interrupt(emu10k1x_t *emu, emu10k1x_midi_t *midi, unsigned int status) | ||
1268 | { | ||
1269 | unsigned char byte; | ||
1270 | |||
1271 | if (midi->rmidi == NULL) { | ||
1272 | snd_emu10k1x_intr_disable(emu, midi->tx_enable | midi->rx_enable); | ||
1273 | return; | ||
1274 | } | ||
1275 | |||
1276 | spin_lock(&midi->input_lock); | ||
1277 | if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { | ||
1278 | if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { | ||
1279 | mpu401_clear_rx(emu, midi); | ||
1280 | } else { | ||
1281 | byte = mpu401_read_data(emu, midi); | ||
1282 | if (midi->substream_input) | ||
1283 | snd_rawmidi_receive(midi->substream_input, &byte, 1); | ||
1284 | } | ||
1285 | } | ||
1286 | spin_unlock(&midi->input_lock); | ||
1287 | |||
1288 | spin_lock(&midi->output_lock); | ||
1289 | if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { | ||
1290 | if (midi->substream_output && | ||
1291 | snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { | ||
1292 | mpu401_write_data(emu, midi, byte); | ||
1293 | } else { | ||
1294 | snd_emu10k1x_intr_disable(emu, midi->tx_enable); | ||
1295 | } | ||
1296 | } | ||
1297 | spin_unlock(&midi->output_lock); | ||
1298 | } | ||
1299 | |||
1300 | static void snd_emu10k1x_midi_interrupt(emu10k1x_t *emu, unsigned int status) | ||
1301 | { | ||
1302 | do_emu10k1x_midi_interrupt(emu, &emu->midi, status); | ||
1303 | } | ||
1304 | |||
1305 | static void snd_emu10k1x_midi_cmd(emu10k1x_t * emu, emu10k1x_midi_t *midi, unsigned char cmd, int ack) | ||
1306 | { | ||
1307 | unsigned long flags; | ||
1308 | int timeout, ok; | ||
1309 | |||
1310 | spin_lock_irqsave(&midi->input_lock, flags); | ||
1311 | mpu401_write_data(emu, midi, 0x00); | ||
1312 | /* mpu401_clear_rx(emu, midi); */ | ||
1313 | |||
1314 | mpu401_write_cmd(emu, midi, cmd); | ||
1315 | if (ack) { | ||
1316 | ok = 0; | ||
1317 | timeout = 10000; | ||
1318 | while (!ok && timeout-- > 0) { | ||
1319 | if (mpu401_input_avail(emu, midi)) { | ||
1320 | if (mpu401_read_data(emu, midi) == MPU401_ACK) | ||
1321 | ok = 1; | ||
1322 | } | ||
1323 | } | ||
1324 | if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK) | ||
1325 | ok = 1; | ||
1326 | } else { | ||
1327 | ok = 1; | ||
1328 | } | ||
1329 | spin_unlock_irqrestore(&midi->input_lock, flags); | ||
1330 | if (!ok) | ||
1331 | snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", | ||
1332 | cmd, emu->port, | ||
1333 | mpu401_read_stat(emu, midi), | ||
1334 | mpu401_read_data(emu, midi)); | ||
1335 | } | ||
1336 | |||
1337 | static int snd_emu10k1x_midi_input_open(snd_rawmidi_substream_t * substream) | ||
1338 | { | ||
1339 | emu10k1x_t *emu; | ||
1340 | emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; | ||
1341 | unsigned long flags; | ||
1342 | |||
1343 | emu = midi->emu; | ||
1344 | snd_assert(emu, return -ENXIO); | ||
1345 | spin_lock_irqsave(&midi->open_lock, flags); | ||
1346 | midi->midi_mode |= EMU10K1X_MIDI_MODE_INPUT; | ||
1347 | midi->substream_input = substream; | ||
1348 | if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) { | ||
1349 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
1350 | snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1); | ||
1351 | snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1); | ||
1352 | } else { | ||
1353 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
1354 | } | ||
1355 | return 0; | ||
1356 | } | ||
1357 | |||
1358 | static int snd_emu10k1x_midi_output_open(snd_rawmidi_substream_t * substream) | ||
1359 | { | ||
1360 | emu10k1x_t *emu; | ||
1361 | emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; | ||
1362 | unsigned long flags; | ||
1363 | |||
1364 | emu = midi->emu; | ||
1365 | snd_assert(emu, return -ENXIO); | ||
1366 | spin_lock_irqsave(&midi->open_lock, flags); | ||
1367 | midi->midi_mode |= EMU10K1X_MIDI_MODE_OUTPUT; | ||
1368 | midi->substream_output = substream; | ||
1369 | if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { | ||
1370 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
1371 | snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 1); | ||
1372 | snd_emu10k1x_midi_cmd(emu, midi, MPU401_ENTER_UART, 1); | ||
1373 | } else { | ||
1374 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
1375 | } | ||
1376 | return 0; | ||
1377 | } | ||
1378 | |||
1379 | static int snd_emu10k1x_midi_input_close(snd_rawmidi_substream_t * substream) | ||
1380 | { | ||
1381 | emu10k1x_t *emu; | ||
1382 | emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; | ||
1383 | unsigned long flags; | ||
1384 | |||
1385 | emu = midi->emu; | ||
1386 | snd_assert(emu, return -ENXIO); | ||
1387 | spin_lock_irqsave(&midi->open_lock, flags); | ||
1388 | snd_emu10k1x_intr_disable(emu, midi->rx_enable); | ||
1389 | midi->midi_mode &= ~EMU10K1X_MIDI_MODE_INPUT; | ||
1390 | midi->substream_input = NULL; | ||
1391 | if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT)) { | ||
1392 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
1393 | snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0); | ||
1394 | } else { | ||
1395 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
1396 | } | ||
1397 | return 0; | ||
1398 | } | ||
1399 | |||
1400 | static int snd_emu10k1x_midi_output_close(snd_rawmidi_substream_t * substream) | ||
1401 | { | ||
1402 | emu10k1x_t *emu; | ||
1403 | emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; | ||
1404 | unsigned long flags; | ||
1405 | |||
1406 | emu = midi->emu; | ||
1407 | snd_assert(emu, return -ENXIO); | ||
1408 | spin_lock_irqsave(&midi->open_lock, flags); | ||
1409 | snd_emu10k1x_intr_disable(emu, midi->tx_enable); | ||
1410 | midi->midi_mode &= ~EMU10K1X_MIDI_MODE_OUTPUT; | ||
1411 | midi->substream_output = NULL; | ||
1412 | if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_INPUT)) { | ||
1413 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
1414 | snd_emu10k1x_midi_cmd(emu, midi, MPU401_RESET, 0); | ||
1415 | } else { | ||
1416 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
1417 | } | ||
1418 | return 0; | ||
1419 | } | ||
1420 | |||
1421 | static void snd_emu10k1x_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) | ||
1422 | { | ||
1423 | emu10k1x_t *emu; | ||
1424 | emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; | ||
1425 | emu = midi->emu; | ||
1426 | snd_assert(emu, return); | ||
1427 | |||
1428 | if (up) | ||
1429 | snd_emu10k1x_intr_enable(emu, midi->rx_enable); | ||
1430 | else | ||
1431 | snd_emu10k1x_intr_disable(emu, midi->rx_enable); | ||
1432 | } | ||
1433 | |||
1434 | static void snd_emu10k1x_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) | ||
1435 | { | ||
1436 | emu10k1x_t *emu; | ||
1437 | emu10k1x_midi_t *midi = (emu10k1x_midi_t *)substream->rmidi->private_data; | ||
1438 | unsigned long flags; | ||
1439 | |||
1440 | emu = midi->emu; | ||
1441 | snd_assert(emu, return); | ||
1442 | |||
1443 | if (up) { | ||
1444 | int max = 4; | ||
1445 | unsigned char byte; | ||
1446 | |||
1447 | /* try to send some amount of bytes here before interrupts */ | ||
1448 | spin_lock_irqsave(&midi->output_lock, flags); | ||
1449 | while (max > 0) { | ||
1450 | if (mpu401_output_ready(emu, midi)) { | ||
1451 | if (!(midi->midi_mode & EMU10K1X_MIDI_MODE_OUTPUT) || | ||
1452 | snd_rawmidi_transmit(substream, &byte, 1) != 1) { | ||
1453 | /* no more data */ | ||
1454 | spin_unlock_irqrestore(&midi->output_lock, flags); | ||
1455 | return; | ||
1456 | } | ||
1457 | mpu401_write_data(emu, midi, byte); | ||
1458 | max--; | ||
1459 | } else { | ||
1460 | break; | ||
1461 | } | ||
1462 | } | ||
1463 | spin_unlock_irqrestore(&midi->output_lock, flags); | ||
1464 | snd_emu10k1x_intr_enable(emu, midi->tx_enable); | ||
1465 | } else { | ||
1466 | snd_emu10k1x_intr_disable(emu, midi->tx_enable); | ||
1467 | } | ||
1468 | } | ||
1469 | |||
1470 | /* | ||
1471 | |||
1472 | */ | ||
1473 | |||
1474 | static snd_rawmidi_ops_t snd_emu10k1x_midi_output = | ||
1475 | { | ||
1476 | .open = snd_emu10k1x_midi_output_open, | ||
1477 | .close = snd_emu10k1x_midi_output_close, | ||
1478 | .trigger = snd_emu10k1x_midi_output_trigger, | ||
1479 | }; | ||
1480 | |||
1481 | static snd_rawmidi_ops_t snd_emu10k1x_midi_input = | ||
1482 | { | ||
1483 | .open = snd_emu10k1x_midi_input_open, | ||
1484 | .close = snd_emu10k1x_midi_input_close, | ||
1485 | .trigger = snd_emu10k1x_midi_input_trigger, | ||
1486 | }; | ||
1487 | |||
1488 | static void snd_emu10k1x_midi_free(snd_rawmidi_t *rmidi) | ||
1489 | { | ||
1490 | emu10k1x_midi_t *midi = (emu10k1x_midi_t *)rmidi->private_data; | ||
1491 | midi->interrupt = NULL; | ||
1492 | midi->rmidi = NULL; | ||
1493 | } | ||
1494 | |||
1495 | static int __devinit emu10k1x_midi_init(emu10k1x_t *emu, emu10k1x_midi_t *midi, int device, char *name) | ||
1496 | { | ||
1497 | snd_rawmidi_t *rmidi; | ||
1498 | int err; | ||
1499 | |||
1500 | if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0) | ||
1501 | return err; | ||
1502 | midi->emu = emu; | ||
1503 | spin_lock_init(&midi->open_lock); | ||
1504 | spin_lock_init(&midi->input_lock); | ||
1505 | spin_lock_init(&midi->output_lock); | ||
1506 | strcpy(rmidi->name, name); | ||
1507 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1x_midi_output); | ||
1508 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1x_midi_input); | ||
1509 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | | ||
1510 | SNDRV_RAWMIDI_INFO_INPUT | | ||
1511 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
1512 | rmidi->private_data = midi; | ||
1513 | rmidi->private_free = snd_emu10k1x_midi_free; | ||
1514 | midi->rmidi = rmidi; | ||
1515 | return 0; | ||
1516 | } | ||
1517 | |||
1518 | static int __devinit snd_emu10k1x_midi(emu10k1x_t *emu) | ||
1519 | { | ||
1520 | emu10k1x_midi_t *midi = &emu->midi; | ||
1521 | int err; | ||
1522 | |||
1523 | if ((err = emu10k1x_midi_init(emu, midi, 0, "EMU10K1X MPU-401 (UART)")) < 0) | ||
1524 | return err; | ||
1525 | |||
1526 | midi->tx_enable = INTE_MIDITXENABLE; | ||
1527 | midi->rx_enable = INTE_MIDIRXENABLE; | ||
1528 | midi->port = MUDATA; | ||
1529 | midi->ipr_tx = IPR_MIDITRANSBUFEMPTY; | ||
1530 | midi->ipr_rx = IPR_MIDIRECVBUFEMPTY; | ||
1531 | midi->interrupt = snd_emu10k1x_midi_interrupt; | ||
1532 | return 0; | ||
1533 | } | ||
1534 | |||
1535 | static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, | ||
1536 | const struct pci_device_id *pci_id) | ||
1537 | { | ||
1538 | static int dev; | ||
1539 | snd_card_t *card; | ||
1540 | emu10k1x_t *chip; | ||
1541 | int err; | ||
1542 | |||
1543 | if (dev >= SNDRV_CARDS) | ||
1544 | return -ENODEV; | ||
1545 | if (!enable[dev]) { | ||
1546 | dev++; | ||
1547 | return -ENOENT; | ||
1548 | } | ||
1549 | |||
1550 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | ||
1551 | if (card == NULL) | ||
1552 | return -ENOMEM; | ||
1553 | |||
1554 | if ((err = snd_emu10k1x_create(card, pci, &chip)) < 0) { | ||
1555 | snd_card_free(card); | ||
1556 | return err; | ||
1557 | } | ||
1558 | |||
1559 | if ((err = snd_emu10k1x_pcm(chip, 0, NULL)) < 0) { | ||
1560 | snd_card_free(card); | ||
1561 | return err; | ||
1562 | } | ||
1563 | if ((err = snd_emu10k1x_pcm(chip, 1, NULL)) < 0) { | ||
1564 | snd_card_free(card); | ||
1565 | return err; | ||
1566 | } | ||
1567 | if ((err = snd_emu10k1x_pcm(chip, 2, NULL)) < 0) { | ||
1568 | snd_card_free(card); | ||
1569 | return err; | ||
1570 | } | ||
1571 | |||
1572 | if ((err = snd_emu10k1x_ac97(chip)) < 0) { | ||
1573 | snd_card_free(card); | ||
1574 | return err; | ||
1575 | } | ||
1576 | |||
1577 | if ((err = snd_emu10k1x_mixer(chip)) < 0) { | ||
1578 | snd_card_free(card); | ||
1579 | return err; | ||
1580 | } | ||
1581 | |||
1582 | if ((err = snd_emu10k1x_midi(chip)) < 0) { | ||
1583 | snd_card_free(card); | ||
1584 | return err; | ||
1585 | } | ||
1586 | |||
1587 | snd_emu10k1x_proc_init(chip); | ||
1588 | |||
1589 | strcpy(card->driver, "EMU10K1X"); | ||
1590 | strcpy(card->shortname, "Dell Sound Blaster Live!"); | ||
1591 | sprintf(card->longname, "%s at 0x%lx irq %i", | ||
1592 | card->shortname, chip->port, chip->irq); | ||
1593 | |||
1594 | if ((err = snd_card_register(card)) < 0) { | ||
1595 | snd_card_free(card); | ||
1596 | return err; | ||
1597 | } | ||
1598 | |||
1599 | pci_set_drvdata(pci, card); | ||
1600 | dev++; | ||
1601 | return 0; | ||
1602 | } | ||
1603 | |||
1604 | static void __devexit snd_emu10k1x_remove(struct pci_dev *pci) | ||
1605 | { | ||
1606 | snd_card_free(pci_get_drvdata(pci)); | ||
1607 | pci_set_drvdata(pci, NULL); | ||
1608 | } | ||
1609 | |||
1610 | // PCI IDs | ||
1611 | static struct pci_device_id snd_emu10k1x_ids[] = { | ||
1612 | { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM version (EMU10K1) */ | ||
1613 | { 0, } | ||
1614 | }; | ||
1615 | MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids); | ||
1616 | |||
1617 | // pci_driver definition | ||
1618 | static struct pci_driver driver = { | ||
1619 | .name = "EMU10K1X", | ||
1620 | .id_table = snd_emu10k1x_ids, | ||
1621 | .probe = snd_emu10k1x_probe, | ||
1622 | .remove = __devexit_p(snd_emu10k1x_remove), | ||
1623 | }; | ||
1624 | |||
1625 | // initialization of the module | ||
1626 | static int __init alsa_card_emu10k1x_init(void) | ||
1627 | { | ||
1628 | int err; | ||
1629 | |||
1630 | if ((err = pci_module_init(&driver)) > 0) | ||
1631 | return err; | ||
1632 | |||
1633 | return 0; | ||
1634 | } | ||
1635 | |||
1636 | // clean up the module | ||
1637 | static void __exit alsa_card_emu10k1x_exit(void) | ||
1638 | { | ||
1639 | pci_unregister_driver(&driver); | ||
1640 | } | ||
1641 | |||
1642 | module_init(alsa_card_emu10k1x_init) | ||
1643 | module_exit(alsa_card_emu10k1x_exit) | ||
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c new file mode 100644 index 000000000000..b9fa2e887fee --- /dev/null +++ b/sound/pci/emu10k1/emufx.c | |||
@@ -0,0 +1,2320 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Creative Labs, Inc. | ||
4 | * Routines for effect processor FX8010 | ||
5 | * | ||
6 | * BUGS: | ||
7 | * -- | ||
8 | * | ||
9 | * TODO: | ||
10 | * -- | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <sound/driver.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/emu10k1.h> | ||
35 | |||
36 | #if 0 /* for testing purposes - digital out -> capture */ | ||
37 | #define EMU10K1_CAPTURE_DIGITAL_OUT | ||
38 | #endif | ||
39 | #if 0 /* for testing purposes - set S/PDIF to AC3 output */ | ||
40 | #define EMU10K1_SET_AC3_IEC958 | ||
41 | #endif | ||
42 | #if 0 /* for testing purposes - feed the front signal to Center/LFE outputs */ | ||
43 | #define EMU10K1_CENTER_LFE_FROM_FRONT | ||
44 | #endif | ||
45 | |||
46 | /* | ||
47 | * Tables | ||
48 | */ | ||
49 | |||
50 | static char *fxbuses[16] = { | ||
51 | /* 0x00 */ "PCM Left", | ||
52 | /* 0x01 */ "PCM Right", | ||
53 | /* 0x02 */ "PCM Surround Left", | ||
54 | /* 0x03 */ "PCM Surround Right", | ||
55 | /* 0x04 */ "MIDI Left", | ||
56 | /* 0x05 */ "MIDI Right", | ||
57 | /* 0x06 */ "Center", | ||
58 | /* 0x07 */ "LFE", | ||
59 | /* 0x08 */ NULL, | ||
60 | /* 0x09 */ NULL, | ||
61 | /* 0x0a */ NULL, | ||
62 | /* 0x0b */ NULL, | ||
63 | /* 0x0c */ "MIDI Reverb", | ||
64 | /* 0x0d */ "MIDI Chorus", | ||
65 | /* 0x0e */ NULL, | ||
66 | /* 0x0f */ NULL | ||
67 | }; | ||
68 | |||
69 | static char *creative_ins[16] = { | ||
70 | /* 0x00 */ "AC97 Left", | ||
71 | /* 0x01 */ "AC97 Right", | ||
72 | /* 0x02 */ "TTL IEC958 Left", | ||
73 | /* 0x03 */ "TTL IEC958 Right", | ||
74 | /* 0x04 */ "Zoom Video Left", | ||
75 | /* 0x05 */ "Zoom Video Right", | ||
76 | /* 0x06 */ "Optical IEC958 Left", | ||
77 | /* 0x07 */ "Optical IEC958 Right", | ||
78 | /* 0x08 */ "Line/Mic 1 Left", | ||
79 | /* 0x09 */ "Line/Mic 1 Right", | ||
80 | /* 0x0a */ "Coaxial IEC958 Left", | ||
81 | /* 0x0b */ "Coaxial IEC958 Right", | ||
82 | /* 0x0c */ "Line/Mic 2 Left", | ||
83 | /* 0x0d */ "Line/Mic 2 Right", | ||
84 | /* 0x0e */ NULL, | ||
85 | /* 0x0f */ NULL | ||
86 | }; | ||
87 | |||
88 | static char *audigy_ins[16] = { | ||
89 | /* 0x00 */ "AC97 Left", | ||
90 | /* 0x01 */ "AC97 Right", | ||
91 | /* 0x02 */ "Audigy CD Left", | ||
92 | /* 0x03 */ "Audigy CD Right", | ||
93 | /* 0x04 */ "Optical IEC958 Left", | ||
94 | /* 0x05 */ "Optical IEC958 Right", | ||
95 | /* 0x06 */ NULL, | ||
96 | /* 0x07 */ NULL, | ||
97 | /* 0x08 */ "Line/Mic 2 Left", | ||
98 | /* 0x09 */ "Line/Mic 2 Right", | ||
99 | /* 0x0a */ "SPDIF Left", | ||
100 | /* 0x0b */ "SPDIF Right", | ||
101 | /* 0x0c */ "Aux2 Left", | ||
102 | /* 0x0d */ "Aux2 Right", | ||
103 | /* 0x0e */ NULL, | ||
104 | /* 0x0f */ NULL | ||
105 | }; | ||
106 | |||
107 | static char *creative_outs[32] = { | ||
108 | /* 0x00 */ "AC97 Left", | ||
109 | /* 0x01 */ "AC97 Right", | ||
110 | /* 0x02 */ "Optical IEC958 Left", | ||
111 | /* 0x03 */ "Optical IEC958 Right", | ||
112 | /* 0x04 */ "Center", | ||
113 | /* 0x05 */ "LFE", | ||
114 | /* 0x06 */ "Headphone Left", | ||
115 | /* 0x07 */ "Headphone Right", | ||
116 | /* 0x08 */ "Surround Left", | ||
117 | /* 0x09 */ "Surround Right", | ||
118 | /* 0x0a */ "PCM Capture Left", | ||
119 | /* 0x0b */ "PCM Capture Right", | ||
120 | /* 0x0c */ "MIC Capture", | ||
121 | /* 0x0d */ "AC97 Surround Left", | ||
122 | /* 0x0e */ "AC97 Surround Right", | ||
123 | /* 0x0f */ NULL, | ||
124 | /* 0x10 */ NULL, | ||
125 | /* 0x11 */ "Analog Center", | ||
126 | /* 0x12 */ "Analog LFE", | ||
127 | /* 0x13 */ NULL, | ||
128 | /* 0x14 */ NULL, | ||
129 | /* 0x15 */ NULL, | ||
130 | /* 0x16 */ NULL, | ||
131 | /* 0x17 */ NULL, | ||
132 | /* 0x18 */ NULL, | ||
133 | /* 0x19 */ NULL, | ||
134 | /* 0x1a */ NULL, | ||
135 | /* 0x1b */ NULL, | ||
136 | /* 0x1c */ NULL, | ||
137 | /* 0x1d */ NULL, | ||
138 | /* 0x1e */ NULL, | ||
139 | /* 0x1f */ NULL, | ||
140 | }; | ||
141 | |||
142 | static char *audigy_outs[32] = { | ||
143 | /* 0x00 */ "Digital Front Left", | ||
144 | /* 0x01 */ "Digital Front Right", | ||
145 | /* 0x02 */ "Digital Center", | ||
146 | /* 0x03 */ "Digital LEF", | ||
147 | /* 0x04 */ "Headphone Left", | ||
148 | /* 0x05 */ "Headphone Right", | ||
149 | /* 0x06 */ "Digital Rear Left", | ||
150 | /* 0x07 */ "Digital Rear Right", | ||
151 | /* 0x08 */ "Front Left", | ||
152 | /* 0x09 */ "Front Right", | ||
153 | /* 0x0a */ "Center", | ||
154 | /* 0x0b */ "LFE", | ||
155 | /* 0x0c */ NULL, | ||
156 | /* 0x0d */ NULL, | ||
157 | /* 0x0e */ "Rear Left", | ||
158 | /* 0x0f */ "Rear Right", | ||
159 | /* 0x10 */ "AC97 Front Left", | ||
160 | /* 0x11 */ "AC97 Front Right", | ||
161 | /* 0x12 */ "ADC Caputre Left", | ||
162 | /* 0x13 */ "ADC Capture Right", | ||
163 | /* 0x14 */ NULL, | ||
164 | /* 0x15 */ NULL, | ||
165 | /* 0x16 */ NULL, | ||
166 | /* 0x17 */ NULL, | ||
167 | /* 0x18 */ NULL, | ||
168 | /* 0x19 */ NULL, | ||
169 | /* 0x1a */ NULL, | ||
170 | /* 0x1b */ NULL, | ||
171 | /* 0x1c */ NULL, | ||
172 | /* 0x1d */ NULL, | ||
173 | /* 0x1e */ NULL, | ||
174 | /* 0x1f */ NULL, | ||
175 | }; | ||
176 | |||
177 | static const u32 bass_table[41][5] = { | ||
178 | { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 }, | ||
179 | { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d }, | ||
180 | { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee }, | ||
181 | { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c }, | ||
182 | { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b }, | ||
183 | { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 }, | ||
184 | { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f }, | ||
185 | { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 }, | ||
186 | { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 }, | ||
187 | { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 }, | ||
188 | { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 }, | ||
189 | { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be }, | ||
190 | { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b }, | ||
191 | { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c }, | ||
192 | { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b }, | ||
193 | { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 }, | ||
194 | { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a }, | ||
195 | { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 }, | ||
196 | { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 }, | ||
197 | { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e }, | ||
198 | { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee }, | ||
199 | { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 }, | ||
200 | { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 }, | ||
201 | { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 }, | ||
202 | { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 }, | ||
203 | { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e }, | ||
204 | { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 }, | ||
205 | { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 }, | ||
206 | { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 }, | ||
207 | { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 }, | ||
208 | { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 }, | ||
209 | { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca }, | ||
210 | { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 }, | ||
211 | { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 }, | ||
212 | { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 }, | ||
213 | { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 }, | ||
214 | { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a }, | ||
215 | { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f }, | ||
216 | { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 }, | ||
217 | { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 }, | ||
218 | { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 } | ||
219 | }; | ||
220 | |||
221 | static const u32 treble_table[41][5] = { | ||
222 | { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 }, | ||
223 | { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 }, | ||
224 | { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 }, | ||
225 | { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca }, | ||
226 | { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 }, | ||
227 | { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 }, | ||
228 | { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 }, | ||
229 | { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 }, | ||
230 | { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 }, | ||
231 | { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df }, | ||
232 | { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff }, | ||
233 | { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 }, | ||
234 | { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c }, | ||
235 | { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 }, | ||
236 | { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 }, | ||
237 | { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 }, | ||
238 | { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 }, | ||
239 | { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d }, | ||
240 | { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 }, | ||
241 | { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 }, | ||
242 | { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f }, | ||
243 | { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb }, | ||
244 | { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 }, | ||
245 | { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 }, | ||
246 | { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd }, | ||
247 | { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 }, | ||
248 | { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad }, | ||
249 | { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 }, | ||
250 | { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 }, | ||
251 | { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c }, | ||
252 | { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 }, | ||
253 | { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 }, | ||
254 | { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 }, | ||
255 | { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 }, | ||
256 | { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 }, | ||
257 | { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 }, | ||
258 | { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d }, | ||
259 | { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b }, | ||
260 | { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 }, | ||
261 | { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd }, | ||
262 | { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 } | ||
263 | }; | ||
264 | |||
265 | static const u32 db_table[101] = { | ||
266 | 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540, | ||
267 | 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8, | ||
268 | 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1, | ||
269 | 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0, | ||
270 | 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9, | ||
271 | 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb, | ||
272 | 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005, | ||
273 | 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d, | ||
274 | 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd, | ||
275 | 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8, | ||
276 | 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481, | ||
277 | 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333, | ||
278 | 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d, | ||
279 | 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6, | ||
280 | 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d, | ||
281 | 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf, | ||
282 | 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038, | ||
283 | 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a, | ||
284 | 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea, | ||
285 | 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272, | ||
286 | 0x7fffffff, | ||
287 | }; | ||
288 | |||
289 | static const u32 onoff_table[2] = { | ||
290 | 0x00000000, 0x00000001 | ||
291 | }; | ||
292 | |||
293 | /* | ||
294 | */ | ||
295 | |||
296 | static inline mm_segment_t snd_enter_user(void) | ||
297 | { | ||
298 | mm_segment_t fs = get_fs(); | ||
299 | set_fs(get_ds()); | ||
300 | return fs; | ||
301 | } | ||
302 | |||
303 | static inline void snd_leave_user(mm_segment_t fs) | ||
304 | { | ||
305 | set_fs(fs); | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * controls | ||
310 | */ | ||
311 | |||
312 | static int snd_emu10k1_gpr_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
313 | { | ||
314 | snd_emu10k1_fx8010_ctl_t *ctl = (snd_emu10k1_fx8010_ctl_t *)kcontrol->private_value; | ||
315 | |||
316 | if (ctl->min == 0 && ctl->max == 1) | ||
317 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
318 | else | ||
319 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
320 | uinfo->count = ctl->vcount; | ||
321 | uinfo->value.integer.min = ctl->min; | ||
322 | uinfo->value.integer.max = ctl->max; | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int snd_emu10k1_gpr_ctl_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
327 | { | ||
328 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
329 | snd_emu10k1_fx8010_ctl_t *ctl = (snd_emu10k1_fx8010_ctl_t *)kcontrol->private_value; | ||
330 | unsigned long flags; | ||
331 | unsigned int i; | ||
332 | |||
333 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
334 | for (i = 0; i < ctl->vcount; i++) | ||
335 | ucontrol->value.integer.value[i] = ctl->value[i]; | ||
336 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static int snd_emu10k1_gpr_ctl_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
341 | { | ||
342 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
343 | snd_emu10k1_fx8010_ctl_t *ctl = (snd_emu10k1_fx8010_ctl_t *)kcontrol->private_value; | ||
344 | unsigned long flags; | ||
345 | unsigned int nval, val; | ||
346 | unsigned int i, j; | ||
347 | int change = 0; | ||
348 | |||
349 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
350 | for (i = 0; i < ctl->vcount; i++) { | ||
351 | nval = ucontrol->value.integer.value[i]; | ||
352 | if (nval < ctl->min) | ||
353 | nval = ctl->min; | ||
354 | if (nval > ctl->max) | ||
355 | nval = ctl->max; | ||
356 | if (nval != ctl->value[i]) | ||
357 | change = 1; | ||
358 | val = ctl->value[i] = nval; | ||
359 | switch (ctl->translation) { | ||
360 | case EMU10K1_GPR_TRANSLATION_NONE: | ||
361 | snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val); | ||
362 | break; | ||
363 | case EMU10K1_GPR_TRANSLATION_TABLE100: | ||
364 | snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]); | ||
365 | break; | ||
366 | case EMU10K1_GPR_TRANSLATION_BASS: | ||
367 | snd_runtime_check((ctl->count % 5) == 0 && (ctl->count / 5) == ctl->vcount, change = -EIO; goto __error); | ||
368 | for (j = 0; j < 5; j++) | ||
369 | snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]); | ||
370 | break; | ||
371 | case EMU10K1_GPR_TRANSLATION_TREBLE: | ||
372 | snd_runtime_check((ctl->count % 5) == 0 && (ctl->count / 5) == ctl->vcount, change = -EIO; goto __error); | ||
373 | for (j = 0; j < 5; j++) | ||
374 | snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]); | ||
375 | break; | ||
376 | case EMU10K1_GPR_TRANSLATION_ONOFF: | ||
377 | snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]); | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | __error: | ||
382 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
383 | return change; | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * Interrupt handler | ||
388 | */ | ||
389 | |||
390 | static void snd_emu10k1_fx8010_interrupt(emu10k1_t *emu) | ||
391 | { | ||
392 | snd_emu10k1_fx8010_irq_t *irq, *nirq; | ||
393 | |||
394 | irq = emu->fx8010.irq_handlers; | ||
395 | while (irq) { | ||
396 | nirq = irq->next; /* irq ptr can be removed from list */ | ||
397 | if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) { | ||
398 | if (irq->handler) | ||
399 | irq->handler(emu, irq->private_data); | ||
400 | snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1); | ||
401 | } | ||
402 | irq = nirq; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | int snd_emu10k1_fx8010_register_irq_handler(emu10k1_t *emu, | ||
407 | snd_fx8010_irq_handler_t *handler, | ||
408 | unsigned char gpr_running, | ||
409 | void *private_data, | ||
410 | snd_emu10k1_fx8010_irq_t **r_irq) | ||
411 | { | ||
412 | snd_emu10k1_fx8010_irq_t *irq; | ||
413 | unsigned long flags; | ||
414 | |||
415 | snd_runtime_check(emu, return -EINVAL); | ||
416 | snd_runtime_check(handler, return -EINVAL); | ||
417 | irq = kmalloc(sizeof(*irq), GFP_ATOMIC); | ||
418 | if (irq == NULL) | ||
419 | return -ENOMEM; | ||
420 | irq->handler = handler; | ||
421 | irq->gpr_running = gpr_running; | ||
422 | irq->private_data = private_data; | ||
423 | irq->next = NULL; | ||
424 | spin_lock_irqsave(&emu->fx8010.irq_lock, flags); | ||
425 | if (emu->fx8010.irq_handlers == NULL) { | ||
426 | emu->fx8010.irq_handlers = irq; | ||
427 | emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt; | ||
428 | snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE); | ||
429 | } else { | ||
430 | irq->next = emu->fx8010.irq_handlers; | ||
431 | emu->fx8010.irq_handlers = irq; | ||
432 | } | ||
433 | spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); | ||
434 | if (r_irq) | ||
435 | *r_irq = irq; | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, | ||
440 | snd_emu10k1_fx8010_irq_t *irq) | ||
441 | { | ||
442 | snd_emu10k1_fx8010_irq_t *tmp; | ||
443 | unsigned long flags; | ||
444 | |||
445 | snd_runtime_check(irq, return -EINVAL); | ||
446 | spin_lock_irqsave(&emu->fx8010.irq_lock, flags); | ||
447 | if ((tmp = emu->fx8010.irq_handlers) == irq) { | ||
448 | emu->fx8010.irq_handlers = tmp->next; | ||
449 | if (emu->fx8010.irq_handlers == NULL) { | ||
450 | snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); | ||
451 | emu->dsp_interrupt = NULL; | ||
452 | } | ||
453 | } else { | ||
454 | while (tmp && tmp->next != irq) | ||
455 | tmp = tmp->next; | ||
456 | if (tmp) | ||
457 | tmp->next = tmp->next->next; | ||
458 | } | ||
459 | spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); | ||
460 | kfree(irq); | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | /************************************************************************* | ||
465 | * EMU10K1 effect manager | ||
466 | *************************************************************************/ | ||
467 | |||
468 | static void snd_emu10k1_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr, | ||
469 | u32 op, u32 r, u32 a, u32 x, u32 y) | ||
470 | { | ||
471 | u_int32_t *code; | ||
472 | snd_assert(*ptr < 512, return); | ||
473 | code = (u_int32_t *)icode->code + (*ptr) * 2; | ||
474 | set_bit(*ptr, icode->code_valid); | ||
475 | code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff); | ||
476 | code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff); | ||
477 | (*ptr)++; | ||
478 | } | ||
479 | |||
480 | #define OP(icode, ptr, op, r, a, x, y) \ | ||
481 | snd_emu10k1_write_op(icode, ptr, op, r, a, x, y) | ||
482 | |||
483 | static void snd_emu10k1_audigy_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr, | ||
484 | u32 op, u32 r, u32 a, u32 x, u32 y) | ||
485 | { | ||
486 | u_int32_t *code; | ||
487 | snd_assert(*ptr < 1024, return); | ||
488 | code = (u_int32_t *)icode->code + (*ptr) * 2; | ||
489 | set_bit(*ptr, icode->code_valid); | ||
490 | code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff); | ||
491 | code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff); | ||
492 | (*ptr)++; | ||
493 | } | ||
494 | |||
495 | #define A_OP(icode, ptr, op, r, a, x, y) \ | ||
496 | snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y) | ||
497 | |||
498 | static void snd_emu10k1_efx_write(emu10k1_t *emu, unsigned int pc, unsigned int data) | ||
499 | { | ||
500 | pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE; | ||
501 | snd_emu10k1_ptr_write(emu, pc, 0, data); | ||
502 | } | ||
503 | |||
504 | unsigned int snd_emu10k1_efx_read(emu10k1_t *emu, unsigned int pc) | ||
505 | { | ||
506 | pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE; | ||
507 | return snd_emu10k1_ptr_read(emu, pc, 0); | ||
508 | } | ||
509 | |||
510 | static int snd_emu10k1_gpr_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
511 | { | ||
512 | int gpr; | ||
513 | u32 val; | ||
514 | |||
515 | for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) { | ||
516 | if (!test_bit(gpr, icode->gpr_valid)) | ||
517 | continue; | ||
518 | if (get_user(val, &icode->gpr_map[gpr])) | ||
519 | return -EFAULT; | ||
520 | snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val); | ||
521 | } | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int snd_emu10k1_gpr_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
526 | { | ||
527 | int gpr; | ||
528 | u32 val; | ||
529 | |||
530 | for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) { | ||
531 | set_bit(gpr, icode->gpr_valid); | ||
532 | val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0); | ||
533 | if (put_user(val, &icode->gpr_map[gpr])) | ||
534 | return -EFAULT; | ||
535 | } | ||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static int snd_emu10k1_tram_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
540 | { | ||
541 | int tram; | ||
542 | u32 addr, val; | ||
543 | |||
544 | for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) { | ||
545 | if (!test_bit(tram, icode->tram_valid)) | ||
546 | continue; | ||
547 | if (get_user(val, &icode->tram_data_map[tram]) || | ||
548 | get_user(addr, &icode->tram_addr_map[tram])) | ||
549 | return -EFAULT; | ||
550 | snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val); | ||
551 | if (!emu->audigy) { | ||
552 | snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr); | ||
553 | } else { | ||
554 | snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12); | ||
555 | snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20); | ||
556 | } | ||
557 | } | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | static int snd_emu10k1_tram_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
562 | { | ||
563 | int tram; | ||
564 | u32 val, addr; | ||
565 | |||
566 | memset(icode->tram_valid, 0, sizeof(icode->tram_valid)); | ||
567 | for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) { | ||
568 | set_bit(tram, icode->tram_valid); | ||
569 | val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0); | ||
570 | if (!emu->audigy) { | ||
571 | addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0); | ||
572 | } else { | ||
573 | addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12; | ||
574 | addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20; | ||
575 | } | ||
576 | if (put_user(val, &icode->tram_data_map[tram]) || | ||
577 | put_user(addr, &icode->tram_addr_map[tram])) | ||
578 | return -EFAULT; | ||
579 | } | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int snd_emu10k1_code_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
584 | { | ||
585 | u32 pc, lo, hi; | ||
586 | |||
587 | for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) { | ||
588 | if (!test_bit(pc / 2, icode->code_valid)) | ||
589 | continue; | ||
590 | if (get_user(lo, &icode->code[pc + 0]) || | ||
591 | get_user(hi, &icode->code[pc + 1])) | ||
592 | return -EFAULT; | ||
593 | snd_emu10k1_efx_write(emu, pc + 0, lo); | ||
594 | snd_emu10k1_efx_write(emu, pc + 1, hi); | ||
595 | } | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int snd_emu10k1_code_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
600 | { | ||
601 | u32 pc; | ||
602 | |||
603 | memset(icode->code_valid, 0, sizeof(icode->code_valid)); | ||
604 | for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) { | ||
605 | set_bit(pc / 2, icode->code_valid); | ||
606 | if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0])) | ||
607 | return -EFAULT; | ||
608 | if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1])) | ||
609 | return -EFAULT; | ||
610 | } | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | static snd_emu10k1_fx8010_ctl_t *snd_emu10k1_look_for_ctl(emu10k1_t *emu, snd_ctl_elem_id_t *id) | ||
615 | { | ||
616 | snd_emu10k1_fx8010_ctl_t *ctl; | ||
617 | snd_kcontrol_t *kcontrol; | ||
618 | struct list_head *list; | ||
619 | |||
620 | list_for_each(list, &emu->fx8010.gpr_ctl) { | ||
621 | ctl = emu10k1_gpr_ctl(list); | ||
622 | kcontrol = ctl->kcontrol; | ||
623 | if (kcontrol->id.iface == id->iface && | ||
624 | !strcmp(kcontrol->id.name, id->name) && | ||
625 | kcontrol->id.index == id->index) | ||
626 | return ctl; | ||
627 | } | ||
628 | return NULL; | ||
629 | } | ||
630 | |||
631 | static int snd_emu10k1_verify_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
632 | { | ||
633 | unsigned int i; | ||
634 | snd_ctl_elem_id_t __user *_id; | ||
635 | snd_ctl_elem_id_t id; | ||
636 | emu10k1_fx8010_control_gpr_t __user *_gctl; | ||
637 | emu10k1_fx8010_control_gpr_t *gctl; | ||
638 | int err; | ||
639 | |||
640 | for (i = 0, _id = icode->gpr_del_controls; | ||
641 | i < icode->gpr_del_control_count; i++, _id++) { | ||
642 | if (copy_from_user(&id, _id, sizeof(id))) | ||
643 | return -EFAULT; | ||
644 | if (snd_emu10k1_look_for_ctl(emu, &id) == NULL) | ||
645 | return -ENOENT; | ||
646 | } | ||
647 | gctl = kmalloc(sizeof(*gctl), GFP_KERNEL); | ||
648 | if (! gctl) | ||
649 | return -ENOMEM; | ||
650 | err = 0; | ||
651 | for (i = 0, _gctl = icode->gpr_add_controls; | ||
652 | i < icode->gpr_add_control_count; i++, _gctl++) { | ||
653 | if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { | ||
654 | err = -EFAULT; | ||
655 | goto __error; | ||
656 | } | ||
657 | if (snd_emu10k1_look_for_ctl(emu, &gctl->id)) | ||
658 | continue; | ||
659 | down_read(&emu->card->controls_rwsem); | ||
660 | if (snd_ctl_find_id(emu->card, &gctl->id) != NULL) { | ||
661 | up_read(&emu->card->controls_rwsem); | ||
662 | err = -EEXIST; | ||
663 | goto __error; | ||
664 | } | ||
665 | up_read(&emu->card->controls_rwsem); | ||
666 | if (gctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER && | ||
667 | gctl->id.iface != SNDRV_CTL_ELEM_IFACE_PCM) { | ||
668 | err = -EINVAL; | ||
669 | goto __error; | ||
670 | } | ||
671 | } | ||
672 | for (i = 0, _gctl = icode->gpr_list_controls; | ||
673 | i < icode->gpr_list_control_count; i++, _gctl++) { | ||
674 | /* FIXME: we need to check the WRITE access */ | ||
675 | if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { | ||
676 | err = -EFAULT; | ||
677 | goto __error; | ||
678 | } | ||
679 | } | ||
680 | __error: | ||
681 | kfree(gctl); | ||
682 | return err; | ||
683 | } | ||
684 | |||
685 | static void snd_emu10k1_ctl_private_free(snd_kcontrol_t *kctl) | ||
686 | { | ||
687 | snd_emu10k1_fx8010_ctl_t *ctl; | ||
688 | |||
689 | ctl = (snd_emu10k1_fx8010_ctl_t *)kctl->private_value; | ||
690 | kctl->private_value = 0; | ||
691 | list_del(&ctl->list); | ||
692 | kfree(ctl); | ||
693 | } | ||
694 | |||
695 | static int snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
696 | { | ||
697 | unsigned int i, j; | ||
698 | emu10k1_fx8010_control_gpr_t __user *_gctl; | ||
699 | emu10k1_fx8010_control_gpr_t *gctl; | ||
700 | snd_emu10k1_fx8010_ctl_t *ctl, *nctl; | ||
701 | snd_kcontrol_new_t knew; | ||
702 | snd_kcontrol_t *kctl; | ||
703 | snd_ctl_elem_value_t *val; | ||
704 | int err = 0; | ||
705 | |||
706 | val = (snd_ctl_elem_value_t *)kmalloc(sizeof(*val), GFP_KERNEL); | ||
707 | gctl = kmalloc(sizeof(*gctl), GFP_KERNEL); | ||
708 | nctl = kmalloc(sizeof(*nctl), GFP_KERNEL); | ||
709 | if (!val || !gctl || !nctl) { | ||
710 | err = -ENOMEM; | ||
711 | goto __error; | ||
712 | } | ||
713 | |||
714 | for (i = 0, _gctl = icode->gpr_add_controls; | ||
715 | i < icode->gpr_add_control_count; i++, _gctl++) { | ||
716 | if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { | ||
717 | err = -EFAULT; | ||
718 | goto __error; | ||
719 | } | ||
720 | snd_runtime_check(gctl->id.iface == SNDRV_CTL_ELEM_IFACE_MIXER || | ||
721 | gctl->id.iface == SNDRV_CTL_ELEM_IFACE_PCM, err = -EINVAL; goto __error); | ||
722 | snd_runtime_check(gctl->id.name[0] != '\0', err = -EINVAL; goto __error); | ||
723 | ctl = snd_emu10k1_look_for_ctl(emu, &gctl->id); | ||
724 | memset(&knew, 0, sizeof(knew)); | ||
725 | knew.iface = gctl->id.iface; | ||
726 | knew.name = gctl->id.name; | ||
727 | knew.index = gctl->id.index; | ||
728 | knew.device = gctl->id.device; | ||
729 | knew.subdevice = gctl->id.subdevice; | ||
730 | knew.info = snd_emu10k1_gpr_ctl_info; | ||
731 | knew.get = snd_emu10k1_gpr_ctl_get; | ||
732 | knew.put = snd_emu10k1_gpr_ctl_put; | ||
733 | memset(nctl, 0, sizeof(*nctl)); | ||
734 | nctl->vcount = gctl->vcount; | ||
735 | nctl->count = gctl->count; | ||
736 | for (j = 0; j < 32; j++) { | ||
737 | nctl->gpr[j] = gctl->gpr[j]; | ||
738 | nctl->value[j] = ~gctl->value[j]; /* inverted, we want to write new value in gpr_ctl_put() */ | ||
739 | val->value.integer.value[j] = gctl->value[j]; | ||
740 | } | ||
741 | nctl->min = gctl->min; | ||
742 | nctl->max = gctl->max; | ||
743 | nctl->translation = gctl->translation; | ||
744 | if (ctl == NULL) { | ||
745 | ctl = (snd_emu10k1_fx8010_ctl_t *)kmalloc(sizeof(*ctl), GFP_KERNEL); | ||
746 | if (ctl == NULL) { | ||
747 | err = -ENOMEM; | ||
748 | goto __error; | ||
749 | } | ||
750 | knew.private_value = (unsigned long)ctl; | ||
751 | *ctl = *nctl; | ||
752 | if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { | ||
753 | kfree(ctl); | ||
754 | goto __error; | ||
755 | } | ||
756 | kctl->private_free = snd_emu10k1_ctl_private_free; | ||
757 | ctl->kcontrol = kctl; | ||
758 | list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl); | ||
759 | } else { | ||
760 | /* overwrite */ | ||
761 | nctl->list = ctl->list; | ||
762 | nctl->kcontrol = ctl->kcontrol; | ||
763 | *ctl = *nctl; | ||
764 | snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
765 | SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id); | ||
766 | } | ||
767 | snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val); | ||
768 | } | ||
769 | __error: | ||
770 | kfree(nctl); | ||
771 | kfree(gctl); | ||
772 | kfree(val); | ||
773 | return err; | ||
774 | } | ||
775 | |||
776 | static int snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
777 | { | ||
778 | unsigned int i; | ||
779 | snd_ctl_elem_id_t id; | ||
780 | snd_ctl_elem_id_t __user *_id; | ||
781 | snd_emu10k1_fx8010_ctl_t *ctl; | ||
782 | snd_card_t *card = emu->card; | ||
783 | |||
784 | for (i = 0, _id = icode->gpr_del_controls; | ||
785 | i < icode->gpr_del_control_count; i++, _id++) { | ||
786 | snd_runtime_check(copy_from_user(&id, _id, sizeof(id)) == 0, return -EFAULT); | ||
787 | down_write(&card->controls_rwsem); | ||
788 | ctl = snd_emu10k1_look_for_ctl(emu, &id); | ||
789 | if (ctl) | ||
790 | snd_ctl_remove(card, ctl->kcontrol); | ||
791 | up_write(&card->controls_rwsem); | ||
792 | } | ||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | static int snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
797 | { | ||
798 | unsigned int i = 0, j; | ||
799 | unsigned int total = 0; | ||
800 | emu10k1_fx8010_control_gpr_t *gctl; | ||
801 | emu10k1_fx8010_control_gpr_t __user *_gctl; | ||
802 | snd_emu10k1_fx8010_ctl_t *ctl; | ||
803 | snd_ctl_elem_id_t *id; | ||
804 | struct list_head *list; | ||
805 | |||
806 | gctl = kmalloc(sizeof(*gctl), GFP_KERNEL); | ||
807 | if (! gctl) | ||
808 | return -ENOMEM; | ||
809 | |||
810 | _gctl = icode->gpr_list_controls; | ||
811 | list_for_each(list, &emu->fx8010.gpr_ctl) { | ||
812 | ctl = emu10k1_gpr_ctl(list); | ||
813 | total++; | ||
814 | if (_gctl && i < icode->gpr_list_control_count) { | ||
815 | memset(gctl, 0, sizeof(*gctl)); | ||
816 | id = &ctl->kcontrol->id; | ||
817 | gctl->id.iface = id->iface; | ||
818 | strlcpy(gctl->id.name, id->name, sizeof(gctl->id.name)); | ||
819 | gctl->id.index = id->index; | ||
820 | gctl->id.device = id->device; | ||
821 | gctl->id.subdevice = id->subdevice; | ||
822 | gctl->vcount = ctl->vcount; | ||
823 | gctl->count = ctl->count; | ||
824 | for (j = 0; j < 32; j++) { | ||
825 | gctl->gpr[j] = ctl->gpr[j]; | ||
826 | gctl->value[j] = ctl->value[j]; | ||
827 | } | ||
828 | gctl->min = ctl->min; | ||
829 | gctl->max = ctl->max; | ||
830 | gctl->translation = ctl->translation; | ||
831 | if (copy_to_user(_gctl, gctl, sizeof(*gctl))) { | ||
832 | kfree(gctl); | ||
833 | return -EFAULT; | ||
834 | } | ||
835 | _gctl++; | ||
836 | i++; | ||
837 | } | ||
838 | } | ||
839 | icode->gpr_list_control_total = total; | ||
840 | kfree(gctl); | ||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | static int snd_emu10k1_icode_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
845 | { | ||
846 | int err = 0; | ||
847 | |||
848 | down(&emu->fx8010.lock); | ||
849 | if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0) | ||
850 | goto __error; | ||
851 | strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)); | ||
852 | /* stop FX processor - this may be dangerous, but it's better to miss | ||
853 | some samples than generate wrong ones - [jk] */ | ||
854 | if (emu->audigy) | ||
855 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP); | ||
856 | else | ||
857 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP); | ||
858 | /* ok, do the main job */ | ||
859 | if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 || | ||
860 | (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 || | ||
861 | (err = snd_emu10k1_tram_poke(emu, icode)) < 0 || | ||
862 | (err = snd_emu10k1_code_poke(emu, icode)) < 0 || | ||
863 | (err = snd_emu10k1_add_controls(emu, icode)) < 0) | ||
864 | goto __error; | ||
865 | /* start FX processor when the DSP code is updated */ | ||
866 | if (emu->audigy) | ||
867 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg); | ||
868 | else | ||
869 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg); | ||
870 | __error: | ||
871 | up(&emu->fx8010.lock); | ||
872 | return err; | ||
873 | } | ||
874 | |||
875 | static int snd_emu10k1_icode_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) | ||
876 | { | ||
877 | int err; | ||
878 | |||
879 | down(&emu->fx8010.lock); | ||
880 | strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name)); | ||
881 | /* ok, do the main job */ | ||
882 | err = snd_emu10k1_gpr_peek(emu, icode); | ||
883 | if (err >= 0) | ||
884 | err = snd_emu10k1_tram_peek(emu, icode); | ||
885 | if (err >= 0) | ||
886 | err = snd_emu10k1_code_peek(emu, icode); | ||
887 | if (err >= 0) | ||
888 | err = snd_emu10k1_list_controls(emu, icode); | ||
889 | up(&emu->fx8010.lock); | ||
890 | return err; | ||
891 | } | ||
892 | |||
893 | static int snd_emu10k1_ipcm_poke(emu10k1_t *emu, emu10k1_fx8010_pcm_t *ipcm) | ||
894 | { | ||
895 | unsigned int i; | ||
896 | int err = 0; | ||
897 | snd_emu10k1_fx8010_pcm_t *pcm; | ||
898 | |||
899 | if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT) | ||
900 | return -EINVAL; | ||
901 | if (ipcm->channels > 32) | ||
902 | return -EINVAL; | ||
903 | pcm = &emu->fx8010.pcm[ipcm->substream]; | ||
904 | down(&emu->fx8010.lock); | ||
905 | spin_lock_irq(&emu->reg_lock); | ||
906 | if (pcm->opened) { | ||
907 | err = -EBUSY; | ||
908 | goto __error; | ||
909 | } | ||
910 | if (ipcm->channels == 0) { /* remove */ | ||
911 | pcm->valid = 0; | ||
912 | } else { | ||
913 | /* FIXME: we need to add universal code to the PCM transfer routine */ | ||
914 | if (ipcm->channels != 2) { | ||
915 | err = -EINVAL; | ||
916 | goto __error; | ||
917 | } | ||
918 | pcm->valid = 1; | ||
919 | pcm->opened = 0; | ||
920 | pcm->channels = ipcm->channels; | ||
921 | pcm->tram_start = ipcm->tram_start; | ||
922 | pcm->buffer_size = ipcm->buffer_size; | ||
923 | pcm->gpr_size = ipcm->gpr_size; | ||
924 | pcm->gpr_count = ipcm->gpr_count; | ||
925 | pcm->gpr_tmpcount = ipcm->gpr_tmpcount; | ||
926 | pcm->gpr_ptr = ipcm->gpr_ptr; | ||
927 | pcm->gpr_trigger = ipcm->gpr_trigger; | ||
928 | pcm->gpr_running = ipcm->gpr_running; | ||
929 | for (i = 0; i < pcm->channels; i++) | ||
930 | pcm->etram[i] = ipcm->etram[i]; | ||
931 | } | ||
932 | __error: | ||
933 | spin_unlock_irq(&emu->reg_lock); | ||
934 | up(&emu->fx8010.lock); | ||
935 | return err; | ||
936 | } | ||
937 | |||
938 | static int snd_emu10k1_ipcm_peek(emu10k1_t *emu, emu10k1_fx8010_pcm_t *ipcm) | ||
939 | { | ||
940 | unsigned int i; | ||
941 | int err = 0; | ||
942 | snd_emu10k1_fx8010_pcm_t *pcm; | ||
943 | |||
944 | if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT) | ||
945 | return -EINVAL; | ||
946 | pcm = &emu->fx8010.pcm[ipcm->substream]; | ||
947 | down(&emu->fx8010.lock); | ||
948 | spin_lock_irq(&emu->reg_lock); | ||
949 | ipcm->channels = pcm->channels; | ||
950 | ipcm->tram_start = pcm->tram_start; | ||
951 | ipcm->buffer_size = pcm->buffer_size; | ||
952 | ipcm->gpr_size = pcm->gpr_size; | ||
953 | ipcm->gpr_ptr = pcm->gpr_ptr; | ||
954 | ipcm->gpr_count = pcm->gpr_count; | ||
955 | ipcm->gpr_tmpcount = pcm->gpr_tmpcount; | ||
956 | ipcm->gpr_trigger = pcm->gpr_trigger; | ||
957 | ipcm->gpr_running = pcm->gpr_running; | ||
958 | for (i = 0; i < pcm->channels; i++) | ||
959 | ipcm->etram[i] = pcm->etram[i]; | ||
960 | ipcm->res1 = ipcm->res2 = 0; | ||
961 | ipcm->pad = 0; | ||
962 | spin_unlock_irq(&emu->reg_lock); | ||
963 | up(&emu->fx8010.lock); | ||
964 | return err; | ||
965 | } | ||
966 | |||
967 | #define SND_EMU10K1_GPR_CONTROLS 41 | ||
968 | #define SND_EMU10K1_INPUTS 10 | ||
969 | #define SND_EMU10K1_PLAYBACK_CHANNELS 8 | ||
970 | #define SND_EMU10K1_CAPTURE_CHANNELS 4 | ||
971 | |||
972 | static void __devinit snd_emu10k1_init_mono_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval) | ||
973 | { | ||
974 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
975 | strcpy(ctl->id.name, name); | ||
976 | ctl->vcount = ctl->count = 1; | ||
977 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; | ||
978 | ctl->min = 0; | ||
979 | ctl->max = 100; | ||
980 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; | ||
981 | } | ||
982 | |||
983 | static void __devinit snd_emu10k1_init_stereo_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval) | ||
984 | { | ||
985 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
986 | strcpy(ctl->id.name, name); | ||
987 | ctl->vcount = ctl->count = 2; | ||
988 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; | ||
989 | ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; | ||
990 | ctl->min = 0; | ||
991 | ctl->max = 100; | ||
992 | ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; | ||
993 | } | ||
994 | |||
995 | static void __devinit snd_emu10k1_init_mono_onoff_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval) | ||
996 | { | ||
997 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
998 | strcpy(ctl->id.name, name); | ||
999 | ctl->vcount = ctl->count = 1; | ||
1000 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; | ||
1001 | ctl->min = 0; | ||
1002 | ctl->max = 1; | ||
1003 | ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; | ||
1004 | } | ||
1005 | |||
1006 | static void __devinit snd_emu10k1_init_stereo_onoff_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval) | ||
1007 | { | ||
1008 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1009 | strcpy(ctl->id.name, name); | ||
1010 | ctl->vcount = ctl->count = 2; | ||
1011 | ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; | ||
1012 | ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; | ||
1013 | ctl->min = 0; | ||
1014 | ctl->max = 1; | ||
1015 | ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; | ||
1016 | } | ||
1017 | |||
1018 | |||
1019 | /* | ||
1020 | * initial DSP configuration for Audigy | ||
1021 | */ | ||
1022 | |||
1023 | static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) | ||
1024 | { | ||
1025 | int err, i, z, gpr, nctl; | ||
1026 | const int playback = 10; | ||
1027 | const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ | ||
1028 | const int stereo_mix = capture + 2; | ||
1029 | const int tmp = 0x88; | ||
1030 | u32 ptr; | ||
1031 | emu10k1_fx8010_code_t *icode = NULL; | ||
1032 | emu10k1_fx8010_control_gpr_t *controls = NULL, *ctl; | ||
1033 | u32 *gpr_map; | ||
1034 | mm_segment_t seg; | ||
1035 | |||
1036 | spin_lock_init(&emu->fx8010.irq_lock); | ||
1037 | INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); | ||
1038 | |||
1039 | if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL || | ||
1040 | (icode->gpr_map = (u_int32_t __user *)kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t), GFP_KERNEL)) == NULL || | ||
1041 | (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(*controls), GFP_KERNEL)) == NULL) { | ||
1042 | err = -ENOMEM; | ||
1043 | goto __err; | ||
1044 | } | ||
1045 | gpr_map = (u32 *)icode->gpr_map; | ||
1046 | |||
1047 | icode->tram_data_map = icode->gpr_map + 512; | ||
1048 | icode->tram_addr_map = icode->tram_data_map + 256; | ||
1049 | icode->code = icode->tram_addr_map + 256; | ||
1050 | |||
1051 | /* clear free GPRs */ | ||
1052 | for (i = 0; i < 512; i++) | ||
1053 | set_bit(i, icode->gpr_valid); | ||
1054 | |||
1055 | /* clear TRAM data & address lines */ | ||
1056 | for (i = 0; i < 256; i++) | ||
1057 | set_bit(i, icode->tram_valid); | ||
1058 | |||
1059 | strcpy(icode->name, "Audigy DSP code for ALSA"); | ||
1060 | ptr = 0; | ||
1061 | nctl = 0; | ||
1062 | gpr = stereo_mix + 10; | ||
1063 | |||
1064 | /* stop FX processor */ | ||
1065 | snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); | ||
1066 | |||
1067 | /* PCM front Playback Volume (independent from stereo mix) */ | ||
1068 | A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); | ||
1069 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT)); | ||
1070 | snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100); | ||
1071 | gpr += 2; | ||
1072 | |||
1073 | /* PCM Surround Playback (independent from stereo mix) */ | ||
1074 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); | ||
1075 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); | ||
1076 | snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100); | ||
1077 | gpr += 2; | ||
1078 | |||
1079 | /* PCM Side Playback (independent from stereo mix) */ | ||
1080 | if (emu->spk71) { | ||
1081 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_SIDE)); | ||
1082 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_SIDE)); | ||
1083 | snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Side Playback Volume", gpr, 100); | ||
1084 | gpr += 2; | ||
1085 | } | ||
1086 | |||
1087 | /* PCM Center Playback (independent from stereo mix) */ | ||
1088 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); | ||
1089 | snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100); | ||
1090 | gpr++; | ||
1091 | |||
1092 | /* PCM LFE Playback (independent from stereo mix) */ | ||
1093 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE)); | ||
1094 | snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100); | ||
1095 | gpr++; | ||
1096 | |||
1097 | /* | ||
1098 | * Stereo Mix | ||
1099 | */ | ||
1100 | /* Wave (PCM) Playback Volume (will be renamed later) */ | ||
1101 | A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); | ||
1102 | A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); | ||
1103 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100); | ||
1104 | gpr += 2; | ||
1105 | |||
1106 | /* Synth Playback */ | ||
1107 | A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); | ||
1108 | A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); | ||
1109 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Playback Volume", gpr, 100); | ||
1110 | gpr += 2; | ||
1111 | |||
1112 | /* Wave (PCM) Capture */ | ||
1113 | A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); | ||
1114 | A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); | ||
1115 | snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0); | ||
1116 | gpr += 2; | ||
1117 | |||
1118 | /* Synth Capture */ | ||
1119 | A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_GPR(capture+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); | ||
1120 | A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_GPR(capture+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); | ||
1121 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Synth Capture Volume", gpr, 0); | ||
1122 | gpr += 2; | ||
1123 | |||
1124 | /* | ||
1125 | * inputs | ||
1126 | */ | ||
1127 | #define A_ADD_VOLUME_IN(var,vol,input) \ | ||
1128 | A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) | ||
1129 | |||
1130 | /* AC'97 Playback Volume - used only for mic (renamed later) */ | ||
1131 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); | ||
1132 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); | ||
1133 | snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0); | ||
1134 | gpr += 2; | ||
1135 | /* AC'97 Capture Volume - used only for mic */ | ||
1136 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L); | ||
1137 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R); | ||
1138 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0); | ||
1139 | gpr += 2; | ||
1140 | |||
1141 | /* mic capture buffer */ | ||
1142 | A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R)); | ||
1143 | |||
1144 | /* Audigy CD Playback Volume */ | ||
1145 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); | ||
1146 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); | ||
1147 | snd_emu10k1_init_stereo_control(&controls[nctl++], | ||
1148 | emu->no_ac97 ? "CD Playback Volume" : "Audigy CD Playback Volume", | ||
1149 | gpr, 0); | ||
1150 | gpr += 2; | ||
1151 | /* Audigy CD Capture Volume */ | ||
1152 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_SPDIF_CD_L); | ||
1153 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_SPDIF_CD_R); | ||
1154 | snd_emu10k1_init_stereo_control(&controls[nctl++], | ||
1155 | emu->no_ac97 ? "CD Capture Volume" : "Audigy CD Capture Volume", | ||
1156 | gpr, 0); | ||
1157 | gpr += 2; | ||
1158 | |||
1159 | /* Optical SPDIF Playback Volume */ | ||
1160 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L); | ||
1161 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R); | ||
1162 | snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Playback Volume", gpr, 0); | ||
1163 | gpr += 2; | ||
1164 | /* Optical SPDIF Capture Volume */ | ||
1165 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L); | ||
1166 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R); | ||
1167 | snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Capture Volume", gpr, 0); | ||
1168 | gpr += 2; | ||
1169 | |||
1170 | /* Line2 Playback Volume */ | ||
1171 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); | ||
1172 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); | ||
1173 | snd_emu10k1_init_stereo_control(&controls[nctl++], | ||
1174 | emu->no_ac97 ? "Line Playback Volume" : "Line2 Playback Volume", | ||
1175 | gpr, 0); | ||
1176 | gpr += 2; | ||
1177 | /* Line2 Capture Volume */ | ||
1178 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_LINE2_L); | ||
1179 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_LINE2_R); | ||
1180 | snd_emu10k1_init_stereo_control(&controls[nctl++], | ||
1181 | emu->no_ac97 ? "Line Capture Volume" : "Line2 Capture Volume", | ||
1182 | gpr, 0); | ||
1183 | gpr += 2; | ||
1184 | |||
1185 | /* Philips ADC Playback Volume */ | ||
1186 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L); | ||
1187 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R); | ||
1188 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0); | ||
1189 | gpr += 2; | ||
1190 | /* Philips ADC Capture Volume */ | ||
1191 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L); | ||
1192 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R); | ||
1193 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0); | ||
1194 | gpr += 2; | ||
1195 | |||
1196 | /* Aux2 Playback Volume */ | ||
1197 | A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); | ||
1198 | A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); | ||
1199 | snd_emu10k1_init_stereo_control(&controls[nctl++], | ||
1200 | emu->no_ac97 ? "Aux Playback Volume" : "Aux2 Playback Volume", | ||
1201 | gpr, 0); | ||
1202 | gpr += 2; | ||
1203 | /* Aux2 Capture Volume */ | ||
1204 | A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AUX2_L); | ||
1205 | A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); | ||
1206 | snd_emu10k1_init_stereo_control(&controls[nctl++], | ||
1207 | emu->no_ac97 ? "Aux Capture Volume" : "Aux2 Capture Volume", | ||
1208 | gpr, 0); | ||
1209 | gpr += 2; | ||
1210 | |||
1211 | /* Stereo Mix Front Playback Volume */ | ||
1212 | A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix)); | ||
1213 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1)); | ||
1214 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100); | ||
1215 | gpr += 2; | ||
1216 | |||
1217 | /* Stereo Mix Surround Playback */ | ||
1218 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix)); | ||
1219 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1)); | ||
1220 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0); | ||
1221 | gpr += 2; | ||
1222 | |||
1223 | /* Stereo Mix Center Playback */ | ||
1224 | /* Center = sub = Left/2 + Right/2 */ | ||
1225 | A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1)); | ||
1226 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp)); | ||
1227 | snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0); | ||
1228 | gpr++; | ||
1229 | |||
1230 | /* Stereo Mix LFE Playback */ | ||
1231 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp)); | ||
1232 | snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); | ||
1233 | gpr++; | ||
1234 | |||
1235 | if (emu->spk71) { | ||
1236 | /* Stereo Mix Side Playback */ | ||
1237 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+6), A_GPR(playback+6), A_GPR(gpr), A_GPR(stereo_mix)); | ||
1238 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+7), A_GPR(playback+7), A_GPR(gpr+1), A_GPR(stereo_mix+1)); | ||
1239 | snd_emu10k1_init_stereo_control(&controls[nctl++], "Side Playback Volume", gpr, 0); | ||
1240 | gpr += 2; | ||
1241 | } | ||
1242 | |||
1243 | /* | ||
1244 | * outputs | ||
1245 | */ | ||
1246 | #define A_PUT_OUTPUT(out,src) A_OP(icode, &ptr, iACC3, A_EXTOUT(out), A_C_00000000, A_C_00000000, A_GPR(src)) | ||
1247 | #define A_PUT_STEREO_OUTPUT(out1,out2,src) \ | ||
1248 | {A_PUT_OUTPUT(out1,src); A_PUT_OUTPUT(out2,src+1);} | ||
1249 | |||
1250 | #define _A_SWITCH(icode, ptr, dst, src, sw) \ | ||
1251 | A_OP((icode), ptr, iMACINT0, dst, A_C_00000000, src, sw); | ||
1252 | #define A_SWITCH(icode, ptr, dst, src, sw) \ | ||
1253 | _A_SWITCH(icode, ptr, A_GPR(dst), A_GPR(src), A_GPR(sw)) | ||
1254 | #define _A_SWITCH_NEG(icode, ptr, dst, src) \ | ||
1255 | A_OP((icode), ptr, iANDXOR, dst, src, A_C_00000001, A_C_00000001); | ||
1256 | #define A_SWITCH_NEG(icode, ptr, dst, src) \ | ||
1257 | _A_SWITCH_NEG(icode, ptr, A_GPR(dst), A_GPR(src)) | ||
1258 | |||
1259 | |||
1260 | /* | ||
1261 | * Process tone control | ||
1262 | */ | ||
1263 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), A_GPR(playback + 0), A_C_00000000, A_C_00000000); /* left */ | ||
1264 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), A_GPR(playback + 1), A_C_00000000, A_C_00000000); /* right */ | ||
1265 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), A_GPR(playback + 2), A_C_00000000, A_C_00000000); /* rear left */ | ||
1266 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), A_GPR(playback + 3), A_C_00000000, A_C_00000000); /* rear right */ | ||
1267 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), A_GPR(playback + 4), A_C_00000000, A_C_00000000); /* center */ | ||
1268 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), A_GPR(playback + 5), A_C_00000000, A_C_00000000); /* LFE */ | ||
1269 | if (emu->spk71) { | ||
1270 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 6), A_GPR(playback + 6), A_C_00000000, A_C_00000000); /* side left */ | ||
1271 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 7), A_GPR(playback + 7), A_C_00000000, A_C_00000000); /* side right */ | ||
1272 | } | ||
1273 | |||
1274 | |||
1275 | ctl = &controls[nctl + 0]; | ||
1276 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1277 | strcpy(ctl->id.name, "Tone Control - Bass"); | ||
1278 | ctl->vcount = 2; | ||
1279 | ctl->count = 10; | ||
1280 | ctl->min = 0; | ||
1281 | ctl->max = 40; | ||
1282 | ctl->value[0] = ctl->value[1] = 20; | ||
1283 | ctl->translation = EMU10K1_GPR_TRANSLATION_BASS; | ||
1284 | ctl = &controls[nctl + 1]; | ||
1285 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1286 | strcpy(ctl->id.name, "Tone Control - Treble"); | ||
1287 | ctl->vcount = 2; | ||
1288 | ctl->count = 10; | ||
1289 | ctl->min = 0; | ||
1290 | ctl->max = 40; | ||
1291 | ctl->value[0] = ctl->value[1] = 20; | ||
1292 | ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE; | ||
1293 | |||
1294 | #define BASS_GPR 0x8c | ||
1295 | #define TREBLE_GPR 0x96 | ||
1296 | |||
1297 | for (z = 0; z < 5; z++) { | ||
1298 | int j; | ||
1299 | for (j = 0; j < 2; j++) { | ||
1300 | controls[nctl + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j; | ||
1301 | controls[nctl + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j; | ||
1302 | } | ||
1303 | } | ||
1304 | for (z = 0; z < 4; z++) { /* front/rear/center-lfe/side */ | ||
1305 | int j, k, l, d; | ||
1306 | for (j = 0; j < 2; j++) { /* left/right */ | ||
1307 | k = 0xb0 + (z * 8) + (j * 4); | ||
1308 | l = 0xe0 + (z * 8) + (j * 4); | ||
1309 | d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j; | ||
1310 | |||
1311 | A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(d), A_GPR(BASS_GPR + 0 + j)); | ||
1312 | A_OP(icode, &ptr, iMACMV, A_GPR(k+1), A_GPR(k), A_GPR(k+1), A_GPR(BASS_GPR + 4 + j)); | ||
1313 | A_OP(icode, &ptr, iMACMV, A_GPR(k), A_GPR(d), A_GPR(k), A_GPR(BASS_GPR + 2 + j)); | ||
1314 | A_OP(icode, &ptr, iMACMV, A_GPR(k+3), A_GPR(k+2), A_GPR(k+3), A_GPR(BASS_GPR + 8 + j)); | ||
1315 | A_OP(icode, &ptr, iMAC0, A_GPR(k+2), A_GPR_ACCU, A_GPR(k+2), A_GPR(BASS_GPR + 6 + j)); | ||
1316 | A_OP(icode, &ptr, iACC3, A_GPR(k+2), A_GPR(k+2), A_GPR(k+2), A_C_00000000); | ||
1317 | |||
1318 | A_OP(icode, &ptr, iMAC0, A_C_00000000, A_C_00000000, A_GPR(k+2), A_GPR(TREBLE_GPR + 0 + j)); | ||
1319 | A_OP(icode, &ptr, iMACMV, A_GPR(l+1), A_GPR(l), A_GPR(l+1), A_GPR(TREBLE_GPR + 4 + j)); | ||
1320 | A_OP(icode, &ptr, iMACMV, A_GPR(l), A_GPR(k+2), A_GPR(l), A_GPR(TREBLE_GPR + 2 + j)); | ||
1321 | A_OP(icode, &ptr, iMACMV, A_GPR(l+3), A_GPR(l+2), A_GPR(l+3), A_GPR(TREBLE_GPR + 8 + j)); | ||
1322 | A_OP(icode, &ptr, iMAC0, A_GPR(l+2), A_GPR_ACCU, A_GPR(l+2), A_GPR(TREBLE_GPR + 6 + j)); | ||
1323 | A_OP(icode, &ptr, iMACINT0, A_GPR(l+2), A_C_00000000, A_GPR(l+2), A_C_00000010); | ||
1324 | |||
1325 | A_OP(icode, &ptr, iACC3, A_GPR(d), A_GPR(l+2), A_C_00000000, A_C_00000000); | ||
1326 | |||
1327 | if (z == 2) /* center */ | ||
1328 | break; | ||
1329 | } | ||
1330 | } | ||
1331 | nctl += 2; | ||
1332 | |||
1333 | #undef BASS_GPR | ||
1334 | #undef TREBLE_GPR | ||
1335 | |||
1336 | for (z = 0; z < 8; z++) { | ||
1337 | A_SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0); | ||
1338 | A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0); | ||
1339 | A_SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1); | ||
1340 | A_OP(icode, &ptr, iACC3, A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); | ||
1341 | } | ||
1342 | snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0); | ||
1343 | gpr += 2; | ||
1344 | |||
1345 | /* Master volume (will be renamed later) */ | ||
1346 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS)); | ||
1347 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS)); | ||
1348 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS)); | ||
1349 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS)); | ||
1350 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS)); | ||
1351 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS)); | ||
1352 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+6+SND_EMU10K1_PLAYBACK_CHANNELS)); | ||
1353 | A_OP(icode, &ptr, iMAC0, A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+7+SND_EMU10K1_PLAYBACK_CHANNELS)); | ||
1354 | snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0); | ||
1355 | gpr += 2; | ||
1356 | |||
1357 | /* analog speakers */ | ||
1358 | A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1359 | A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1360 | A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1361 | A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1362 | if (emu->spk71) | ||
1363 | A_PUT_STEREO_OUTPUT(A_EXTOUT_ASIDE_L, A_EXTOUT_ASIDE_R, playback+6 + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1364 | |||
1365 | /* headphone */ | ||
1366 | A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1367 | |||
1368 | /* digital outputs */ | ||
1369 | /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ | ||
1370 | |||
1371 | /* IEC958 Optical Raw Playback Switch */ | ||
1372 | gpr_map[gpr++] = 0; | ||
1373 | gpr_map[gpr++] = 0x1008; | ||
1374 | gpr_map[gpr++] = 0xffff0000; | ||
1375 | for (z = 0; z < 2; z++) { | ||
1376 | A_OP(icode, &ptr, iMAC0, A_GPR(tmp + 2), A_FXBUS(FXBUS_PT_LEFT + z), A_C_00000000, A_C_00000000); | ||
1377 | A_OP(icode, &ptr, iSKIP, A_GPR_COND, A_GPR_COND, A_GPR(gpr - 2), A_C_00000001); | ||
1378 | A_OP(icode, &ptr, iACC3, A_GPR(tmp + 2), A_C_00000000, A_C_00010000, A_GPR(tmp + 2)); | ||
1379 | A_OP(icode, &ptr, iANDXOR, A_GPR(tmp + 2), A_GPR(tmp + 2), A_GPR(gpr - 1), A_C_00000000); | ||
1380 | A_SWITCH(icode, &ptr, tmp + 0, tmp + 2, gpr + z); | ||
1381 | A_SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z); | ||
1382 | A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1); | ||
1383 | if ((z==1) && (emu->card_capabilities->spdif_bug)) { | ||
1384 | /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */ | ||
1385 | snd_printk("Installing spdif_bug patch: %s\n", emu->card_capabilities->name); | ||
1386 | A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000); | ||
1387 | A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); | ||
1388 | } else { | ||
1389 | A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); | ||
1390 | } | ||
1391 | } | ||
1392 | snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "IEC958 Optical Raw Playback Switch", gpr, 0); | ||
1393 | gpr += 2; | ||
1394 | |||
1395 | A_PUT_STEREO_OUTPUT(A_EXTOUT_REAR_L, A_EXTOUT_REAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1396 | A_PUT_OUTPUT(A_EXTOUT_CENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1397 | A_PUT_OUTPUT(A_EXTOUT_LFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1398 | |||
1399 | /* ADC buffer */ | ||
1400 | #ifdef EMU10K1_CAPTURE_DIGITAL_OUT | ||
1401 | A_PUT_STEREO_OUTPUT(A_EXTOUT_ADC_CAP_L, A_EXTOUT_ADC_CAP_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); | ||
1402 | #else | ||
1403 | A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_L, capture); | ||
1404 | A_PUT_OUTPUT(A_EXTOUT_ADC_CAP_R, capture+1); | ||
1405 | #endif | ||
1406 | |||
1407 | /* EFX capture - capture the 16 EXTINs */ | ||
1408 | for (z = 0; z < 16; z++) { | ||
1409 | A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z)); | ||
1410 | } | ||
1411 | |||
1412 | /* | ||
1413 | * ok, set up done.. | ||
1414 | */ | ||
1415 | |||
1416 | if (gpr > tmp) { | ||
1417 | snd_BUG(); | ||
1418 | err = -EIO; | ||
1419 | goto __err; | ||
1420 | } | ||
1421 | /* clear remaining instruction memory */ | ||
1422 | while (ptr < 0x400) | ||
1423 | A_OP(icode, &ptr, 0x0f, 0xc0, 0xc0, 0xcf, 0xc0); | ||
1424 | |||
1425 | seg = snd_enter_user(); | ||
1426 | icode->gpr_add_control_count = nctl; | ||
1427 | icode->gpr_add_controls = (emu10k1_fx8010_control_gpr_t __user *)controls; | ||
1428 | err = snd_emu10k1_icode_poke(emu, icode); | ||
1429 | snd_leave_user(seg); | ||
1430 | |||
1431 | __err: | ||
1432 | kfree(controls); | ||
1433 | if (icode != NULL) { | ||
1434 | kfree((void *)icode->gpr_map); | ||
1435 | kfree(icode); | ||
1436 | } | ||
1437 | return err; | ||
1438 | } | ||
1439 | |||
1440 | |||
1441 | /* | ||
1442 | * initial DSP configuration for Emu10k1 | ||
1443 | */ | ||
1444 | |||
1445 | /* when volume = max, then copy only to avoid volume modification */ | ||
1446 | /* with iMAC0 (negative values) */ | ||
1447 | static void __devinit _volume(emu10k1_fx8010_code_t *icode, u32 *ptr, u32 dst, u32 src, u32 vol) | ||
1448 | { | ||
1449 | OP(icode, ptr, iMAC0, dst, C_00000000, src, vol); | ||
1450 | OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); | ||
1451 | OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001); | ||
1452 | OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000); | ||
1453 | } | ||
1454 | static void __devinit _volume_add(emu10k1_fx8010_code_t *icode, u32 *ptr, u32 dst, u32 src, u32 vol) | ||
1455 | { | ||
1456 | OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); | ||
1457 | OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); | ||
1458 | OP(icode, ptr, iMACINT0, dst, dst, src, C_00000001); | ||
1459 | OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001); | ||
1460 | OP(icode, ptr, iMAC0, dst, dst, src, vol); | ||
1461 | } | ||
1462 | static void __devinit _volume_out(emu10k1_fx8010_code_t *icode, u32 *ptr, u32 dst, u32 src, u32 vol) | ||
1463 | { | ||
1464 | OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); | ||
1465 | OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); | ||
1466 | OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000); | ||
1467 | OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001); | ||
1468 | OP(icode, ptr, iMAC0, dst, C_00000000, src, vol); | ||
1469 | } | ||
1470 | |||
1471 | #define VOLUME(icode, ptr, dst, src, vol) \ | ||
1472 | _volume(icode, ptr, GPR(dst), GPR(src), GPR(vol)) | ||
1473 | #define VOLUME_IN(icode, ptr, dst, src, vol) \ | ||
1474 | _volume(icode, ptr, GPR(dst), EXTIN(src), GPR(vol)) | ||
1475 | #define VOLUME_ADD(icode, ptr, dst, src, vol) \ | ||
1476 | _volume_add(icode, ptr, GPR(dst), GPR(src), GPR(vol)) | ||
1477 | #define VOLUME_ADDIN(icode, ptr, dst, src, vol) \ | ||
1478 | _volume_add(icode, ptr, GPR(dst), EXTIN(src), GPR(vol)) | ||
1479 | #define VOLUME_OUT(icode, ptr, dst, src, vol) \ | ||
1480 | _volume_out(icode, ptr, EXTOUT(dst), GPR(src), GPR(vol)) | ||
1481 | #define _SWITCH(icode, ptr, dst, src, sw) \ | ||
1482 | OP((icode), ptr, iMACINT0, dst, C_00000000, src, sw); | ||
1483 | #define SWITCH(icode, ptr, dst, src, sw) \ | ||
1484 | _SWITCH(icode, ptr, GPR(dst), GPR(src), GPR(sw)) | ||
1485 | #define SWITCH_IN(icode, ptr, dst, src, sw) \ | ||
1486 | _SWITCH(icode, ptr, GPR(dst), EXTIN(src), GPR(sw)) | ||
1487 | #define _SWITCH_NEG(icode, ptr, dst, src) \ | ||
1488 | OP((icode), ptr, iANDXOR, dst, src, C_00000001, C_00000001); | ||
1489 | #define SWITCH_NEG(icode, ptr, dst, src) \ | ||
1490 | _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src)) | ||
1491 | |||
1492 | |||
1493 | static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) | ||
1494 | { | ||
1495 | int err, i, z, gpr, tmp, playback, capture; | ||
1496 | u32 ptr; | ||
1497 | emu10k1_fx8010_code_t *icode; | ||
1498 | emu10k1_fx8010_pcm_t *ipcm = NULL; | ||
1499 | emu10k1_fx8010_control_gpr_t *controls = NULL, *ctl; | ||
1500 | u32 *gpr_map; | ||
1501 | mm_segment_t seg; | ||
1502 | |||
1503 | spin_lock_init(&emu->fx8010.irq_lock); | ||
1504 | INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); | ||
1505 | |||
1506 | if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL) | ||
1507 | return -ENOMEM; | ||
1508 | if ((icode->gpr_map = (u_int32_t __user *)kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t), GFP_KERNEL)) == NULL || | ||
1509 | (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(emu10k1_fx8010_control_gpr_t), GFP_KERNEL)) == NULL || | ||
1510 | (ipcm = kcalloc(1, sizeof(*ipcm), GFP_KERNEL)) == NULL) { | ||
1511 | err = -ENOMEM; | ||
1512 | goto __err; | ||
1513 | } | ||
1514 | gpr_map = (u32 *)icode->gpr_map; | ||
1515 | |||
1516 | icode->tram_data_map = icode->gpr_map + 256; | ||
1517 | icode->tram_addr_map = icode->tram_data_map + 160; | ||
1518 | icode->code = icode->tram_addr_map + 160; | ||
1519 | |||
1520 | /* clear free GPRs */ | ||
1521 | for (i = 0; i < 256; i++) | ||
1522 | set_bit(i, icode->gpr_valid); | ||
1523 | |||
1524 | /* clear TRAM data & address lines */ | ||
1525 | for (i = 0; i < 160; i++) | ||
1526 | set_bit(i, icode->tram_valid); | ||
1527 | |||
1528 | strcpy(icode->name, "SB Live! FX8010 code for ALSA v1.2 by Jaroslav Kysela"); | ||
1529 | ptr = 0; i = 0; | ||
1530 | /* we have 10 inputs */ | ||
1531 | playback = SND_EMU10K1_INPUTS; | ||
1532 | /* we have 6 playback channels and tone control doubles */ | ||
1533 | capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); | ||
1534 | gpr = capture + SND_EMU10K1_CAPTURE_CHANNELS; | ||
1535 | tmp = 0x88; /* we need 4 temporary GPR */ | ||
1536 | /* from 0x8c to 0xff is the area for tone control */ | ||
1537 | |||
1538 | /* stop FX processor */ | ||
1539 | snd_emu10k1_ptr_write(emu, DBG, 0, (emu->fx8010.dbg = 0) | EMU10K1_DBG_SINGLE_STEP); | ||
1540 | |||
1541 | /* | ||
1542 | * Process FX Buses | ||
1543 | */ | ||
1544 | OP(icode, &ptr, iMACINT0, GPR(0), C_00000000, FXBUS(FXBUS_PCM_LEFT), C_00000004); | ||
1545 | OP(icode, &ptr, iMACINT0, GPR(1), C_00000000, FXBUS(FXBUS_PCM_RIGHT), C_00000004); | ||
1546 | OP(icode, &ptr, iMACINT0, GPR(2), C_00000000, FXBUS(FXBUS_MIDI_LEFT), C_00000004); | ||
1547 | OP(icode, &ptr, iMACINT0, GPR(3), C_00000000, FXBUS(FXBUS_MIDI_RIGHT), C_00000004); | ||
1548 | OP(icode, &ptr, iMACINT0, GPR(4), C_00000000, FXBUS(FXBUS_PCM_LEFT_REAR), C_00000004); | ||
1549 | OP(icode, &ptr, iMACINT0, GPR(5), C_00000000, FXBUS(FXBUS_PCM_RIGHT_REAR), C_00000004); | ||
1550 | OP(icode, &ptr, iMACINT0, GPR(6), C_00000000, FXBUS(FXBUS_PCM_CENTER), C_00000004); | ||
1551 | OP(icode, &ptr, iMACINT0, GPR(7), C_00000000, FXBUS(FXBUS_PCM_LFE), C_00000004); | ||
1552 | OP(icode, &ptr, iMACINT0, GPR(8), C_00000000, C_00000000, C_00000000); /* S/PDIF left */ | ||
1553 | OP(icode, &ptr, iMACINT0, GPR(9), C_00000000, C_00000000, C_00000000); /* S/PDIF right */ | ||
1554 | |||
1555 | /* Raw S/PDIF PCM */ | ||
1556 | ipcm->substream = 0; | ||
1557 | ipcm->channels = 2; | ||
1558 | ipcm->tram_start = 0; | ||
1559 | ipcm->buffer_size = (64 * 1024) / 2; | ||
1560 | ipcm->gpr_size = gpr++; | ||
1561 | ipcm->gpr_ptr = gpr++; | ||
1562 | ipcm->gpr_count = gpr++; | ||
1563 | ipcm->gpr_tmpcount = gpr++; | ||
1564 | ipcm->gpr_trigger = gpr++; | ||
1565 | ipcm->gpr_running = gpr++; | ||
1566 | ipcm->etram[0] = 0; | ||
1567 | ipcm->etram[1] = 1; | ||
1568 | |||
1569 | gpr_map[gpr + 0] = 0xfffff000; | ||
1570 | gpr_map[gpr + 1] = 0xffff0000; | ||
1571 | gpr_map[gpr + 2] = 0x70000000; | ||
1572 | gpr_map[gpr + 3] = 0x00000007; | ||
1573 | gpr_map[gpr + 4] = 0x001f << 11; | ||
1574 | gpr_map[gpr + 5] = 0x001c << 11; | ||
1575 | gpr_map[gpr + 6] = (0x22 - 0x01) - 1; /* skip at 01 to 22 */ | ||
1576 | gpr_map[gpr + 7] = (0x22 - 0x06) - 1; /* skip at 06 to 22 */ | ||
1577 | gpr_map[gpr + 8] = 0x2000000 + (2<<11); | ||
1578 | gpr_map[gpr + 9] = 0x4000000 + (2<<11); | ||
1579 | gpr_map[gpr + 10] = 1<<11; | ||
1580 | gpr_map[gpr + 11] = (0x24 - 0x0a) - 1; /* skip at 0a to 24 */ | ||
1581 | gpr_map[gpr + 12] = 0; | ||
1582 | |||
1583 | /* if the trigger flag is not set, skip */ | ||
1584 | /* 00: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_trigger), C_00000000, C_00000000); | ||
1585 | /* 01: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_ZERO, GPR(gpr + 6)); | ||
1586 | /* if the running flag is set, we're running */ | ||
1587 | /* 02: */ OP(icode, &ptr, iMAC0, C_00000000, GPR(ipcm->gpr_running), C_00000000, C_00000000); | ||
1588 | /* 03: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000004); | ||
1589 | /* wait until ((GPR_DBAC>>11) & 0x1f) == 0x1c) */ | ||
1590 | /* 04: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), GPR_DBAC, GPR(gpr + 4), C_00000000); | ||
1591 | /* 05: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(gpr + 5)); | ||
1592 | /* 06: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 7)); | ||
1593 | /* 07: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000010, C_00000001, C_00000000); | ||
1594 | |||
1595 | /* 08: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000000, C_00000001); | ||
1596 | /* 09: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), GPR(gpr + 12), C_ffffffff, C_00000000); | ||
1597 | /* 0a: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, GPR(gpr + 11)); | ||
1598 | /* 0b: */ OP(icode, &ptr, iACC3, GPR(gpr + 12), C_00000001, C_00000000, C_00000000); | ||
1599 | |||
1600 | /* 0c: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[0]), GPR(gpr + 0), C_00000000); | ||
1601 | /* 0d: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000); | ||
1602 | /* 0e: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2)); | ||
1603 | /* 0f: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001); | ||
1604 | /* 10: */ OP(icode, &ptr, iANDXOR, GPR(8), GPR(8), GPR(gpr + 1), GPR(gpr + 2)); | ||
1605 | |||
1606 | /* 11: */ OP(icode, &ptr, iANDXOR, GPR(tmp + 0), ETRAM_DATA(ipcm->etram[1]), GPR(gpr + 0), C_00000000); | ||
1607 | /* 12: */ OP(icode, &ptr, iLOG, GPR(tmp + 0), GPR(tmp + 0), GPR(gpr + 3), C_00000000); | ||
1608 | /* 13: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(tmp + 0), GPR(gpr + 1), GPR(gpr + 2)); | ||
1609 | /* 14: */ OP(icode, &ptr, iSKIP, C_00000000, GPR_COND, CC_REG_MINUS, C_00000001); | ||
1610 | /* 15: */ OP(icode, &ptr, iANDXOR, GPR(9), GPR(9), GPR(gpr + 1), GPR(gpr + 2)); | ||
1611 | |||
1612 | /* 16: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(ipcm->gpr_ptr), C_00000001, C_00000000); | ||
1613 | /* 17: */ OP(icode, &ptr, iMACINT0, C_00000000, GPR(tmp + 0), C_ffffffff, GPR(ipcm->gpr_size)); | ||
1614 | /* 18: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_MINUS, C_00000001); | ||
1615 | /* 19: */ OP(icode, &ptr, iACC3, GPR(tmp + 0), C_00000000, C_00000000, C_00000000); | ||
1616 | /* 1a: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_ptr), GPR(tmp + 0), C_00000000, C_00000000); | ||
1617 | |||
1618 | /* 1b: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_tmpcount), C_ffffffff, C_00000000); | ||
1619 | /* 1c: */ OP(icode, &ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); | ||
1620 | /* 1d: */ OP(icode, &ptr, iACC3, GPR(ipcm->gpr_tmpcount), GPR(ipcm->gpr_count), C_00000000, C_00000000); | ||
1621 | /* 1e: */ OP(icode, &ptr, iACC3, GPR_IRQ, C_80000000, C_00000000, C_00000000); | ||
1622 | /* 1f: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00000001, C_00010000); | ||
1623 | |||
1624 | /* 20: */ OP(icode, &ptr, iANDXOR, GPR(ipcm->gpr_running), GPR(ipcm->gpr_running), C_00010000, C_00000001); | ||
1625 | /* 21: */ OP(icode, &ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000002); | ||
1626 | |||
1627 | /* 22: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[0]), GPR(gpr + 8), GPR_DBAC, C_ffffffff); | ||
1628 | /* 23: */ OP(icode, &ptr, iMACINT1, ETRAM_ADDR(ipcm->etram[1]), GPR(gpr + 9), GPR_DBAC, C_ffffffff); | ||
1629 | |||
1630 | /* 24: */ | ||
1631 | gpr += 13; | ||
1632 | |||
1633 | /* Wave Playback Volume */ | ||
1634 | for (z = 0; z < 2; z++) | ||
1635 | VOLUME(icode, &ptr, playback + z, z, gpr + z); | ||
1636 | snd_emu10k1_init_stereo_control(controls + i++, "Wave Playback Volume", gpr, 100); | ||
1637 | gpr += 2; | ||
1638 | |||
1639 | /* Wave Surround Playback Volume */ | ||
1640 | for (z = 0; z < 2; z++) | ||
1641 | VOLUME(icode, &ptr, playback + 2 + z, z, gpr + z); | ||
1642 | snd_emu10k1_init_stereo_control(controls + i++, "Wave Surround Playback Volume", gpr, 0); | ||
1643 | gpr += 2; | ||
1644 | |||
1645 | /* Wave Center/LFE Playback Volume */ | ||
1646 | OP(icode, &ptr, iACC3, GPR(tmp + 0), FXBUS(FXBUS_PCM_LEFT), FXBUS(FXBUS_PCM_RIGHT), C_00000000); | ||
1647 | OP(icode, &ptr, iMACINT0, GPR(tmp + 0), C_00000000, GPR(tmp + 0), C_00000002); | ||
1648 | VOLUME(icode, &ptr, playback + 4, tmp + 0, gpr); | ||
1649 | snd_emu10k1_init_mono_control(controls + i++, "Wave Center Playback Volume", gpr++, 0); | ||
1650 | VOLUME(icode, &ptr, playback + 5, tmp + 0, gpr); | ||
1651 | snd_emu10k1_init_mono_control(controls + i++, "Wave LFE Playback Volume", gpr++, 0); | ||
1652 | |||
1653 | /* Wave Capture Volume + Switch */ | ||
1654 | for (z = 0; z < 2; z++) { | ||
1655 | SWITCH(icode, &ptr, tmp + 0, z, gpr + 2 + z); | ||
1656 | VOLUME(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1657 | } | ||
1658 | snd_emu10k1_init_stereo_control(controls + i++, "Wave Capture Volume", gpr, 0); | ||
1659 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "Wave Capture Switch", gpr + 2, 0); | ||
1660 | gpr += 4; | ||
1661 | |||
1662 | /* Synth Playback Volume */ | ||
1663 | for (z = 0; z < 2; z++) | ||
1664 | VOLUME_ADD(icode, &ptr, playback + z, 2 + z, gpr + z); | ||
1665 | snd_emu10k1_init_stereo_control(controls + i++, "Synth Playback Volume", gpr, 100); | ||
1666 | gpr += 2; | ||
1667 | |||
1668 | /* Synth Capture Volume + Switch */ | ||
1669 | for (z = 0; z < 2; z++) { | ||
1670 | SWITCH(icode, &ptr, tmp + 0, 2 + z, gpr + 2 + z); | ||
1671 | VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1672 | } | ||
1673 | snd_emu10k1_init_stereo_control(controls + i++, "Synth Capture Volume", gpr, 0); | ||
1674 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "Synth Capture Switch", gpr + 2, 0); | ||
1675 | gpr += 4; | ||
1676 | |||
1677 | /* Surround Digital Playback Volume (renamed later without Digital) */ | ||
1678 | for (z = 0; z < 2; z++) | ||
1679 | VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z); | ||
1680 | snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100); | ||
1681 | gpr += 2; | ||
1682 | |||
1683 | /* Surround Capture Volume + Switch */ | ||
1684 | for (z = 0; z < 2; z++) { | ||
1685 | SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z); | ||
1686 | VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1687 | } | ||
1688 | snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0); | ||
1689 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0); | ||
1690 | gpr += 4; | ||
1691 | |||
1692 | /* Center Playback Volume (renamed later without Digital) */ | ||
1693 | VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr); | ||
1694 | snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100); | ||
1695 | |||
1696 | /* LFE Playback Volume + Switch (renamed later without Digital) */ | ||
1697 | VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr); | ||
1698 | snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100); | ||
1699 | |||
1700 | /* | ||
1701 | * Process inputs | ||
1702 | */ | ||
1703 | |||
1704 | if (emu->fx8010.extin_mask & ((1<<EXTIN_AC97_L)|(1<<EXTIN_AC97_R))) { | ||
1705 | /* AC'97 Playback Volume */ | ||
1706 | VOLUME_ADDIN(icode, &ptr, playback + 0, EXTIN_AC97_L, gpr); gpr++; | ||
1707 | VOLUME_ADDIN(icode, &ptr, playback + 1, EXTIN_AC97_R, gpr); gpr++; | ||
1708 | snd_emu10k1_init_stereo_control(controls + i++, "AC97 Playback Volume", gpr-2, 0); | ||
1709 | /* AC'97 Capture Volume */ | ||
1710 | VOLUME_ADDIN(icode, &ptr, capture + 0, EXTIN_AC97_L, gpr); gpr++; | ||
1711 | VOLUME_ADDIN(icode, &ptr, capture + 1, EXTIN_AC97_R, gpr); gpr++; | ||
1712 | snd_emu10k1_init_stereo_control(controls + i++, "AC97 Capture Volume", gpr-2, 100); | ||
1713 | } | ||
1714 | |||
1715 | if (emu->fx8010.extin_mask & ((1<<EXTIN_SPDIF_CD_L)|(1<<EXTIN_SPDIF_CD_R))) { | ||
1716 | /* IEC958 TTL Playback Volume */ | ||
1717 | for (z = 0; z < 2; z++) | ||
1718 | VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_SPDIF_CD_L + z, gpr + z); | ||
1719 | snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Playback Volume", gpr, 0); | ||
1720 | gpr += 2; | ||
1721 | |||
1722 | /* IEC958 TTL Capture Volume + Switch */ | ||
1723 | for (z = 0; z < 2; z++) { | ||
1724 | SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_SPDIF_CD_L + z, gpr + 2 + z); | ||
1725 | VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1726 | } | ||
1727 | snd_emu10k1_init_stereo_control(controls + i++, "IEC958 TTL Capture Volume", gpr, 0); | ||
1728 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 TTL Capture Switch", gpr + 2, 0); | ||
1729 | gpr += 4; | ||
1730 | } | ||
1731 | |||
1732 | if (emu->fx8010.extin_mask & ((1<<EXTIN_ZOOM_L)|(1<<EXTIN_ZOOM_R))) { | ||
1733 | /* Zoom Video Playback Volume */ | ||
1734 | for (z = 0; z < 2; z++) | ||
1735 | VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_ZOOM_L + z, gpr + z); | ||
1736 | snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Playback Volume", gpr, 0); | ||
1737 | gpr += 2; | ||
1738 | |||
1739 | /* Zoom Video Capture Volume + Switch */ | ||
1740 | for (z = 0; z < 2; z++) { | ||
1741 | SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_ZOOM_L + z, gpr + 2 + z); | ||
1742 | VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1743 | } | ||
1744 | snd_emu10k1_init_stereo_control(controls + i++, "Zoom Video Capture Volume", gpr, 0); | ||
1745 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "Zoom Video Capture Switch", gpr + 2, 0); | ||
1746 | gpr += 4; | ||
1747 | } | ||
1748 | |||
1749 | if (emu->fx8010.extin_mask & ((1<<EXTIN_TOSLINK_L)|(1<<EXTIN_TOSLINK_R))) { | ||
1750 | /* IEC958 Optical Playback Volume */ | ||
1751 | for (z = 0; z < 2; z++) | ||
1752 | VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z); | ||
1753 | snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Playback Volume", gpr, 0); | ||
1754 | gpr += 2; | ||
1755 | |||
1756 | /* IEC958 Optical Capture Volume */ | ||
1757 | for (z = 0; z < 2; z++) { | ||
1758 | SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z); | ||
1759 | VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1760 | } | ||
1761 | snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Capture Volume", gpr, 0); | ||
1762 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 LiveDrive Capture Switch", gpr + 2, 0); | ||
1763 | gpr += 4; | ||
1764 | } | ||
1765 | |||
1766 | if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE1_L)|(1<<EXTIN_LINE1_R))) { | ||
1767 | /* Line LiveDrive Playback Volume */ | ||
1768 | for (z = 0; z < 2; z++) | ||
1769 | VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE1_L + z, gpr + z); | ||
1770 | snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0); | ||
1771 | gpr += 2; | ||
1772 | |||
1773 | /* Line LiveDrive Capture Volume + Switch */ | ||
1774 | for (z = 0; z < 2; z++) { | ||
1775 | SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE1_L + z, gpr + 2 + z); | ||
1776 | VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1777 | } | ||
1778 | snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0); | ||
1779 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0); | ||
1780 | gpr += 4; | ||
1781 | } | ||
1782 | |||
1783 | if (emu->fx8010.extin_mask & ((1<<EXTIN_COAX_SPDIF_L)|(1<<EXTIN_COAX_SPDIF_R))) { | ||
1784 | /* IEC958 Coax Playback Volume */ | ||
1785 | for (z = 0; z < 2; z++) | ||
1786 | VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_COAX_SPDIF_L + z, gpr + z); | ||
1787 | snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Playback Volume", gpr, 0); | ||
1788 | gpr += 2; | ||
1789 | |||
1790 | /* IEC958 Coax Capture Volume + Switch */ | ||
1791 | for (z = 0; z < 2; z++) { | ||
1792 | SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_COAX_SPDIF_L + z, gpr + 2 + z); | ||
1793 | VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1794 | } | ||
1795 | snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Coaxial Capture Volume", gpr, 0); | ||
1796 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Coaxial Capture Switch", gpr + 2, 0); | ||
1797 | gpr += 4; | ||
1798 | } | ||
1799 | |||
1800 | if (emu->fx8010.extin_mask & ((1<<EXTIN_LINE2_L)|(1<<EXTIN_LINE2_R))) { | ||
1801 | /* Line LiveDrive Playback Volume */ | ||
1802 | for (z = 0; z < 2; z++) | ||
1803 | VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z); | ||
1804 | snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0); | ||
1805 | controls[i-1].id.index = 1; | ||
1806 | gpr += 2; | ||
1807 | |||
1808 | /* Line LiveDrive Capture Volume */ | ||
1809 | for (z = 0; z < 2; z++) { | ||
1810 | SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z); | ||
1811 | VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); | ||
1812 | } | ||
1813 | snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0); | ||
1814 | controls[i-1].id.index = 1; | ||
1815 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0); | ||
1816 | controls[i-1].id.index = 1; | ||
1817 | gpr += 4; | ||
1818 | } | ||
1819 | |||
1820 | /* | ||
1821 | * Process tone control | ||
1822 | */ | ||
1823 | OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), GPR(playback + 0), C_00000000, C_00000000); /* left */ | ||
1824 | OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), GPR(playback + 1), C_00000000, C_00000000); /* right */ | ||
1825 | OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2), GPR(playback + 2), C_00000000, C_00000000); /* rear left */ | ||
1826 | OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 3), GPR(playback + 3), C_00000000, C_00000000); /* rear right */ | ||
1827 | OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), GPR(playback + 4), C_00000000, C_00000000); /* center */ | ||
1828 | OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), GPR(playback + 5), C_00000000, C_00000000); /* LFE */ | ||
1829 | |||
1830 | ctl = &controls[i + 0]; | ||
1831 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1832 | strcpy(ctl->id.name, "Tone Control - Bass"); | ||
1833 | ctl->vcount = 2; | ||
1834 | ctl->count = 10; | ||
1835 | ctl->min = 0; | ||
1836 | ctl->max = 40; | ||
1837 | ctl->value[0] = ctl->value[1] = 20; | ||
1838 | ctl->translation = EMU10K1_GPR_TRANSLATION_BASS; | ||
1839 | ctl = &controls[i + 1]; | ||
1840 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
1841 | strcpy(ctl->id.name, "Tone Control - Treble"); | ||
1842 | ctl->vcount = 2; | ||
1843 | ctl->count = 10; | ||
1844 | ctl->min = 0; | ||
1845 | ctl->max = 40; | ||
1846 | ctl->value[0] = ctl->value[1] = 20; | ||
1847 | ctl->translation = EMU10K1_GPR_TRANSLATION_TREBLE; | ||
1848 | |||
1849 | #define BASS_GPR 0x8c | ||
1850 | #define TREBLE_GPR 0x96 | ||
1851 | |||
1852 | for (z = 0; z < 5; z++) { | ||
1853 | int j; | ||
1854 | for (j = 0; j < 2; j++) { | ||
1855 | controls[i + 0].gpr[z * 2 + j] = BASS_GPR + z * 2 + j; | ||
1856 | controls[i + 1].gpr[z * 2 + j] = TREBLE_GPR + z * 2 + j; | ||
1857 | } | ||
1858 | } | ||
1859 | for (z = 0; z < 3; z++) { /* front/rear/center-lfe */ | ||
1860 | int j, k, l, d; | ||
1861 | for (j = 0; j < 2; j++) { /* left/right */ | ||
1862 | k = 0xa0 + (z * 8) + (j * 4); | ||
1863 | l = 0xd0 + (z * 8) + (j * 4); | ||
1864 | d = playback + SND_EMU10K1_PLAYBACK_CHANNELS + z * 2 + j; | ||
1865 | |||
1866 | OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(d), GPR(BASS_GPR + 0 + j)); | ||
1867 | OP(icode, &ptr, iMACMV, GPR(k+1), GPR(k), GPR(k+1), GPR(BASS_GPR + 4 + j)); | ||
1868 | OP(icode, &ptr, iMACMV, GPR(k), GPR(d), GPR(k), GPR(BASS_GPR + 2 + j)); | ||
1869 | OP(icode, &ptr, iMACMV, GPR(k+3), GPR(k+2), GPR(k+3), GPR(BASS_GPR + 8 + j)); | ||
1870 | OP(icode, &ptr, iMAC0, GPR(k+2), GPR_ACCU, GPR(k+2), GPR(BASS_GPR + 6 + j)); | ||
1871 | OP(icode, &ptr, iACC3, GPR(k+2), GPR(k+2), GPR(k+2), C_00000000); | ||
1872 | |||
1873 | OP(icode, &ptr, iMAC0, C_00000000, C_00000000, GPR(k+2), GPR(TREBLE_GPR + 0 + j)); | ||
1874 | OP(icode, &ptr, iMACMV, GPR(l+1), GPR(l), GPR(l+1), GPR(TREBLE_GPR + 4 + j)); | ||
1875 | OP(icode, &ptr, iMACMV, GPR(l), GPR(k+2), GPR(l), GPR(TREBLE_GPR + 2 + j)); | ||
1876 | OP(icode, &ptr, iMACMV, GPR(l+3), GPR(l+2), GPR(l+3), GPR(TREBLE_GPR + 8 + j)); | ||
1877 | OP(icode, &ptr, iMAC0, GPR(l+2), GPR_ACCU, GPR(l+2), GPR(TREBLE_GPR + 6 + j)); | ||
1878 | OP(icode, &ptr, iMACINT0, GPR(l+2), C_00000000, GPR(l+2), C_00000010); | ||
1879 | |||
1880 | OP(icode, &ptr, iACC3, GPR(d), GPR(l+2), C_00000000, C_00000000); | ||
1881 | |||
1882 | if (z == 2) /* center */ | ||
1883 | break; | ||
1884 | } | ||
1885 | } | ||
1886 | i += 2; | ||
1887 | |||
1888 | #undef BASS_GPR | ||
1889 | #undef TREBLE_GPR | ||
1890 | |||
1891 | for (z = 0; z < 6; z++) { | ||
1892 | SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, gpr + 0); | ||
1893 | SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 0); | ||
1894 | SWITCH(icode, &ptr, tmp + 1, playback + z, tmp + 1); | ||
1895 | OP(icode, &ptr, iACC3, GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000); | ||
1896 | } | ||
1897 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "Tone Control - Switch", gpr, 0); | ||
1898 | gpr += 2; | ||
1899 | |||
1900 | /* | ||
1901 | * Process outputs | ||
1902 | */ | ||
1903 | if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_L)|(1<<EXTOUT_AC97_R))) { | ||
1904 | /* AC'97 Playback Volume */ | ||
1905 | |||
1906 | for (z = 0; z < 2; z++) | ||
1907 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), C_00000000, C_00000000); | ||
1908 | } | ||
1909 | |||
1910 | if (emu->fx8010.extout_mask & ((1<<EXTOUT_TOSLINK_L)|(1<<EXTOUT_TOSLINK_R))) { | ||
1911 | /* IEC958 Optical Raw Playback Switch */ | ||
1912 | |||
1913 | for (z = 0; z < 2; z++) { | ||
1914 | SWITCH(icode, &ptr, tmp + 0, 8 + z, gpr + z); | ||
1915 | SWITCH_NEG(icode, &ptr, tmp + 1, gpr + z); | ||
1916 | SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1); | ||
1917 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_TOSLINK_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000); | ||
1918 | #ifdef EMU10K1_CAPTURE_DIGITAL_OUT | ||
1919 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(tmp + 0), GPR(tmp + 1), C_00000000); | ||
1920 | #endif | ||
1921 | } | ||
1922 | |||
1923 | snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Optical Raw Playback Switch", gpr, 0); | ||
1924 | gpr += 2; | ||
1925 | } | ||
1926 | |||
1927 | if (emu->fx8010.extout_mask & ((1<<EXTOUT_HEADPHONE_L)|(1<<EXTOUT_HEADPHONE_R))) { | ||
1928 | /* Headphone Playback Volume */ | ||
1929 | |||
1930 | for (z = 0; z < 2; z++) { | ||
1931 | SWITCH(icode, &ptr, tmp + 0, playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4 + z, gpr + 2 + z); | ||
1932 | SWITCH_NEG(icode, &ptr, tmp + 1, gpr + 2 + z); | ||
1933 | SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1); | ||
1934 | OP(icode, &ptr, iACC3, GPR(tmp + 0), GPR(tmp + 0), GPR(tmp + 1), C_00000000); | ||
1935 | VOLUME_OUT(icode, &ptr, EXTOUT_HEADPHONE_L + z, tmp + 0, gpr + z); | ||
1936 | } | ||
1937 | |||
1938 | snd_emu10k1_init_stereo_control(controls + i++, "Headphone Playback Volume", gpr + 0, 0); | ||
1939 | controls[i-1].id.index = 1; /* AC'97 can have also Headphone control */ | ||
1940 | snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone Center Playback Switch", gpr + 2, 0); | ||
1941 | controls[i-1].id.index = 1; | ||
1942 | snd_emu10k1_init_mono_onoff_control(controls + i++, "Headphone LFE Playback Switch", gpr + 3, 0); | ||
1943 | controls[i-1].id.index = 1; | ||
1944 | |||
1945 | gpr += 4; | ||
1946 | } | ||
1947 | |||
1948 | if (emu->fx8010.extout_mask & ((1<<EXTOUT_REAR_L)|(1<<EXTOUT_REAR_R))) | ||
1949 | for (z = 0; z < 2; z++) | ||
1950 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000); | ||
1951 | |||
1952 | if (emu->fx8010.extout_mask & ((1<<EXTOUT_AC97_REAR_L)|(1<<EXTOUT_AC97_REAR_R))) | ||
1953 | for (z = 0; z < 2; z++) | ||
1954 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_REAR_L + z), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 2 + z), C_00000000, C_00000000); | ||
1955 | |||
1956 | if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_CENTER)) { | ||
1957 | #ifndef EMU10K1_CENTER_LFE_FROM_FRONT | ||
1958 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000); | ||
1959 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 4), C_00000000, C_00000000); | ||
1960 | #else | ||
1961 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_CENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000); | ||
1962 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ACENTER), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 0), C_00000000, C_00000000); | ||
1963 | #endif | ||
1964 | } | ||
1965 | |||
1966 | if (emu->fx8010.extout_mask & (1<<EXTOUT_AC97_LFE)) { | ||
1967 | #ifndef EMU10K1_CENTER_LFE_FROM_FRONT | ||
1968 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000); | ||
1969 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 5), C_00000000, C_00000000); | ||
1970 | #else | ||
1971 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_AC97_LFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000); | ||
1972 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ALFE), GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + 1), C_00000000, C_00000000); | ||
1973 | #endif | ||
1974 | } | ||
1975 | |||
1976 | #ifndef EMU10K1_CAPTURE_DIGITAL_OUT | ||
1977 | for (z = 0; z < 2; z++) | ||
1978 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_ADC_CAP_L + z), GPR(capture + z), C_00000000, C_00000000); | ||
1979 | #endif | ||
1980 | |||
1981 | if (emu->fx8010.extout_mask & (1<<EXTOUT_MIC_CAP)) | ||
1982 | OP(icode, &ptr, iACC3, EXTOUT(EXTOUT_MIC_CAP), GPR(capture + 2), C_00000000, C_00000000); | ||
1983 | |||
1984 | /* EFX capture - capture the 16 EXTINS */ | ||
1985 | OP(icode, &ptr, iACC3, FXBUS2(14), C_00000000, C_00000000, EXTIN(0)); | ||
1986 | OP(icode, &ptr, iACC3, FXBUS2(15), C_00000000, C_00000000, EXTIN(1)); | ||
1987 | OP(icode, &ptr, iACC3, FXBUS2(0), C_00000000, C_00000000, EXTIN(2)); | ||
1988 | OP(icode, &ptr, iACC3, FXBUS2(3), C_00000000, C_00000000, EXTIN(3)); | ||
1989 | /* Dont connect anything to FXBUS2 1 and 2. These are shared with | ||
1990 | * Center/LFE on the SBLive 5.1. The kX driver only changes the | ||
1991 | * routing when it detects an SBLive 5.1. | ||
1992 | * | ||
1993 | * Since only 14 of the 16 EXTINs are used, this is not a big problem. | ||
1994 | * We route AC97L and R to FX capture 14 and 15, SPDIF CD in to FX capture | ||
1995 | * 0 and 3, then the rest of the EXTINs to the corresponding FX capture | ||
1996 | * channel. | ||
1997 | */ | ||
1998 | for (z = 4; z < 14; z++) { | ||
1999 | OP(icode, &ptr, iACC3, FXBUS2(z), C_00000000, C_00000000, EXTIN(z)); | ||
2000 | } | ||
2001 | |||
2002 | if (gpr > tmp) { | ||
2003 | snd_BUG(); | ||
2004 | err = -EIO; | ||
2005 | goto __err; | ||
2006 | } | ||
2007 | if (i > SND_EMU10K1_GPR_CONTROLS) { | ||
2008 | snd_BUG(); | ||
2009 | err = -EIO; | ||
2010 | goto __err; | ||
2011 | } | ||
2012 | |||
2013 | /* clear remaining instruction memory */ | ||
2014 | while (ptr < 0x200) | ||
2015 | OP(icode, &ptr, iACC3, C_00000000, C_00000000, C_00000000, C_00000000); | ||
2016 | |||
2017 | if ((err = snd_emu10k1_fx8010_tram_setup(emu, ipcm->buffer_size)) < 0) | ||
2018 | goto __err; | ||
2019 | seg = snd_enter_user(); | ||
2020 | icode->gpr_add_control_count = i; | ||
2021 | icode->gpr_add_controls = (emu10k1_fx8010_control_gpr_t __user *)controls; | ||
2022 | err = snd_emu10k1_icode_poke(emu, icode); | ||
2023 | snd_leave_user(seg); | ||
2024 | if (err >= 0) | ||
2025 | err = snd_emu10k1_ipcm_poke(emu, ipcm); | ||
2026 | __err: | ||
2027 | kfree(ipcm); | ||
2028 | kfree(controls); | ||
2029 | if (icode != NULL) { | ||
2030 | kfree((void *)icode->gpr_map); | ||
2031 | kfree(icode); | ||
2032 | } | ||
2033 | return err; | ||
2034 | } | ||
2035 | |||
2036 | int __devinit snd_emu10k1_init_efx(emu10k1_t *emu) | ||
2037 | { | ||
2038 | if (emu->audigy) | ||
2039 | return _snd_emu10k1_audigy_init_efx(emu); | ||
2040 | else | ||
2041 | return _snd_emu10k1_init_efx(emu); | ||
2042 | } | ||
2043 | |||
2044 | void snd_emu10k1_free_efx(emu10k1_t *emu) | ||
2045 | { | ||
2046 | /* stop processor */ | ||
2047 | if (emu->audigy) | ||
2048 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = A_DBG_SINGLE_STEP); | ||
2049 | else | ||
2050 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = EMU10K1_DBG_SINGLE_STEP); | ||
2051 | } | ||
2052 | |||
2053 | #if 0 // FIXME: who use them? | ||
2054 | int snd_emu10k1_fx8010_tone_control_activate(emu10k1_t *emu, int output) | ||
2055 | { | ||
2056 | snd_runtime_check(output >= 0 && output < 6, return -EINVAL); | ||
2057 | snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 1); | ||
2058 | return 0; | ||
2059 | } | ||
2060 | |||
2061 | int snd_emu10k1_fx8010_tone_control_deactivate(emu10k1_t *emu, int output) | ||
2062 | { | ||
2063 | snd_runtime_check(output >= 0 && output < 6, return -EINVAL); | ||
2064 | snd_emu10k1_ptr_write(emu, emu->gpr_base + 0x94 + output, 0, 0); | ||
2065 | return 0; | ||
2066 | } | ||
2067 | #endif | ||
2068 | |||
2069 | int snd_emu10k1_fx8010_tram_setup(emu10k1_t *emu, u32 size) | ||
2070 | { | ||
2071 | u8 size_reg = 0; | ||
2072 | |||
2073 | /* size is in samples */ | ||
2074 | if (size != 0) { | ||
2075 | size = (size - 1) >> 13; | ||
2076 | |||
2077 | while (size) { | ||
2078 | size >>= 1; | ||
2079 | size_reg++; | ||
2080 | } | ||
2081 | size = 0x2000 << size_reg; | ||
2082 | } | ||
2083 | if ((emu->fx8010.etram_pages.bytes / 2) == size) | ||
2084 | return 0; | ||
2085 | spin_lock_irq(&emu->emu_lock); | ||
2086 | outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG); | ||
2087 | spin_unlock_irq(&emu->emu_lock); | ||
2088 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); | ||
2089 | snd_emu10k1_ptr_write(emu, TCBS, 0, 0); | ||
2090 | if (emu->fx8010.etram_pages.area != NULL) { | ||
2091 | snd_dma_free_pages(&emu->fx8010.etram_pages); | ||
2092 | emu->fx8010.etram_pages.area = NULL; | ||
2093 | emu->fx8010.etram_pages.bytes = 0; | ||
2094 | } | ||
2095 | |||
2096 | if (size > 0) { | ||
2097 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), | ||
2098 | size * 2, &emu->fx8010.etram_pages) < 0) | ||
2099 | return -ENOMEM; | ||
2100 | memset(emu->fx8010.etram_pages.area, 0, size * 2); | ||
2101 | snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr); | ||
2102 | snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg); | ||
2103 | spin_lock_irq(&emu->emu_lock); | ||
2104 | outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); | ||
2105 | spin_unlock_irq(&emu->emu_lock); | ||
2106 | } | ||
2107 | |||
2108 | return 0; | ||
2109 | } | ||
2110 | |||
2111 | static int snd_emu10k1_fx8010_open(snd_hwdep_t * hw, struct file *file) | ||
2112 | { | ||
2113 | return 0; | ||
2114 | } | ||
2115 | |||
2116 | static void copy_string(char *dst, char *src, char *null, int idx) | ||
2117 | { | ||
2118 | if (src == NULL) | ||
2119 | sprintf(dst, "%s %02X", null, idx); | ||
2120 | else | ||
2121 | strcpy(dst, src); | ||
2122 | } | ||
2123 | |||
2124 | static int snd_emu10k1_fx8010_info(emu10k1_t *emu, emu10k1_fx8010_info_t *info) | ||
2125 | { | ||
2126 | char **fxbus, **extin, **extout; | ||
2127 | unsigned short fxbus_mask, extin_mask, extout_mask; | ||
2128 | int res; | ||
2129 | |||
2130 | memset(info, 0, sizeof(info)); | ||
2131 | info->card = emu->card_type; | ||
2132 | info->internal_tram_size = emu->fx8010.itram_size; | ||
2133 | info->external_tram_size = emu->fx8010.etram_pages.bytes / 2; | ||
2134 | fxbus = fxbuses; | ||
2135 | extin = emu->audigy ? audigy_ins : creative_ins; | ||
2136 | extout = emu->audigy ? audigy_outs : creative_outs; | ||
2137 | fxbus_mask = emu->fx8010.fxbus_mask; | ||
2138 | extin_mask = emu->fx8010.extin_mask; | ||
2139 | extout_mask = emu->fx8010.extout_mask; | ||
2140 | for (res = 0; res < 16; res++, fxbus++, extin++, extout++) { | ||
2141 | copy_string(info->fxbus_names[res], fxbus_mask & (1 << res) ? *fxbus : NULL, "FXBUS", res); | ||
2142 | copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res); | ||
2143 | copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res); | ||
2144 | } | ||
2145 | for (res = 16; res < 32; res++, extout++) | ||
2146 | copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res); | ||
2147 | info->gpr_controls = emu->fx8010.gpr_count; | ||
2148 | return 0; | ||
2149 | } | ||
2150 | |||
2151 | static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg) | ||
2152 | { | ||
2153 | emu10k1_t *emu = hw->private_data; | ||
2154 | emu10k1_fx8010_info_t *info; | ||
2155 | emu10k1_fx8010_code_t *icode; | ||
2156 | emu10k1_fx8010_pcm_t *ipcm; | ||
2157 | unsigned int addr; | ||
2158 | void __user *argp = (void __user *)arg; | ||
2159 | int res; | ||
2160 | |||
2161 | switch (cmd) { | ||
2162 | case SNDRV_EMU10K1_IOCTL_INFO: | ||
2163 | info = (emu10k1_fx8010_info_t *)kmalloc(sizeof(*info), GFP_KERNEL); | ||
2164 | if (!info) | ||
2165 | return -ENOMEM; | ||
2166 | if ((res = snd_emu10k1_fx8010_info(emu, info)) < 0) { | ||
2167 | kfree(info); | ||
2168 | return res; | ||
2169 | } | ||
2170 | if (copy_to_user(argp, info, sizeof(*info))) { | ||
2171 | kfree(info); | ||
2172 | return -EFAULT; | ||
2173 | } | ||
2174 | kfree(info); | ||
2175 | return 0; | ||
2176 | case SNDRV_EMU10K1_IOCTL_CODE_POKE: | ||
2177 | if (!capable(CAP_SYS_ADMIN)) | ||
2178 | return -EPERM; | ||
2179 | icode = (emu10k1_fx8010_code_t *)kmalloc(sizeof(*icode), GFP_KERNEL); | ||
2180 | if (icode == NULL) | ||
2181 | return -ENOMEM; | ||
2182 | if (copy_from_user(icode, argp, sizeof(*icode))) { | ||
2183 | kfree(icode); | ||
2184 | return -EFAULT; | ||
2185 | } | ||
2186 | res = snd_emu10k1_icode_poke(emu, icode); | ||
2187 | kfree(icode); | ||
2188 | return res; | ||
2189 | case SNDRV_EMU10K1_IOCTL_CODE_PEEK: | ||
2190 | icode = (emu10k1_fx8010_code_t *)kmalloc(sizeof(*icode), GFP_KERNEL); | ||
2191 | if (icode == NULL) | ||
2192 | return -ENOMEM; | ||
2193 | if (copy_from_user(icode, argp, sizeof(*icode))) { | ||
2194 | kfree(icode); | ||
2195 | return -EFAULT; | ||
2196 | } | ||
2197 | res = snd_emu10k1_icode_peek(emu, icode); | ||
2198 | if (res == 0 && copy_to_user(argp, icode, sizeof(*icode))) { | ||
2199 | kfree(icode); | ||
2200 | return -EFAULT; | ||
2201 | } | ||
2202 | kfree(icode); | ||
2203 | return res; | ||
2204 | case SNDRV_EMU10K1_IOCTL_PCM_POKE: | ||
2205 | ipcm = (emu10k1_fx8010_pcm_t *)kmalloc(sizeof(*ipcm), GFP_KERNEL); | ||
2206 | if (ipcm == NULL) | ||
2207 | return -ENOMEM; | ||
2208 | if (copy_from_user(ipcm, argp, sizeof(*ipcm))) { | ||
2209 | kfree(ipcm); | ||
2210 | return -EFAULT; | ||
2211 | } | ||
2212 | res = snd_emu10k1_ipcm_poke(emu, ipcm); | ||
2213 | kfree(ipcm); | ||
2214 | return res; | ||
2215 | case SNDRV_EMU10K1_IOCTL_PCM_PEEK: | ||
2216 | ipcm = kcalloc(1, sizeof(*ipcm), GFP_KERNEL); | ||
2217 | if (ipcm == NULL) | ||
2218 | return -ENOMEM; | ||
2219 | if (copy_from_user(ipcm, argp, sizeof(*ipcm))) { | ||
2220 | kfree(ipcm); | ||
2221 | return -EFAULT; | ||
2222 | } | ||
2223 | res = snd_emu10k1_ipcm_peek(emu, ipcm); | ||
2224 | if (res == 0 && copy_to_user(argp, ipcm, sizeof(*ipcm))) { | ||
2225 | kfree(ipcm); | ||
2226 | return -EFAULT; | ||
2227 | } | ||
2228 | kfree(ipcm); | ||
2229 | return res; | ||
2230 | case SNDRV_EMU10K1_IOCTL_TRAM_SETUP: | ||
2231 | if (!capable(CAP_SYS_ADMIN)) | ||
2232 | return -EPERM; | ||
2233 | if (get_user(addr, (unsigned int __user *)argp)) | ||
2234 | return -EFAULT; | ||
2235 | down(&emu->fx8010.lock); | ||
2236 | res = snd_emu10k1_fx8010_tram_setup(emu, addr); | ||
2237 | up(&emu->fx8010.lock); | ||
2238 | return res; | ||
2239 | case SNDRV_EMU10K1_IOCTL_STOP: | ||
2240 | if (!capable(CAP_SYS_ADMIN)) | ||
2241 | return -EPERM; | ||
2242 | if (emu->audigy) | ||
2243 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP); | ||
2244 | else | ||
2245 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP); | ||
2246 | return 0; | ||
2247 | case SNDRV_EMU10K1_IOCTL_CONTINUE: | ||
2248 | if (!capable(CAP_SYS_ADMIN)) | ||
2249 | return -EPERM; | ||
2250 | if (emu->audigy) | ||
2251 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg = 0); | ||
2252 | else | ||
2253 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg = 0); | ||
2254 | return 0; | ||
2255 | case SNDRV_EMU10K1_IOCTL_ZERO_TRAM_COUNTER: | ||
2256 | if (!capable(CAP_SYS_ADMIN)) | ||
2257 | return -EPERM; | ||
2258 | if (emu->audigy) | ||
2259 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_ZC); | ||
2260 | else | ||
2261 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_ZC); | ||
2262 | udelay(10); | ||
2263 | if (emu->audigy) | ||
2264 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg); | ||
2265 | else | ||
2266 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg); | ||
2267 | return 0; | ||
2268 | case SNDRV_EMU10K1_IOCTL_SINGLE_STEP: | ||
2269 | if (!capable(CAP_SYS_ADMIN)) | ||
2270 | return -EPERM; | ||
2271 | if (get_user(addr, (unsigned int __user *)argp)) | ||
2272 | return -EFAULT; | ||
2273 | if (addr > 0x1ff) | ||
2274 | return -EINVAL; | ||
2275 | if (emu->audigy) | ||
2276 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | addr); | ||
2277 | else | ||
2278 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | addr); | ||
2279 | udelay(10); | ||
2280 | if (emu->audigy) | ||
2281 | snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg |= A_DBG_SINGLE_STEP | A_DBG_STEP_ADDR | addr); | ||
2282 | else | ||
2283 | snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg |= EMU10K1_DBG_SINGLE_STEP | EMU10K1_DBG_STEP | addr); | ||
2284 | return 0; | ||
2285 | case SNDRV_EMU10K1_IOCTL_DBG_READ: | ||
2286 | if (emu->audigy) | ||
2287 | addr = snd_emu10k1_ptr_read(emu, A_DBG, 0); | ||
2288 | else | ||
2289 | addr = snd_emu10k1_ptr_read(emu, DBG, 0); | ||
2290 | if (put_user(addr, (unsigned int __user *)argp)) | ||
2291 | return -EFAULT; | ||
2292 | return 0; | ||
2293 | } | ||
2294 | return -ENOTTY; | ||
2295 | } | ||
2296 | |||
2297 | static int snd_emu10k1_fx8010_release(snd_hwdep_t * hw, struct file *file) | ||
2298 | { | ||
2299 | return 0; | ||
2300 | } | ||
2301 | |||
2302 | int __devinit snd_emu10k1_fx8010_new(emu10k1_t *emu, int device, snd_hwdep_t ** rhwdep) | ||
2303 | { | ||
2304 | snd_hwdep_t *hw; | ||
2305 | int err; | ||
2306 | |||
2307 | if (rhwdep) | ||
2308 | *rhwdep = NULL; | ||
2309 | if ((err = snd_hwdep_new(emu->card, "FX8010", device, &hw)) < 0) | ||
2310 | return err; | ||
2311 | strcpy(hw->name, "EMU10K1 (FX8010)"); | ||
2312 | hw->iface = SNDRV_HWDEP_IFACE_EMU10K1; | ||
2313 | hw->ops.open = snd_emu10k1_fx8010_open; | ||
2314 | hw->ops.ioctl = snd_emu10k1_fx8010_ioctl; | ||
2315 | hw->ops.release = snd_emu10k1_fx8010_release; | ||
2316 | hw->private_data = emu; | ||
2317 | if (rhwdep) | ||
2318 | *rhwdep = hw; | ||
2319 | return 0; | ||
2320 | } | ||
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c new file mode 100644 index 000000000000..044663d31aa7 --- /dev/null +++ b/sound/pci/emu10k1/emumixer.c | |||
@@ -0,0 +1,955 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz>, | ||
3 | * Takashi Iwai <tiwai@suse.de> | ||
4 | * Creative Labs, Inc. | ||
5 | * Routines for control of EMU10K1 chips / mixer routines | ||
6 | * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> | ||
7 | * | ||
8 | * BUGS: | ||
9 | * -- | ||
10 | * | ||
11 | * TODO: | ||
12 | * -- | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
27 | * | ||
28 | */ | ||
29 | |||
30 | #include <sound/driver.h> | ||
31 | #include <linux/time.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/emu10k1.h> | ||
35 | |||
36 | #define AC97_ID_STAC9758 0x83847658 | ||
37 | |||
38 | static int snd_emu10k1_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
39 | { | ||
40 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
41 | uinfo->count = 1; | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | static int snd_emu10k1_spdif_get(snd_kcontrol_t * kcontrol, | ||
46 | snd_ctl_elem_value_t * ucontrol) | ||
47 | { | ||
48 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
49 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
50 | unsigned long flags; | ||
51 | |||
52 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
53 | ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; | ||
54 | ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; | ||
55 | ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; | ||
56 | ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; | ||
57 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int snd_emu10k1_spdif_get_mask(snd_kcontrol_t * kcontrol, | ||
62 | snd_ctl_elem_value_t * ucontrol) | ||
63 | { | ||
64 | ucontrol->value.iec958.status[0] = 0xff; | ||
65 | ucontrol->value.iec958.status[1] = 0xff; | ||
66 | ucontrol->value.iec958.status[2] = 0xff; | ||
67 | ucontrol->value.iec958.status[3] = 0xff; | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int snd_audigy_spdif_output_rate_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
72 | { | ||
73 | static char *texts[] = {"44100", "48000", "96000"}; | ||
74 | |||
75 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
76 | uinfo->count = 1; | ||
77 | uinfo->value.enumerated.items = 3; | ||
78 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
79 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
80 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int snd_audigy_spdif_output_rate_get(snd_kcontrol_t * kcontrol, | ||
85 | snd_ctl_elem_value_t * ucontrol) | ||
86 | { | ||
87 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
88 | unsigned int tmp; | ||
89 | unsigned long flags; | ||
90 | |||
91 | |||
92 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
93 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | ||
94 | switch (tmp & A_SPDIF_RATE_MASK) { | ||
95 | case A_SPDIF_44100: | ||
96 | ucontrol->value.enumerated.item[0] = 0; | ||
97 | break; | ||
98 | case A_SPDIF_48000: | ||
99 | ucontrol->value.enumerated.item[0] = 1; | ||
100 | break; | ||
101 | case A_SPDIF_96000: | ||
102 | ucontrol->value.enumerated.item[0] = 2; | ||
103 | break; | ||
104 | default: | ||
105 | ucontrol->value.enumerated.item[0] = 1; | ||
106 | } | ||
107 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int snd_audigy_spdif_output_rate_put(snd_kcontrol_t * kcontrol, | ||
112 | snd_ctl_elem_value_t * ucontrol) | ||
113 | { | ||
114 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
115 | int change; | ||
116 | unsigned int reg, val, tmp; | ||
117 | unsigned long flags; | ||
118 | |||
119 | switch(ucontrol->value.enumerated.item[0]) { | ||
120 | case 0: | ||
121 | val = A_SPDIF_44100; | ||
122 | break; | ||
123 | case 1: | ||
124 | val = A_SPDIF_48000; | ||
125 | break; | ||
126 | case 2: | ||
127 | val = A_SPDIF_96000; | ||
128 | break; | ||
129 | default: | ||
130 | val = A_SPDIF_48000; | ||
131 | break; | ||
132 | } | ||
133 | |||
134 | |||
135 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
136 | reg = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | ||
137 | tmp = reg & ~A_SPDIF_RATE_MASK; | ||
138 | tmp |= val; | ||
139 | if ((change = (tmp != reg))) | ||
140 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, 0, tmp); | ||
141 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
142 | return change; | ||
143 | } | ||
144 | |||
145 | static snd_kcontrol_new_t snd_audigy_spdif_output_rate = | ||
146 | { | ||
147 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
148 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
149 | .name = "Audigy SPDIF Output Sample Rate", | ||
150 | .count = 1, | ||
151 | .info = snd_audigy_spdif_output_rate_info, | ||
152 | .get = snd_audigy_spdif_output_rate_get, | ||
153 | .put = snd_audigy_spdif_output_rate_put | ||
154 | }; | ||
155 | |||
156 | static int snd_emu10k1_spdif_put(snd_kcontrol_t * kcontrol, | ||
157 | snd_ctl_elem_value_t * ucontrol) | ||
158 | { | ||
159 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
160 | unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
161 | int change; | ||
162 | unsigned int val; | ||
163 | unsigned long flags; | ||
164 | |||
165 | val = (ucontrol->value.iec958.status[0] << 0) | | ||
166 | (ucontrol->value.iec958.status[1] << 8) | | ||
167 | (ucontrol->value.iec958.status[2] << 16) | | ||
168 | (ucontrol->value.iec958.status[3] << 24); | ||
169 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
170 | change = val != emu->spdif_bits[idx]; | ||
171 | if (change) { | ||
172 | snd_emu10k1_ptr_write(emu, SPCS0 + idx, 0, val); | ||
173 | emu->spdif_bits[idx] = val; | ||
174 | } | ||
175 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
176 | return change; | ||
177 | } | ||
178 | |||
179 | static snd_kcontrol_new_t snd_emu10k1_spdif_mask_control = | ||
180 | { | ||
181 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
182 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
183 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), | ||
184 | .count = 4, | ||
185 | .info = snd_emu10k1_spdif_info, | ||
186 | .get = snd_emu10k1_spdif_get_mask | ||
187 | }; | ||
188 | |||
189 | static snd_kcontrol_new_t snd_emu10k1_spdif_control = | ||
190 | { | ||
191 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
192 | .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), | ||
193 | .count = 4, | ||
194 | .info = snd_emu10k1_spdif_info, | ||
195 | .get = snd_emu10k1_spdif_get, | ||
196 | .put = snd_emu10k1_spdif_put | ||
197 | }; | ||
198 | |||
199 | |||
200 | static void update_emu10k1_fxrt(emu10k1_t *emu, int voice, unsigned char *route) | ||
201 | { | ||
202 | if (emu->audigy) { | ||
203 | snd_emu10k1_ptr_write(emu, A_FXRT1, voice, | ||
204 | snd_emu10k1_compose_audigy_fxrt1(route)); | ||
205 | snd_emu10k1_ptr_write(emu, A_FXRT2, voice, | ||
206 | snd_emu10k1_compose_audigy_fxrt2(route)); | ||
207 | } else { | ||
208 | snd_emu10k1_ptr_write(emu, FXRT, voice, | ||
209 | snd_emu10k1_compose_send_routing(route)); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | static void update_emu10k1_send_volume(emu10k1_t *emu, int voice, unsigned char *volume) | ||
214 | { | ||
215 | snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_A, voice, volume[0]); | ||
216 | snd_emu10k1_ptr_write(emu, PTRX_FXSENDAMOUNT_B, voice, volume[1]); | ||
217 | snd_emu10k1_ptr_write(emu, PSST_FXSENDAMOUNT_C, voice, volume[2]); | ||
218 | snd_emu10k1_ptr_write(emu, DSL_FXSENDAMOUNT_D, voice, volume[3]); | ||
219 | if (emu->audigy) { | ||
220 | unsigned int val = ((unsigned int)volume[4] << 24) | | ||
221 | ((unsigned int)volume[5] << 16) | | ||
222 | ((unsigned int)volume[6] << 8) | | ||
223 | (unsigned int)volume[7]; | ||
224 | snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, val); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | /* PCM stream controls */ | ||
229 | |||
230 | static int snd_emu10k1_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
231 | { | ||
232 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
233 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
234 | uinfo->count = emu->audigy ? 3*8 : 3*4; | ||
235 | uinfo->value.integer.min = 0; | ||
236 | uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int snd_emu10k1_send_routing_get(snd_kcontrol_t * kcontrol, | ||
241 | snd_ctl_elem_value_t * ucontrol) | ||
242 | { | ||
243 | unsigned long flags; | ||
244 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
245 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
246 | int voice, idx; | ||
247 | int num_efx = emu->audigy ? 8 : 4; | ||
248 | int mask = emu->audigy ? 0x3f : 0x0f; | ||
249 | |||
250 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
251 | for (voice = 0; voice < 3; voice++) | ||
252 | for (idx = 0; idx < num_efx; idx++) | ||
253 | ucontrol->value.integer.value[(voice * num_efx) + idx] = | ||
254 | mix->send_routing[voice][idx] & mask; | ||
255 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int snd_emu10k1_send_routing_put(snd_kcontrol_t * kcontrol, | ||
260 | snd_ctl_elem_value_t * ucontrol) | ||
261 | { | ||
262 | unsigned long flags; | ||
263 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
264 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
265 | int change = 0, voice, idx, val; | ||
266 | int num_efx = emu->audigy ? 8 : 4; | ||
267 | int mask = emu->audigy ? 0x3f : 0x0f; | ||
268 | |||
269 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
270 | for (voice = 0; voice < 3; voice++) | ||
271 | for (idx = 0; idx < num_efx; idx++) { | ||
272 | val = ucontrol->value.integer.value[(voice * num_efx) + idx] & mask; | ||
273 | if (mix->send_routing[voice][idx] != val) { | ||
274 | mix->send_routing[voice][idx] = val; | ||
275 | change = 1; | ||
276 | } | ||
277 | } | ||
278 | if (change && mix->epcm) { | ||
279 | if (mix->epcm->voices[0] && mix->epcm->voices[1]) { | ||
280 | update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, | ||
281 | &mix->send_routing[1][0]); | ||
282 | update_emu10k1_fxrt(emu, mix->epcm->voices[1]->number, | ||
283 | &mix->send_routing[2][0]); | ||
284 | } else if (mix->epcm->voices[0]) { | ||
285 | update_emu10k1_fxrt(emu, mix->epcm->voices[0]->number, | ||
286 | &mix->send_routing[0][0]); | ||
287 | } | ||
288 | } | ||
289 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
290 | return change; | ||
291 | } | ||
292 | |||
293 | static snd_kcontrol_new_t snd_emu10k1_send_routing_control = | ||
294 | { | ||
295 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
296 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
297 | .name = "EMU10K1 PCM Send Routing", | ||
298 | .count = 32, | ||
299 | .info = snd_emu10k1_send_routing_info, | ||
300 | .get = snd_emu10k1_send_routing_get, | ||
301 | .put = snd_emu10k1_send_routing_put | ||
302 | }; | ||
303 | |||
304 | static int snd_emu10k1_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
305 | { | ||
306 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
307 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
308 | uinfo->count = emu->audigy ? 3*8 : 3*4; | ||
309 | uinfo->value.integer.min = 0; | ||
310 | uinfo->value.integer.max = 255; | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int snd_emu10k1_send_volume_get(snd_kcontrol_t * kcontrol, | ||
315 | snd_ctl_elem_value_t * ucontrol) | ||
316 | { | ||
317 | unsigned long flags; | ||
318 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
319 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
320 | int idx; | ||
321 | int num_efx = emu->audigy ? 8 : 4; | ||
322 | |||
323 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
324 | for (idx = 0; idx < 3*num_efx; idx++) | ||
325 | ucontrol->value.integer.value[idx] = mix->send_volume[idx/num_efx][idx%num_efx]; | ||
326 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int snd_emu10k1_send_volume_put(snd_kcontrol_t * kcontrol, | ||
331 | snd_ctl_elem_value_t * ucontrol) | ||
332 | { | ||
333 | unsigned long flags; | ||
334 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
335 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
336 | int change = 0, idx, val; | ||
337 | int num_efx = emu->audigy ? 8 : 4; | ||
338 | |||
339 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
340 | for (idx = 0; idx < 3*num_efx; idx++) { | ||
341 | val = ucontrol->value.integer.value[idx] & 255; | ||
342 | if (mix->send_volume[idx/num_efx][idx%num_efx] != val) { | ||
343 | mix->send_volume[idx/num_efx][idx%num_efx] = val; | ||
344 | change = 1; | ||
345 | } | ||
346 | } | ||
347 | if (change && mix->epcm) { | ||
348 | if (mix->epcm->voices[0] && mix->epcm->voices[1]) { | ||
349 | update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, | ||
350 | &mix->send_volume[1][0]); | ||
351 | update_emu10k1_send_volume(emu, mix->epcm->voices[1]->number, | ||
352 | &mix->send_volume[2][0]); | ||
353 | } else if (mix->epcm->voices[0]) { | ||
354 | update_emu10k1_send_volume(emu, mix->epcm->voices[0]->number, | ||
355 | &mix->send_volume[0][0]); | ||
356 | } | ||
357 | } | ||
358 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
359 | return change; | ||
360 | } | ||
361 | |||
362 | static snd_kcontrol_new_t snd_emu10k1_send_volume_control = | ||
363 | { | ||
364 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
365 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
366 | .name = "EMU10K1 PCM Send Volume", | ||
367 | .count = 32, | ||
368 | .info = snd_emu10k1_send_volume_info, | ||
369 | .get = snd_emu10k1_send_volume_get, | ||
370 | .put = snd_emu10k1_send_volume_put | ||
371 | }; | ||
372 | |||
373 | static int snd_emu10k1_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
374 | { | ||
375 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
376 | uinfo->count = 3; | ||
377 | uinfo->value.integer.min = 0; | ||
378 | uinfo->value.integer.max = 0xffff; | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int snd_emu10k1_attn_get(snd_kcontrol_t * kcontrol, | ||
383 | snd_ctl_elem_value_t * ucontrol) | ||
384 | { | ||
385 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
386 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
387 | unsigned long flags; | ||
388 | int idx; | ||
389 | |||
390 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
391 | for (idx = 0; idx < 3; idx++) | ||
392 | ucontrol->value.integer.value[idx] = mix->attn[idx]; | ||
393 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int snd_emu10k1_attn_put(snd_kcontrol_t * kcontrol, | ||
398 | snd_ctl_elem_value_t * ucontrol) | ||
399 | { | ||
400 | unsigned long flags; | ||
401 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
402 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
403 | int change = 0, idx, val; | ||
404 | |||
405 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
406 | for (idx = 0; idx < 3; idx++) { | ||
407 | val = ucontrol->value.integer.value[idx] & 0xffff; | ||
408 | if (mix->attn[idx] != val) { | ||
409 | mix->attn[idx] = val; | ||
410 | change = 1; | ||
411 | } | ||
412 | } | ||
413 | if (change && mix->epcm) { | ||
414 | if (mix->epcm->voices[0] && mix->epcm->voices[1]) { | ||
415 | snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[1]); | ||
416 | snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[1]->number, mix->attn[2]); | ||
417 | } else if (mix->epcm->voices[0]) { | ||
418 | snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[0]->number, mix->attn[0]); | ||
419 | } | ||
420 | } | ||
421 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
422 | return change; | ||
423 | } | ||
424 | |||
425 | static snd_kcontrol_new_t snd_emu10k1_attn_control = | ||
426 | { | ||
427 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
428 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
429 | .name = "EMU10K1 PCM Volume", | ||
430 | .count = 32, | ||
431 | .info = snd_emu10k1_attn_info, | ||
432 | .get = snd_emu10k1_attn_get, | ||
433 | .put = snd_emu10k1_attn_put | ||
434 | }; | ||
435 | |||
436 | /* Mutichannel PCM stream controls */ | ||
437 | |||
438 | static int snd_emu10k1_efx_send_routing_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
439 | { | ||
440 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
441 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
442 | uinfo->count = emu->audigy ? 8 : 4; | ||
443 | uinfo->value.integer.min = 0; | ||
444 | uinfo->value.integer.max = emu->audigy ? 0x3f : 0x0f; | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int snd_emu10k1_efx_send_routing_get(snd_kcontrol_t * kcontrol, | ||
449 | snd_ctl_elem_value_t * ucontrol) | ||
450 | { | ||
451 | unsigned long flags; | ||
452 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
453 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
454 | int idx; | ||
455 | int num_efx = emu->audigy ? 8 : 4; | ||
456 | int mask = emu->audigy ? 0x3f : 0x0f; | ||
457 | |||
458 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
459 | for (idx = 0; idx < num_efx; idx++) | ||
460 | ucontrol->value.integer.value[idx] = | ||
461 | mix->send_routing[0][idx] & mask; | ||
462 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int snd_emu10k1_efx_send_routing_put(snd_kcontrol_t * kcontrol, | ||
467 | snd_ctl_elem_value_t * ucontrol) | ||
468 | { | ||
469 | unsigned long flags; | ||
470 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
471 | int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
472 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch]; | ||
473 | int change = 0, idx, val; | ||
474 | int num_efx = emu->audigy ? 8 : 4; | ||
475 | int mask = emu->audigy ? 0x3f : 0x0f; | ||
476 | |||
477 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
478 | for (idx = 0; idx < num_efx; idx++) { | ||
479 | val = ucontrol->value.integer.value[idx] & mask; | ||
480 | if (mix->send_routing[0][idx] != val) { | ||
481 | mix->send_routing[0][idx] = val; | ||
482 | change = 1; | ||
483 | } | ||
484 | } | ||
485 | |||
486 | if (change && mix->epcm) { | ||
487 | if (mix->epcm->voices[ch]) { | ||
488 | update_emu10k1_fxrt(emu, mix->epcm->voices[ch]->number, | ||
489 | &mix->send_routing[0][0]); | ||
490 | } | ||
491 | } | ||
492 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
493 | return change; | ||
494 | } | ||
495 | |||
496 | static snd_kcontrol_new_t snd_emu10k1_efx_send_routing_control = | ||
497 | { | ||
498 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
499 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
500 | .name = "Multichannel PCM Send Routing", | ||
501 | .count = 16, | ||
502 | .info = snd_emu10k1_efx_send_routing_info, | ||
503 | .get = snd_emu10k1_efx_send_routing_get, | ||
504 | .put = snd_emu10k1_efx_send_routing_put | ||
505 | }; | ||
506 | |||
507 | static int snd_emu10k1_efx_send_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
508 | { | ||
509 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
510 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
511 | uinfo->count = emu->audigy ? 8 : 4; | ||
512 | uinfo->value.integer.min = 0; | ||
513 | uinfo->value.integer.max = 255; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int snd_emu10k1_efx_send_volume_get(snd_kcontrol_t * kcontrol, | ||
518 | snd_ctl_elem_value_t * ucontrol) | ||
519 | { | ||
520 | unsigned long flags; | ||
521 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
522 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
523 | int idx; | ||
524 | int num_efx = emu->audigy ? 8 : 4; | ||
525 | |||
526 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
527 | for (idx = 0; idx < num_efx; idx++) | ||
528 | ucontrol->value.integer.value[idx] = mix->send_volume[0][idx]; | ||
529 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int snd_emu10k1_efx_send_volume_put(snd_kcontrol_t * kcontrol, | ||
534 | snd_ctl_elem_value_t * ucontrol) | ||
535 | { | ||
536 | unsigned long flags; | ||
537 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
538 | int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
539 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch]; | ||
540 | int change = 0, idx, val; | ||
541 | int num_efx = emu->audigy ? 8 : 4; | ||
542 | |||
543 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
544 | for (idx = 0; idx < num_efx; idx++) { | ||
545 | val = ucontrol->value.integer.value[idx] & 255; | ||
546 | if (mix->send_volume[0][idx] != val) { | ||
547 | mix->send_volume[0][idx] = val; | ||
548 | change = 1; | ||
549 | } | ||
550 | } | ||
551 | if (change && mix->epcm) { | ||
552 | if (mix->epcm->voices[ch]) { | ||
553 | update_emu10k1_send_volume(emu, mix->epcm->voices[ch]->number, | ||
554 | &mix->send_volume[0][0]); | ||
555 | } | ||
556 | } | ||
557 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
558 | return change; | ||
559 | } | ||
560 | |||
561 | |||
562 | static snd_kcontrol_new_t snd_emu10k1_efx_send_volume_control = | ||
563 | { | ||
564 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
565 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
566 | .name = "Multichannel PCM Send Volume", | ||
567 | .count = 16, | ||
568 | .info = snd_emu10k1_efx_send_volume_info, | ||
569 | .get = snd_emu10k1_efx_send_volume_get, | ||
570 | .put = snd_emu10k1_efx_send_volume_put | ||
571 | }; | ||
572 | |||
573 | static int snd_emu10k1_efx_attn_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
574 | { | ||
575 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
576 | uinfo->count = 1; | ||
577 | uinfo->value.integer.min = 0; | ||
578 | uinfo->value.integer.max = 0xffff; | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int snd_emu10k1_efx_attn_get(snd_kcontrol_t * kcontrol, | ||
583 | snd_ctl_elem_value_t * ucontrol) | ||
584 | { | ||
585 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
586 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[snd_ctl_get_ioffidx(kcontrol, &ucontrol->id)]; | ||
587 | unsigned long flags; | ||
588 | |||
589 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
590 | ucontrol->value.integer.value[0] = mix->attn[0]; | ||
591 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int snd_emu10k1_efx_attn_put(snd_kcontrol_t * kcontrol, | ||
596 | snd_ctl_elem_value_t * ucontrol) | ||
597 | { | ||
598 | unsigned long flags; | ||
599 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
600 | int ch = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
601 | emu10k1_pcm_mixer_t *mix = &emu->efx_pcm_mixer[ch]; | ||
602 | int change = 0, val; | ||
603 | |||
604 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
605 | val = ucontrol->value.integer.value[0] & 0xffff; | ||
606 | if (mix->attn[0] != val) { | ||
607 | mix->attn[0] = val; | ||
608 | change = 1; | ||
609 | } | ||
610 | if (change && mix->epcm) { | ||
611 | if (mix->epcm->voices[ch]) { | ||
612 | snd_emu10k1_ptr_write(emu, VTFT_VOLUMETARGET, mix->epcm->voices[ch]->number, mix->attn[0]); | ||
613 | } | ||
614 | } | ||
615 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
616 | return change; | ||
617 | } | ||
618 | |||
619 | static snd_kcontrol_new_t snd_emu10k1_efx_attn_control = | ||
620 | { | ||
621 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
622 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
623 | .name = "Multichannel PCM Volume", | ||
624 | .count = 16, | ||
625 | .info = snd_emu10k1_efx_attn_info, | ||
626 | .get = snd_emu10k1_efx_attn_get, | ||
627 | .put = snd_emu10k1_efx_attn_put | ||
628 | }; | ||
629 | |||
630 | static int snd_emu10k1_shared_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
631 | { | ||
632 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
633 | uinfo->count = 1; | ||
634 | uinfo->value.integer.min = 0; | ||
635 | uinfo->value.integer.max = 1; | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int snd_emu10k1_shared_spdif_get(snd_kcontrol_t * kcontrol, | ||
640 | snd_ctl_elem_value_t * ucontrol) | ||
641 | { | ||
642 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
643 | |||
644 | if (emu->audigy) | ||
645 | ucontrol->value.integer.value[0] = inl(emu->port + A_IOCFG) & A_IOCFG_GPOUT0 ? 1 : 0; | ||
646 | else | ||
647 | ucontrol->value.integer.value[0] = inl(emu->port + HCFG) & HCFG_GPOUT0 ? 1 : 0; | ||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | static int snd_emu10k1_shared_spdif_put(snd_kcontrol_t * kcontrol, | ||
652 | snd_ctl_elem_value_t * ucontrol) | ||
653 | { | ||
654 | unsigned long flags; | ||
655 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
656 | unsigned int reg, val; | ||
657 | int change = 0; | ||
658 | |||
659 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
660 | if (emu->audigy) { | ||
661 | reg = inl(emu->port + A_IOCFG); | ||
662 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; | ||
663 | change = (reg & A_IOCFG_GPOUT0) != val; | ||
664 | if (change) { | ||
665 | reg &= ~A_IOCFG_GPOUT0; | ||
666 | reg |= val; | ||
667 | outl(reg | val, emu->port + A_IOCFG); | ||
668 | } | ||
669 | } | ||
670 | reg = inl(emu->port + HCFG); | ||
671 | val = ucontrol->value.integer.value[0] ? HCFG_GPOUT0 : 0; | ||
672 | change |= (reg & HCFG_GPOUT0) != val; | ||
673 | if (change) { | ||
674 | reg &= ~HCFG_GPOUT0; | ||
675 | reg |= val; | ||
676 | outl(reg | val, emu->port + HCFG); | ||
677 | } | ||
678 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
679 | return change; | ||
680 | } | ||
681 | |||
682 | static snd_kcontrol_new_t snd_emu10k1_shared_spdif __devinitdata = | ||
683 | { | ||
684 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
685 | .name = "SB Live Analog/Digital Output Jack", | ||
686 | .info = snd_emu10k1_shared_spdif_info, | ||
687 | .get = snd_emu10k1_shared_spdif_get, | ||
688 | .put = snd_emu10k1_shared_spdif_put | ||
689 | }; | ||
690 | |||
691 | static snd_kcontrol_new_t snd_audigy_shared_spdif __devinitdata = | ||
692 | { | ||
693 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
694 | .name = "Audigy Analog/Digital Output Jack", | ||
695 | .info = snd_emu10k1_shared_spdif_info, | ||
696 | .get = snd_emu10k1_shared_spdif_get, | ||
697 | .put = snd_emu10k1_shared_spdif_put | ||
698 | }; | ||
699 | |||
700 | /* | ||
701 | */ | ||
702 | static void snd_emu10k1_mixer_free_ac97(ac97_t *ac97) | ||
703 | { | ||
704 | emu10k1_t *emu = ac97->private_data; | ||
705 | emu->ac97 = NULL; | ||
706 | } | ||
707 | |||
708 | /* | ||
709 | */ | ||
710 | static int remove_ctl(snd_card_t *card, const char *name) | ||
711 | { | ||
712 | snd_ctl_elem_id_t id; | ||
713 | memset(&id, 0, sizeof(id)); | ||
714 | strcpy(id.name, name); | ||
715 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
716 | return snd_ctl_remove_id(card, &id); | ||
717 | } | ||
718 | |||
719 | static snd_kcontrol_t *ctl_find(snd_card_t *card, const char *name) | ||
720 | { | ||
721 | snd_ctl_elem_id_t sid; | ||
722 | memset(&sid, 0, sizeof(sid)); | ||
723 | strcpy(sid.name, name); | ||
724 | sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
725 | return snd_ctl_find_id(card, &sid); | ||
726 | } | ||
727 | |||
728 | static int rename_ctl(snd_card_t *card, const char *src, const char *dst) | ||
729 | { | ||
730 | snd_kcontrol_t *kctl = ctl_find(card, src); | ||
731 | if (kctl) { | ||
732 | strcpy(kctl->id.name, dst); | ||
733 | return 0; | ||
734 | } | ||
735 | return -ENOENT; | ||
736 | } | ||
737 | |||
738 | int __devinit snd_emu10k1_mixer(emu10k1_t *emu) | ||
739 | { | ||
740 | int err, pcm; | ||
741 | snd_kcontrol_t *kctl; | ||
742 | snd_card_t *card = emu->card; | ||
743 | char **c; | ||
744 | static char *emu10k1_remove_ctls[] = { | ||
745 | /* no AC97 mono, surround, center/lfe */ | ||
746 | "Master Mono Playback Switch", | ||
747 | "Master Mono Playback Volume", | ||
748 | "PCM Out Path & Mute", | ||
749 | "Mono Output Select", | ||
750 | "Surround Playback Switch", | ||
751 | "Surround Playback Volume", | ||
752 | "Center Playback Switch", | ||
753 | "Center Playback Volume", | ||
754 | "LFE Playback Switch", | ||
755 | "LFE Playback Volume", | ||
756 | NULL | ||
757 | }; | ||
758 | static char *emu10k1_rename_ctls[] = { | ||
759 | "Surround Digital Playback Volume", "Surround Playback Volume", | ||
760 | "Center Digital Playback Volume", "Center Playback Volume", | ||
761 | "LFE Digital Playback Volume", "LFE Playback Volume", | ||
762 | NULL | ||
763 | }; | ||
764 | static char *audigy_remove_ctls[] = { | ||
765 | /* Master/PCM controls on ac97 of Audigy has no effect */ | ||
766 | "PCM Playback Switch", | ||
767 | "PCM Playback Volume", | ||
768 | "Master Mono Playback Switch", | ||
769 | "Master Mono Playback Volume", | ||
770 | "Master Playback Switch", | ||
771 | "Master Playback Volume", | ||
772 | "PCM Out Path & Mute", | ||
773 | "Mono Output Select", | ||
774 | /* remove unused AC97 capture controls */ | ||
775 | "Capture Source", | ||
776 | "Capture Switch", | ||
777 | "Capture Volume", | ||
778 | "Mic Select", | ||
779 | "Video Playback Switch", | ||
780 | "Video Playback Volume", | ||
781 | "Mic Playback Switch", | ||
782 | "Mic Playback Volume", | ||
783 | NULL | ||
784 | }; | ||
785 | static char *audigy_rename_ctls[] = { | ||
786 | /* use conventional names */ | ||
787 | "Wave Playback Volume", "PCM Playback Volume", | ||
788 | /* "Wave Capture Volume", "PCM Capture Volume", */ | ||
789 | "Wave Master Playback Volume", "Master Playback Volume", | ||
790 | "AMic Playback Volume", "Mic Playback Volume", | ||
791 | NULL | ||
792 | }; | ||
793 | |||
794 | if (!emu->no_ac97) { | ||
795 | ac97_bus_t *pbus; | ||
796 | ac97_template_t ac97; | ||
797 | static ac97_bus_ops_t ops = { | ||
798 | .write = snd_emu10k1_ac97_write, | ||
799 | .read = snd_emu10k1_ac97_read, | ||
800 | }; | ||
801 | |||
802 | if ((err = snd_ac97_bus(emu->card, 0, &ops, NULL, &pbus)) < 0) | ||
803 | return err; | ||
804 | pbus->no_vra = 1; /* we don't need VRA */ | ||
805 | |||
806 | memset(&ac97, 0, sizeof(ac97)); | ||
807 | ac97.private_data = emu; | ||
808 | ac97.private_free = snd_emu10k1_mixer_free_ac97; | ||
809 | ac97.scaps = AC97_SCAP_NO_SPDIF; | ||
810 | if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) | ||
811 | return err; | ||
812 | if (emu->audigy) { | ||
813 | /* set master volume to 0 dB */ | ||
814 | snd_ac97_write(emu->ac97, AC97_MASTER, 0x0000); | ||
815 | /* set capture source to mic */ | ||
816 | snd_ac97_write(emu->ac97, AC97_REC_SEL, 0x0000); | ||
817 | c = audigy_remove_ctls; | ||
818 | } else { | ||
819 | /* | ||
820 | * Credits for cards based on STAC9758: | ||
821 | * James Courtier-Dutton <James@superbug.demon.co.uk> | ||
822 | * Voluspa <voluspa@comhem.se> | ||
823 | */ | ||
824 | if (emu->ac97->id == AC97_ID_STAC9758) { | ||
825 | emu->rear_ac97 = 1; | ||
826 | snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE|AC97SLOT_REAR_LEFT|AC97SLOT_REAR_RIGHT); | ||
827 | } | ||
828 | /* remove unused AC97 controls */ | ||
829 | snd_ac97_write(emu->ac97, AC97_SURROUND_MASTER, 0x0202); | ||
830 | snd_ac97_write(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); | ||
831 | c = emu10k1_remove_ctls; | ||
832 | } | ||
833 | for (; *c; c++) | ||
834 | remove_ctl(card, *c); | ||
835 | } else { | ||
836 | if (emu->APS) | ||
837 | strcpy(emu->card->mixername, "EMU APS"); | ||
838 | else if (emu->audigy) | ||
839 | strcpy(emu->card->mixername, "SB Audigy"); | ||
840 | else | ||
841 | strcpy(emu->card->mixername, "Emu10k1"); | ||
842 | } | ||
843 | |||
844 | if (emu->audigy) | ||
845 | c = audigy_rename_ctls; | ||
846 | else | ||
847 | c = emu10k1_rename_ctls; | ||
848 | for (; *c; c += 2) | ||
849 | rename_ctl(card, c[0], c[1]); | ||
850 | |||
851 | if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) | ||
852 | return -ENOMEM; | ||
853 | if ((err = snd_ctl_add(card, kctl))) | ||
854 | return err; | ||
855 | if ((kctl = emu->ctl_send_volume = snd_ctl_new1(&snd_emu10k1_send_volume_control, emu)) == NULL) | ||
856 | return -ENOMEM; | ||
857 | if ((err = snd_ctl_add(card, kctl))) | ||
858 | return err; | ||
859 | if ((kctl = emu->ctl_attn = snd_ctl_new1(&snd_emu10k1_attn_control, emu)) == NULL) | ||
860 | return -ENOMEM; | ||
861 | if ((err = snd_ctl_add(card, kctl))) | ||
862 | return err; | ||
863 | |||
864 | if ((kctl = emu->ctl_efx_send_routing = snd_ctl_new1(&snd_emu10k1_efx_send_routing_control, emu)) == NULL) | ||
865 | return -ENOMEM; | ||
866 | if ((err = snd_ctl_add(card, kctl))) | ||
867 | return err; | ||
868 | |||
869 | if ((kctl = emu->ctl_efx_send_volume = snd_ctl_new1(&snd_emu10k1_efx_send_volume_control, emu)) == NULL) | ||
870 | return -ENOMEM; | ||
871 | if ((err = snd_ctl_add(card, kctl))) | ||
872 | return err; | ||
873 | |||
874 | if ((kctl = emu->ctl_efx_attn = snd_ctl_new1(&snd_emu10k1_efx_attn_control, emu)) == NULL) | ||
875 | return -ENOMEM; | ||
876 | if ((err = snd_ctl_add(card, kctl))) | ||
877 | return err; | ||
878 | |||
879 | /* initialize the routing and volume table for each pcm playback stream */ | ||
880 | for (pcm = 0; pcm < 32; pcm++) { | ||
881 | emu10k1_pcm_mixer_t *mix; | ||
882 | int v; | ||
883 | |||
884 | mix = &emu->pcm_mixer[pcm]; | ||
885 | mix->epcm = NULL; | ||
886 | |||
887 | for (v = 0; v < 4; v++) | ||
888 | mix->send_routing[0][v] = | ||
889 | mix->send_routing[1][v] = | ||
890 | mix->send_routing[2][v] = v; | ||
891 | |||
892 | memset(&mix->send_volume, 0, sizeof(mix->send_volume)); | ||
893 | mix->send_volume[0][0] = mix->send_volume[0][1] = | ||
894 | mix->send_volume[1][0] = mix->send_volume[2][1] = 255; | ||
895 | |||
896 | mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; | ||
897 | } | ||
898 | |||
899 | /* initialize the routing and volume table for the multichannel playback stream */ | ||
900 | for (pcm = 0; pcm < NUM_EFX_PLAYBACK; pcm++) { | ||
901 | emu10k1_pcm_mixer_t *mix; | ||
902 | int v; | ||
903 | |||
904 | mix = &emu->efx_pcm_mixer[pcm]; | ||
905 | mix->epcm = NULL; | ||
906 | |||
907 | mix->send_routing[0][0] = pcm; | ||
908 | mix->send_routing[0][1] = (pcm == 0) ? 1 : 0; | ||
909 | for (v = 0; v < 2; v++) | ||
910 | mix->send_routing[0][2+v] = 13+v; | ||
911 | if (emu->audigy) | ||
912 | for (v = 0; v < 4; v++) | ||
913 | mix->send_routing[0][4+v] = 60+v; | ||
914 | |||
915 | memset(&mix->send_volume, 0, sizeof(mix->send_volume)); | ||
916 | mix->send_volume[0][0] = 255; | ||
917 | |||
918 | mix->attn[0] = 0xffff; | ||
919 | } | ||
920 | |||
921 | if (! emu->APS) { /* FIXME: APS has these controls? */ | ||
922 | /* sb live! and audigy */ | ||
923 | if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_mask_control, emu)) == NULL) | ||
924 | return -ENOMEM; | ||
925 | if ((err = snd_ctl_add(card, kctl))) | ||
926 | return err; | ||
927 | if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) | ||
928 | return -ENOMEM; | ||
929 | if ((err = snd_ctl_add(card, kctl))) | ||
930 | return err; | ||
931 | } | ||
932 | |||
933 | if (emu->audigy) { | ||
934 | if ((kctl = snd_ctl_new1(&snd_audigy_shared_spdif, emu)) == NULL) | ||
935 | return -ENOMEM; | ||
936 | if ((err = snd_ctl_add(card, kctl))) | ||
937 | return err; | ||
938 | if ((kctl = snd_ctl_new1(&snd_audigy_spdif_output_rate, emu)) == NULL) | ||
939 | return -ENOMEM; | ||
940 | if ((err = snd_ctl_add(card, kctl))) | ||
941 | return err; | ||
942 | } else if (! emu->APS) { | ||
943 | /* sb live! */ | ||
944 | if ((kctl = snd_ctl_new1(&snd_emu10k1_shared_spdif, emu)) == NULL) | ||
945 | return -ENOMEM; | ||
946 | if ((err = snd_ctl_add(card, kctl))) | ||
947 | return err; | ||
948 | } | ||
949 | if (emu->audigy && emu->revision == 4) { /* P16V */ | ||
950 | if ((err = snd_p16v_mixer(emu))) | ||
951 | return err; | ||
952 | } | ||
953 | |||
954 | return 0; | ||
955 | } | ||
diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c new file mode 100644 index 000000000000..eb57458a9665 --- /dev/null +++ b/sound/pci/emu10k1/emumpu401.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Routines for control of EMU10K1 MPU-401 in UART mode | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <linux/time.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <sound/core.h> | ||
26 | #include <sound/emu10k1.h> | ||
27 | |||
28 | #define EMU10K1_MIDI_MODE_INPUT (1<<0) | ||
29 | #define EMU10K1_MIDI_MODE_OUTPUT (1<<1) | ||
30 | |||
31 | static inline unsigned char mpu401_read(emu10k1_t *emu, emu10k1_midi_t *mpu, int idx) | ||
32 | { | ||
33 | if (emu->audigy) | ||
34 | return (unsigned char)snd_emu10k1_ptr_read(emu, mpu->port + idx, 0); | ||
35 | else | ||
36 | return inb(emu->port + mpu->port + idx); | ||
37 | } | ||
38 | |||
39 | static inline void mpu401_write(emu10k1_t *emu, emu10k1_midi_t *mpu, int data, int idx) | ||
40 | { | ||
41 | if (emu->audigy) | ||
42 | snd_emu10k1_ptr_write(emu, mpu->port + idx, 0, data); | ||
43 | else | ||
44 | outb(data, emu->port + mpu->port + idx); | ||
45 | } | ||
46 | |||
47 | #define mpu401_write_data(emu, mpu, data) mpu401_write(emu, mpu, data, 0) | ||
48 | #define mpu401_write_cmd(emu, mpu, data) mpu401_write(emu, mpu, data, 1) | ||
49 | #define mpu401_read_data(emu, mpu) mpu401_read(emu, mpu, 0) | ||
50 | #define mpu401_read_stat(emu, mpu) mpu401_read(emu, mpu, 1) | ||
51 | |||
52 | #define mpu401_input_avail(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x80)) | ||
53 | #define mpu401_output_ready(emu,mpu) (!(mpu401_read_stat(emu,mpu) & 0x40)) | ||
54 | |||
55 | #define MPU401_RESET 0xff | ||
56 | #define MPU401_ENTER_UART 0x3f | ||
57 | #define MPU401_ACK 0xfe | ||
58 | |||
59 | static void mpu401_clear_rx(emu10k1_t *emu, emu10k1_midi_t *mpu) | ||
60 | { | ||
61 | int timeout = 100000; | ||
62 | for (; timeout > 0 && mpu401_input_avail(emu, mpu); timeout--) | ||
63 | mpu401_read_data(emu, mpu); | ||
64 | #ifdef CONFIG_SND_DEBUG | ||
65 | if (timeout <= 0) | ||
66 | snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu)); | ||
67 | #endif | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | |||
72 | */ | ||
73 | |||
74 | static void do_emu10k1_midi_interrupt(emu10k1_t *emu, emu10k1_midi_t *midi, unsigned int status) | ||
75 | { | ||
76 | unsigned char byte; | ||
77 | |||
78 | if (midi->rmidi == NULL) { | ||
79 | snd_emu10k1_intr_disable(emu, midi->tx_enable | midi->rx_enable); | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | spin_lock(&midi->input_lock); | ||
84 | if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) { | ||
85 | if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { | ||
86 | mpu401_clear_rx(emu, midi); | ||
87 | } else { | ||
88 | byte = mpu401_read_data(emu, midi); | ||
89 | if (midi->substream_input) | ||
90 | snd_rawmidi_receive(midi->substream_input, &byte, 1); | ||
91 | } | ||
92 | } | ||
93 | spin_unlock(&midi->input_lock); | ||
94 | |||
95 | spin_lock(&midi->output_lock); | ||
96 | if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) { | ||
97 | if (midi->substream_output && | ||
98 | snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) { | ||
99 | mpu401_write_data(emu, midi, byte); | ||
100 | } else { | ||
101 | snd_emu10k1_intr_disable(emu, midi->tx_enable); | ||
102 | } | ||
103 | } | ||
104 | spin_unlock(&midi->output_lock); | ||
105 | } | ||
106 | |||
107 | static void snd_emu10k1_midi_interrupt(emu10k1_t *emu, unsigned int status) | ||
108 | { | ||
109 | do_emu10k1_midi_interrupt(emu, &emu->midi, status); | ||
110 | } | ||
111 | |||
112 | static void snd_emu10k1_midi_interrupt2(emu10k1_t *emu, unsigned int status) | ||
113 | { | ||
114 | do_emu10k1_midi_interrupt(emu, &emu->midi2, status); | ||
115 | } | ||
116 | |||
117 | static void snd_emu10k1_midi_cmd(emu10k1_t * emu, emu10k1_midi_t *midi, unsigned char cmd, int ack) | ||
118 | { | ||
119 | unsigned long flags; | ||
120 | int timeout, ok; | ||
121 | |||
122 | spin_lock_irqsave(&midi->input_lock, flags); | ||
123 | mpu401_write_data(emu, midi, 0x00); | ||
124 | /* mpu401_clear_rx(emu, midi); */ | ||
125 | |||
126 | mpu401_write_cmd(emu, midi, cmd); | ||
127 | if (ack) { | ||
128 | ok = 0; | ||
129 | timeout = 10000; | ||
130 | while (!ok && timeout-- > 0) { | ||
131 | if (mpu401_input_avail(emu, midi)) { | ||
132 | if (mpu401_read_data(emu, midi) == MPU401_ACK) | ||
133 | ok = 1; | ||
134 | } | ||
135 | } | ||
136 | if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK) | ||
137 | ok = 1; | ||
138 | } else { | ||
139 | ok = 1; | ||
140 | } | ||
141 | spin_unlock_irqrestore(&midi->input_lock, flags); | ||
142 | if (!ok) | ||
143 | snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", | ||
144 | cmd, emu->port, | ||
145 | mpu401_read_stat(emu, midi), | ||
146 | mpu401_read_data(emu, midi)); | ||
147 | } | ||
148 | |||
149 | static int snd_emu10k1_midi_input_open(snd_rawmidi_substream_t * substream) | ||
150 | { | ||
151 | emu10k1_t *emu; | ||
152 | emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; | ||
153 | unsigned long flags; | ||
154 | |||
155 | emu = midi->emu; | ||
156 | snd_assert(emu, return -ENXIO); | ||
157 | spin_lock_irqsave(&midi->open_lock, flags); | ||
158 | midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT; | ||
159 | midi->substream_input = substream; | ||
160 | if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { | ||
161 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
162 | snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1); | ||
163 | snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1); | ||
164 | } else { | ||
165 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
166 | } | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int snd_emu10k1_midi_output_open(snd_rawmidi_substream_t * substream) | ||
171 | { | ||
172 | emu10k1_t *emu; | ||
173 | emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; | ||
174 | unsigned long flags; | ||
175 | |||
176 | emu = midi->emu; | ||
177 | snd_assert(emu, return -ENXIO); | ||
178 | spin_lock_irqsave(&midi->open_lock, flags); | ||
179 | midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT; | ||
180 | midi->substream_output = substream; | ||
181 | if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { | ||
182 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
183 | snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1); | ||
184 | snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1); | ||
185 | } else { | ||
186 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
187 | } | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int snd_emu10k1_midi_input_close(snd_rawmidi_substream_t * substream) | ||
192 | { | ||
193 | emu10k1_t *emu; | ||
194 | emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; | ||
195 | unsigned long flags; | ||
196 | |||
197 | emu = midi->emu; | ||
198 | snd_assert(emu, return -ENXIO); | ||
199 | spin_lock_irqsave(&midi->open_lock, flags); | ||
200 | snd_emu10k1_intr_disable(emu, midi->rx_enable); | ||
201 | midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT; | ||
202 | midi->substream_input = NULL; | ||
203 | if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) { | ||
204 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
205 | snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); | ||
206 | } else { | ||
207 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
208 | } | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int snd_emu10k1_midi_output_close(snd_rawmidi_substream_t * substream) | ||
213 | { | ||
214 | emu10k1_t *emu; | ||
215 | emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; | ||
216 | unsigned long flags; | ||
217 | |||
218 | emu = midi->emu; | ||
219 | snd_assert(emu, return -ENXIO); | ||
220 | spin_lock_irqsave(&midi->open_lock, flags); | ||
221 | snd_emu10k1_intr_disable(emu, midi->tx_enable); | ||
222 | midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT; | ||
223 | midi->substream_output = NULL; | ||
224 | if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) { | ||
225 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
226 | snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0); | ||
227 | } else { | ||
228 | spin_unlock_irqrestore(&midi->open_lock, flags); | ||
229 | } | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static void snd_emu10k1_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) | ||
234 | { | ||
235 | emu10k1_t *emu; | ||
236 | emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; | ||
237 | emu = midi->emu; | ||
238 | snd_assert(emu, return); | ||
239 | |||
240 | if (up) | ||
241 | snd_emu10k1_intr_enable(emu, midi->rx_enable); | ||
242 | else | ||
243 | snd_emu10k1_intr_disable(emu, midi->rx_enable); | ||
244 | } | ||
245 | |||
246 | static void snd_emu10k1_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) | ||
247 | { | ||
248 | emu10k1_t *emu; | ||
249 | emu10k1_midi_t *midi = (emu10k1_midi_t *)substream->rmidi->private_data; | ||
250 | unsigned long flags; | ||
251 | |||
252 | emu = midi->emu; | ||
253 | snd_assert(emu, return); | ||
254 | |||
255 | if (up) { | ||
256 | int max = 4; | ||
257 | unsigned char byte; | ||
258 | |||
259 | /* try to send some amount of bytes here before interrupts */ | ||
260 | spin_lock_irqsave(&midi->output_lock, flags); | ||
261 | while (max > 0) { | ||
262 | if (mpu401_output_ready(emu, midi)) { | ||
263 | if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) || | ||
264 | snd_rawmidi_transmit(substream, &byte, 1) != 1) { | ||
265 | /* no more data */ | ||
266 | spin_unlock_irqrestore(&midi->output_lock, flags); | ||
267 | return; | ||
268 | } | ||
269 | mpu401_write_data(emu, midi, byte); | ||
270 | max--; | ||
271 | } else { | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | spin_unlock_irqrestore(&midi->output_lock, flags); | ||
276 | snd_emu10k1_intr_enable(emu, midi->tx_enable); | ||
277 | } else { | ||
278 | snd_emu10k1_intr_disable(emu, midi->tx_enable); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | |||
284 | */ | ||
285 | |||
286 | static snd_rawmidi_ops_t snd_emu10k1_midi_output = | ||
287 | { | ||
288 | .open = snd_emu10k1_midi_output_open, | ||
289 | .close = snd_emu10k1_midi_output_close, | ||
290 | .trigger = snd_emu10k1_midi_output_trigger, | ||
291 | }; | ||
292 | |||
293 | static snd_rawmidi_ops_t snd_emu10k1_midi_input = | ||
294 | { | ||
295 | .open = snd_emu10k1_midi_input_open, | ||
296 | .close = snd_emu10k1_midi_input_close, | ||
297 | .trigger = snd_emu10k1_midi_input_trigger, | ||
298 | }; | ||
299 | |||
300 | static void snd_emu10k1_midi_free(snd_rawmidi_t *rmidi) | ||
301 | { | ||
302 | emu10k1_midi_t *midi = (emu10k1_midi_t *)rmidi->private_data; | ||
303 | midi->interrupt = NULL; | ||
304 | midi->rmidi = NULL; | ||
305 | } | ||
306 | |||
307 | static int __devinit emu10k1_midi_init(emu10k1_t *emu, emu10k1_midi_t *midi, int device, char *name) | ||
308 | { | ||
309 | snd_rawmidi_t *rmidi; | ||
310 | int err; | ||
311 | |||
312 | if ((err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi)) < 0) | ||
313 | return err; | ||
314 | midi->emu = emu; | ||
315 | spin_lock_init(&midi->open_lock); | ||
316 | spin_lock_init(&midi->input_lock); | ||
317 | spin_lock_init(&midi->output_lock); | ||
318 | strcpy(rmidi->name, name); | ||
319 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output); | ||
320 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input); | ||
321 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | | ||
322 | SNDRV_RAWMIDI_INFO_INPUT | | ||
323 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
324 | rmidi->private_data = midi; | ||
325 | rmidi->private_free = snd_emu10k1_midi_free; | ||
326 | midi->rmidi = rmidi; | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | int __devinit snd_emu10k1_midi(emu10k1_t *emu) | ||
331 | { | ||
332 | emu10k1_midi_t *midi = &emu->midi; | ||
333 | int err; | ||
334 | |||
335 | if ((err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)")) < 0) | ||
336 | return err; | ||
337 | |||
338 | midi->tx_enable = INTE_MIDITXENABLE; | ||
339 | midi->rx_enable = INTE_MIDIRXENABLE; | ||
340 | midi->port = MUDATA; | ||
341 | midi->ipr_tx = IPR_MIDITRANSBUFEMPTY; | ||
342 | midi->ipr_rx = IPR_MIDIRECVBUFEMPTY; | ||
343 | midi->interrupt = snd_emu10k1_midi_interrupt; | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | int __devinit snd_emu10k1_audigy_midi(emu10k1_t *emu) | ||
348 | { | ||
349 | emu10k1_midi_t *midi; | ||
350 | int err; | ||
351 | |||
352 | midi = &emu->midi; | ||
353 | if ((err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)")) < 0) | ||
354 | return err; | ||
355 | |||
356 | midi->tx_enable = INTE_MIDITXENABLE; | ||
357 | midi->rx_enable = INTE_MIDIRXENABLE; | ||
358 | midi->port = A_MUDATA1; | ||
359 | midi->ipr_tx = IPR_MIDITRANSBUFEMPTY; | ||
360 | midi->ipr_rx = IPR_MIDIRECVBUFEMPTY; | ||
361 | midi->interrupt = snd_emu10k1_midi_interrupt; | ||
362 | |||
363 | midi = &emu->midi2; | ||
364 | if ((err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2")) < 0) | ||
365 | return err; | ||
366 | |||
367 | midi->tx_enable = INTE_A_MIDITXENABLE2; | ||
368 | midi->rx_enable = INTE_A_MIDIRXENABLE2; | ||
369 | midi->port = A_MUDATA2; | ||
370 | midi->ipr_tx = IPR_A_MIDITRANSBUFEMPTY2; | ||
371 | midi->ipr_rx = IPR_A_MIDIRECVBUFEMPTY2; | ||
372 | midi->interrupt = snd_emu10k1_midi_interrupt2; | ||
373 | return 0; | ||
374 | } | ||
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c new file mode 100644 index 000000000000..d1c2a02c486b --- /dev/null +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -0,0 +1,1724 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Creative Labs, Inc. | ||
4 | * Routines for control of EMU10K1 chips / PCM routines | ||
5 | * Multichannel PCM support Copyright (c) Lee Revell <rlrevell@joe-job.com> | ||
6 | * | ||
7 | * BUGS: | ||
8 | * -- | ||
9 | * | ||
10 | * TODO: | ||
11 | * -- | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <sound/driver.h> | ||
30 | #include <linux/pci.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/time.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <sound/core.h> | ||
36 | #include <sound/emu10k1.h> | ||
37 | |||
38 | static void snd_emu10k1_pcm_interrupt(emu10k1_t *emu, emu10k1_voice_t *voice) | ||
39 | { | ||
40 | emu10k1_pcm_t *epcm; | ||
41 | |||
42 | if ((epcm = voice->epcm) == NULL) | ||
43 | return; | ||
44 | if (epcm->substream == NULL) | ||
45 | return; | ||
46 | #if 0 | ||
47 | printk("IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n", | ||
48 | epcm->substream->runtime->hw->pointer(emu, epcm->substream), | ||
49 | snd_pcm_lib_period_bytes(epcm->substream), | ||
50 | snd_pcm_lib_buffer_bytes(epcm->substream)); | ||
51 | #endif | ||
52 | snd_pcm_period_elapsed(epcm->substream); | ||
53 | } | ||
54 | |||
55 | static void snd_emu10k1_pcm_ac97adc_interrupt(emu10k1_t *emu, unsigned int status) | ||
56 | { | ||
57 | #if 0 | ||
58 | if (status & IPR_ADCBUFHALFFULL) { | ||
59 | if (emu->pcm_capture_substream->runtime->mode == SNDRV_PCM_MODE_FRAME) | ||
60 | return; | ||
61 | } | ||
62 | #endif | ||
63 | snd_pcm_period_elapsed(emu->pcm_capture_substream); | ||
64 | } | ||
65 | |||
66 | static void snd_emu10k1_pcm_ac97mic_interrupt(emu10k1_t *emu, unsigned int status) | ||
67 | { | ||
68 | #if 0 | ||
69 | if (status & IPR_MICBUFHALFFULL) { | ||
70 | if (emu->pcm_capture_mic_substream->runtime->mode == SNDRV_PCM_MODE_FRAME) | ||
71 | return; | ||
72 | } | ||
73 | #endif | ||
74 | snd_pcm_period_elapsed(emu->pcm_capture_mic_substream); | ||
75 | } | ||
76 | |||
77 | static void snd_emu10k1_pcm_efx_interrupt(emu10k1_t *emu, unsigned int status) | ||
78 | { | ||
79 | #if 0 | ||
80 | if (status & IPR_EFXBUFHALFFULL) { | ||
81 | if (emu->pcm_capture_efx_substream->runtime->mode == SNDRV_PCM_MODE_FRAME) | ||
82 | return; | ||
83 | } | ||
84 | #endif | ||
85 | snd_pcm_period_elapsed(emu->pcm_capture_efx_substream); | ||
86 | } | ||
87 | |||
88 | static snd_pcm_uframes_t snd_emu10k1_efx_playback_pointer(snd_pcm_substream_t * substream) | ||
89 | { | ||
90 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
91 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
92 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
93 | unsigned int ptr; | ||
94 | |||
95 | if (!epcm->running) | ||
96 | return 0; | ||
97 | ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff; | ||
98 | ptr += runtime->buffer_size; | ||
99 | ptr -= epcm->ccca_start_addr; | ||
100 | ptr %= runtime->buffer_size; | ||
101 | |||
102 | return ptr; | ||
103 | } | ||
104 | |||
105 | static int snd_emu10k1_pcm_channel_alloc(emu10k1_pcm_t * epcm, int voices) | ||
106 | { | ||
107 | int err, i; | ||
108 | |||
109 | if (epcm->voices[1] != NULL && voices < 2) { | ||
110 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]); | ||
111 | epcm->voices[1] = NULL; | ||
112 | } | ||
113 | for (i = 0; i < voices; i++) { | ||
114 | if (epcm->voices[i] == NULL) | ||
115 | break; | ||
116 | } | ||
117 | if (i == voices) | ||
118 | return 0; /* already allocated */ | ||
119 | |||
120 | for (i = 0; i < ARRAY_SIZE(epcm->voices); i++) { | ||
121 | if (epcm->voices[i]) { | ||
122 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); | ||
123 | epcm->voices[i] = NULL; | ||
124 | } | ||
125 | } | ||
126 | err = snd_emu10k1_voice_alloc(epcm->emu, | ||
127 | epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX, | ||
128 | voices, | ||
129 | &epcm->voices[0]); | ||
130 | |||
131 | if (err < 0) | ||
132 | return err; | ||
133 | epcm->voices[0]->epcm = epcm; | ||
134 | if (voices > 1) { | ||
135 | for (i = 1; i < voices; i++) { | ||
136 | epcm->voices[i] = &epcm->emu->voices[epcm->voices[0]->number + i]; | ||
137 | epcm->voices[i]->epcm = epcm; | ||
138 | } | ||
139 | } | ||
140 | if (epcm->extra == NULL) { | ||
141 | err = snd_emu10k1_voice_alloc(epcm->emu, | ||
142 | epcm->type == PLAYBACK_EMUVOICE ? EMU10K1_PCM : EMU10K1_EFX, | ||
143 | 1, | ||
144 | &epcm->extra); | ||
145 | if (err < 0) { | ||
146 | // printk("pcm_channel_alloc: failed extra: voices=%d, frame=%d\n", voices, frame); | ||
147 | for (i = 0; i < voices; i++) { | ||
148 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); | ||
149 | epcm->voices[i] = NULL; | ||
150 | } | ||
151 | return err; | ||
152 | } | ||
153 | epcm->extra->epcm = epcm; | ||
154 | epcm->extra->interrupt = snd_emu10k1_pcm_interrupt; | ||
155 | } | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static unsigned int capture_period_sizes[31] = { | ||
160 | 384, 448, 512, 640, | ||
161 | 384*2, 448*2, 512*2, 640*2, | ||
162 | 384*4, 448*4, 512*4, 640*4, | ||
163 | 384*8, 448*8, 512*8, 640*8, | ||
164 | 384*16, 448*16, 512*16, 640*16, | ||
165 | 384*32, 448*32, 512*32, 640*32, | ||
166 | 384*64, 448*64, 512*64, 640*64, | ||
167 | 384*128,448*128,512*128 | ||
168 | }; | ||
169 | |||
170 | static snd_pcm_hw_constraint_list_t hw_constraints_capture_period_sizes = { | ||
171 | .count = 31, | ||
172 | .list = capture_period_sizes, | ||
173 | .mask = 0 | ||
174 | }; | ||
175 | |||
176 | static unsigned int capture_rates[8] = { | ||
177 | 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 | ||
178 | }; | ||
179 | |||
180 | static snd_pcm_hw_constraint_list_t hw_constraints_capture_rates = { | ||
181 | .count = 8, | ||
182 | .list = capture_rates, | ||
183 | .mask = 0 | ||
184 | }; | ||
185 | |||
186 | static unsigned int snd_emu10k1_capture_rate_reg(unsigned int rate) | ||
187 | { | ||
188 | switch (rate) { | ||
189 | case 8000: return ADCCR_SAMPLERATE_8; | ||
190 | case 11025: return ADCCR_SAMPLERATE_11; | ||
191 | case 16000: return ADCCR_SAMPLERATE_16; | ||
192 | case 22050: return ADCCR_SAMPLERATE_22; | ||
193 | case 24000: return ADCCR_SAMPLERATE_24; | ||
194 | case 32000: return ADCCR_SAMPLERATE_32; | ||
195 | case 44100: return ADCCR_SAMPLERATE_44; | ||
196 | case 48000: return ADCCR_SAMPLERATE_48; | ||
197 | default: | ||
198 | snd_BUG(); | ||
199 | return ADCCR_SAMPLERATE_8; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static unsigned int snd_emu10k1_audigy_capture_rate_reg(unsigned int rate) | ||
204 | { | ||
205 | switch (rate) { | ||
206 | case 8000: return A_ADCCR_SAMPLERATE_8; | ||
207 | case 11025: return A_ADCCR_SAMPLERATE_11; | ||
208 | case 12000: return A_ADCCR_SAMPLERATE_12; /* really supported? */ | ||
209 | case 16000: return ADCCR_SAMPLERATE_16; | ||
210 | case 22050: return ADCCR_SAMPLERATE_22; | ||
211 | case 24000: return ADCCR_SAMPLERATE_24; | ||
212 | case 32000: return ADCCR_SAMPLERATE_32; | ||
213 | case 44100: return ADCCR_SAMPLERATE_44; | ||
214 | case 48000: return ADCCR_SAMPLERATE_48; | ||
215 | default: | ||
216 | snd_BUG(); | ||
217 | return A_ADCCR_SAMPLERATE_8; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | static unsigned int emu10k1_calc_pitch_target(unsigned int rate) | ||
222 | { | ||
223 | unsigned int pitch_target; | ||
224 | |||
225 | pitch_target = (rate << 8) / 375; | ||
226 | pitch_target = (pitch_target >> 1) + (pitch_target & 1); | ||
227 | return pitch_target; | ||
228 | } | ||
229 | |||
230 | #define PITCH_48000 0x00004000 | ||
231 | #define PITCH_96000 0x00008000 | ||
232 | #define PITCH_85000 0x00007155 | ||
233 | #define PITCH_80726 0x00006ba2 | ||
234 | #define PITCH_67882 0x00005a82 | ||
235 | #define PITCH_57081 0x00004c1c | ||
236 | |||
237 | static unsigned int emu10k1_select_interprom(unsigned int pitch_target) | ||
238 | { | ||
239 | if (pitch_target == PITCH_48000) | ||
240 | return CCCA_INTERPROM_0; | ||
241 | else if (pitch_target < PITCH_48000) | ||
242 | return CCCA_INTERPROM_1; | ||
243 | else if (pitch_target >= PITCH_96000) | ||
244 | return CCCA_INTERPROM_0; | ||
245 | else if (pitch_target >= PITCH_85000) | ||
246 | return CCCA_INTERPROM_6; | ||
247 | else if (pitch_target >= PITCH_80726) | ||
248 | return CCCA_INTERPROM_5; | ||
249 | else if (pitch_target >= PITCH_67882) | ||
250 | return CCCA_INTERPROM_4; | ||
251 | else if (pitch_target >= PITCH_57081) | ||
252 | return CCCA_INTERPROM_3; | ||
253 | else | ||
254 | return CCCA_INTERPROM_2; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * calculate cache invalidate size | ||
259 | * | ||
260 | * stereo: channel is stereo | ||
261 | * w_16: using 16bit samples | ||
262 | * | ||
263 | * returns: cache invalidate size in samples | ||
264 | */ | ||
265 | static int inline emu10k1_ccis(int stereo, int w_16) | ||
266 | { | ||
267 | if (w_16) { | ||
268 | return stereo ? 24 : 26; | ||
269 | } else { | ||
270 | return stereo ? 24*2 : 26*2; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | static void snd_emu10k1_pcm_init_voice(emu10k1_t *emu, | ||
275 | int master, int extra, | ||
276 | emu10k1_voice_t *evoice, | ||
277 | unsigned int start_addr, | ||
278 | unsigned int end_addr, | ||
279 | emu10k1_pcm_mixer_t *mix) | ||
280 | { | ||
281 | snd_pcm_substream_t *substream = evoice->epcm->substream; | ||
282 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
283 | unsigned int silent_page, tmp; | ||
284 | int voice, stereo, w_16; | ||
285 | unsigned char attn, send_amount[8]; | ||
286 | unsigned char send_routing[8]; | ||
287 | unsigned long flags; | ||
288 | unsigned int pitch_target; | ||
289 | unsigned int ccis; | ||
290 | |||
291 | voice = evoice->number; | ||
292 | stereo = runtime->channels == 2; | ||
293 | w_16 = snd_pcm_format_width(runtime->format) == 16; | ||
294 | |||
295 | if (!extra && stereo) { | ||
296 | start_addr >>= 1; | ||
297 | end_addr >>= 1; | ||
298 | } | ||
299 | if (w_16) { | ||
300 | start_addr >>= 1; | ||
301 | end_addr >>= 1; | ||
302 | } | ||
303 | |||
304 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
305 | |||
306 | /* volume parameters */ | ||
307 | if (extra) { | ||
308 | attn = 0; | ||
309 | memset(send_routing, 0, sizeof(send_routing)); | ||
310 | send_routing[0] = 0; | ||
311 | send_routing[1] = 1; | ||
312 | send_routing[2] = 2; | ||
313 | send_routing[3] = 3; | ||
314 | memset(send_amount, 0, sizeof(send_amount)); | ||
315 | } else { | ||
316 | /* mono, left, right (master voice = left) */ | ||
317 | tmp = stereo ? (master ? 1 : 2) : 0; | ||
318 | memcpy(send_routing, &mix->send_routing[tmp][0], 8); | ||
319 | memcpy(send_amount, &mix->send_volume[tmp][0], 8); | ||
320 | } | ||
321 | |||
322 | ccis = emu10k1_ccis(stereo, w_16); | ||
323 | |||
324 | if (master) { | ||
325 | evoice->epcm->ccca_start_addr = start_addr + ccis; | ||
326 | if (extra) { | ||
327 | start_addr += ccis; | ||
328 | end_addr += ccis; | ||
329 | } | ||
330 | if (stereo && !extra) { | ||
331 | snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK); | ||
332 | snd_emu10k1_ptr_write(emu, CPF, (voice + 1), CPF_STEREO_MASK); | ||
333 | } else { | ||
334 | snd_emu10k1_ptr_write(emu, CPF, voice, 0); | ||
335 | } | ||
336 | } | ||
337 | |||
338 | // setup routing | ||
339 | if (emu->audigy) { | ||
340 | snd_emu10k1_ptr_write(emu, A_FXRT1, voice, | ||
341 | snd_emu10k1_compose_audigy_fxrt1(send_routing)); | ||
342 | snd_emu10k1_ptr_write(emu, A_FXRT2, voice, | ||
343 | snd_emu10k1_compose_audigy_fxrt2(send_routing)); | ||
344 | snd_emu10k1_ptr_write(emu, A_SENDAMOUNTS, voice, | ||
345 | ((unsigned int)send_amount[4] << 24) | | ||
346 | ((unsigned int)send_amount[5] << 16) | | ||
347 | ((unsigned int)send_amount[6] << 8) | | ||
348 | (unsigned int)send_amount[7]); | ||
349 | } else | ||
350 | snd_emu10k1_ptr_write(emu, FXRT, voice, | ||
351 | snd_emu10k1_compose_send_routing(send_routing)); | ||
352 | // Stop CA | ||
353 | // Assumption that PT is already 0 so no harm overwriting | ||
354 | snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]); | ||
355 | snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24)); | ||
356 | snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24)); | ||
357 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | ||
358 | if (extra) | ||
359 | snd_emu10k1_ptr_write(emu, CCCA, voice, start_addr | | ||
360 | emu10k1_select_interprom(pitch_target) | | ||
361 | (w_16 ? 0 : CCCA_8BITSELECT)); | ||
362 | else | ||
363 | snd_emu10k1_ptr_write(emu, CCCA, voice, (start_addr + ccis) | | ||
364 | emu10k1_select_interprom(pitch_target) | | ||
365 | (w_16 ? 0 : CCCA_8BITSELECT)); | ||
366 | // Clear filter delay memory | ||
367 | snd_emu10k1_ptr_write(emu, Z1, voice, 0); | ||
368 | snd_emu10k1_ptr_write(emu, Z2, voice, 0); | ||
369 | // invalidate maps | ||
370 | silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; | ||
371 | snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); | ||
372 | snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); | ||
373 | // modulation envelope | ||
374 | snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); | ||
375 | snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); | ||
376 | snd_emu10k1_ptr_write(emu, ATKHLDM, voice, 0); | ||
377 | snd_emu10k1_ptr_write(emu, DCYSUSM, voice, 0x007f); | ||
378 | snd_emu10k1_ptr_write(emu, LFOVAL1, voice, 0x8000); | ||
379 | snd_emu10k1_ptr_write(emu, LFOVAL2, voice, 0x8000); | ||
380 | snd_emu10k1_ptr_write(emu, FMMOD, voice, 0); | ||
381 | snd_emu10k1_ptr_write(emu, TREMFRQ, voice, 0); | ||
382 | snd_emu10k1_ptr_write(emu, FM2FRQ2, voice, 0); | ||
383 | snd_emu10k1_ptr_write(emu, ENVVAL, voice, 0x8000); | ||
384 | // volume envelope | ||
385 | snd_emu10k1_ptr_write(emu, ATKHLDV, voice, 0x7f7f); | ||
386 | snd_emu10k1_ptr_write(emu, ENVVOL, voice, 0x0000); | ||
387 | // filter envelope | ||
388 | snd_emu10k1_ptr_write(emu, PEFE_FILTERAMOUNT, voice, 0x7f); | ||
389 | // pitch envelope | ||
390 | snd_emu10k1_ptr_write(emu, PEFE_PITCHAMOUNT, voice, 0); | ||
391 | |||
392 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
393 | } | ||
394 | |||
395 | static int snd_emu10k1_playback_hw_params(snd_pcm_substream_t * substream, | ||
396 | snd_pcm_hw_params_t * hw_params) | ||
397 | { | ||
398 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
399 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
400 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
401 | int err; | ||
402 | |||
403 | if ((err = snd_emu10k1_pcm_channel_alloc(epcm, params_channels(hw_params))) < 0) | ||
404 | return err; | ||
405 | if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) | ||
406 | return err; | ||
407 | if (err > 0) { /* change */ | ||
408 | snd_util_memblk_t *memblk; | ||
409 | if (epcm->memblk != NULL) | ||
410 | snd_emu10k1_free_pages(emu, epcm->memblk); | ||
411 | memblk = snd_emu10k1_alloc_pages(emu, substream); | ||
412 | if ((epcm->memblk = memblk) == NULL || ((emu10k1_memblk_t *)memblk)->mapped_page < 0) { | ||
413 | epcm->start_addr = 0; | ||
414 | return -ENOMEM; | ||
415 | } | ||
416 | epcm->start_addr = ((emu10k1_memblk_t *)memblk)->mapped_page << PAGE_SHIFT; | ||
417 | } | ||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int snd_emu10k1_playback_hw_free(snd_pcm_substream_t * substream) | ||
422 | { | ||
423 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
424 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
425 | emu10k1_pcm_t *epcm; | ||
426 | |||
427 | if (runtime->private_data == NULL) | ||
428 | return 0; | ||
429 | epcm = runtime->private_data; | ||
430 | if (epcm->extra) { | ||
431 | snd_emu10k1_voice_free(epcm->emu, epcm->extra); | ||
432 | epcm->extra = NULL; | ||
433 | } | ||
434 | if (epcm->voices[1]) { | ||
435 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[1]); | ||
436 | epcm->voices[1] = NULL; | ||
437 | } | ||
438 | if (epcm->voices[0]) { | ||
439 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[0]); | ||
440 | epcm->voices[0] = NULL; | ||
441 | } | ||
442 | if (epcm->memblk) { | ||
443 | snd_emu10k1_free_pages(emu, epcm->memblk); | ||
444 | epcm->memblk = NULL; | ||
445 | epcm->start_addr = 0; | ||
446 | } | ||
447 | snd_pcm_lib_free_pages(substream); | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static int snd_emu10k1_efx_playback_hw_free(snd_pcm_substream_t * substream) | ||
452 | { | ||
453 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
454 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
455 | emu10k1_pcm_t *epcm; | ||
456 | int i; | ||
457 | |||
458 | if (runtime->private_data == NULL) | ||
459 | return 0; | ||
460 | epcm = runtime->private_data; | ||
461 | if (epcm->extra) { | ||
462 | snd_emu10k1_voice_free(epcm->emu, epcm->extra); | ||
463 | epcm->extra = NULL; | ||
464 | } | ||
465 | for (i=0; i < NUM_EFX_PLAYBACK; i++) { | ||
466 | if (epcm->voices[i]) { | ||
467 | snd_emu10k1_voice_free(epcm->emu, epcm->voices[i]); | ||
468 | epcm->voices[i] = NULL; | ||
469 | } | ||
470 | } | ||
471 | if (epcm->memblk) { | ||
472 | snd_emu10k1_free_pages(emu, epcm->memblk); | ||
473 | epcm->memblk = NULL; | ||
474 | epcm->start_addr = 0; | ||
475 | } | ||
476 | snd_pcm_lib_free_pages(substream); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | static int snd_emu10k1_playback_prepare(snd_pcm_substream_t * substream) | ||
481 | { | ||
482 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
483 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
484 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
485 | unsigned int start_addr, end_addr; | ||
486 | |||
487 | start_addr = epcm->start_addr; | ||
488 | end_addr = snd_pcm_lib_period_bytes(substream); | ||
489 | if (runtime->channels == 2) { | ||
490 | start_addr >>= 1; | ||
491 | end_addr >>= 1; | ||
492 | } | ||
493 | end_addr += start_addr; | ||
494 | snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra, | ||
495 | start_addr, end_addr, NULL); | ||
496 | start_addr = epcm->start_addr; | ||
497 | end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream); | ||
498 | snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0], | ||
499 | start_addr, end_addr, | ||
500 | &emu->pcm_mixer[substream->number]); | ||
501 | if (epcm->voices[1]) | ||
502 | snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[1], | ||
503 | start_addr, end_addr, | ||
504 | &emu->pcm_mixer[substream->number]); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static int snd_emu10k1_efx_playback_prepare(snd_pcm_substream_t * substream) | ||
509 | { | ||
510 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
511 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
512 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
513 | unsigned int start_addr, end_addr; | ||
514 | unsigned int channel_size; | ||
515 | int i; | ||
516 | |||
517 | start_addr = epcm->start_addr; | ||
518 | end_addr = epcm->start_addr + snd_pcm_lib_buffer_bytes(substream); | ||
519 | |||
520 | /* | ||
521 | * the kX driver leaves some space between voices | ||
522 | */ | ||
523 | channel_size = ( end_addr - start_addr ) / NUM_EFX_PLAYBACK; | ||
524 | |||
525 | snd_emu10k1_pcm_init_voice(emu, 1, 1, epcm->extra, | ||
526 | start_addr, start_addr + (channel_size / 2), NULL); | ||
527 | |||
528 | /* only difference with the master voice is we use it for the pointer */ | ||
529 | snd_emu10k1_pcm_init_voice(emu, 1, 0, epcm->voices[0], | ||
530 | start_addr, start_addr + channel_size, | ||
531 | &emu->efx_pcm_mixer[0]); | ||
532 | |||
533 | start_addr += channel_size; | ||
534 | for (i = 1; i < NUM_EFX_PLAYBACK; i++) { | ||
535 | snd_emu10k1_pcm_init_voice(emu, 0, 0, epcm->voices[i], | ||
536 | start_addr, start_addr + channel_size, | ||
537 | &emu->efx_pcm_mixer[i]); | ||
538 | start_addr += channel_size; | ||
539 | } | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static snd_pcm_hardware_t snd_emu10k1_efx_playback = | ||
545 | { | ||
546 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_NONINTERLEAVED | | ||
547 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
548 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), | ||
549 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
550 | .rates = SNDRV_PCM_RATE_48000, | ||
551 | .rate_min = 48000, | ||
552 | .rate_max = 48000, | ||
553 | .channels_min = NUM_EFX_PLAYBACK, | ||
554 | .channels_max = NUM_EFX_PLAYBACK, | ||
555 | .buffer_bytes_max = (64*1024), | ||
556 | .period_bytes_min = 64, | ||
557 | .period_bytes_max = (64*1024), | ||
558 | .periods_min = 2, | ||
559 | .periods_max = 2, | ||
560 | .fifo_size = 0, | ||
561 | }; | ||
562 | |||
563 | static int snd_emu10k1_capture_hw_params(snd_pcm_substream_t * substream, | ||
564 | snd_pcm_hw_params_t * hw_params) | ||
565 | { | ||
566 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | ||
567 | } | ||
568 | |||
569 | static int snd_emu10k1_capture_hw_free(snd_pcm_substream_t * substream) | ||
570 | { | ||
571 | return snd_pcm_lib_free_pages(substream); | ||
572 | } | ||
573 | |||
574 | static int snd_emu10k1_capture_prepare(snd_pcm_substream_t * substream) | ||
575 | { | ||
576 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
577 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
578 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
579 | int idx; | ||
580 | |||
581 | /* zeroing the buffer size will stop capture */ | ||
582 | snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0); | ||
583 | switch (epcm->type) { | ||
584 | case CAPTURE_AC97ADC: | ||
585 | snd_emu10k1_ptr_write(emu, ADCCR, 0, 0); | ||
586 | break; | ||
587 | case CAPTURE_EFX: | ||
588 | if (emu->audigy) { | ||
589 | snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0); | ||
590 | snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0); | ||
591 | } else | ||
592 | snd_emu10k1_ptr_write(emu, FXWC, 0, 0); | ||
593 | break; | ||
594 | default: | ||
595 | break; | ||
596 | } | ||
597 | snd_emu10k1_ptr_write(emu, epcm->capture_ba_reg, 0, runtime->dma_addr); | ||
598 | epcm->capture_bufsize = snd_pcm_lib_buffer_bytes(substream); | ||
599 | epcm->capture_bs_val = 0; | ||
600 | for (idx = 0; idx < 31; idx++) { | ||
601 | if (capture_period_sizes[idx] == epcm->capture_bufsize) { | ||
602 | epcm->capture_bs_val = idx + 1; | ||
603 | break; | ||
604 | } | ||
605 | } | ||
606 | if (epcm->capture_bs_val == 0) { | ||
607 | snd_BUG(); | ||
608 | epcm->capture_bs_val++; | ||
609 | } | ||
610 | if (epcm->type == CAPTURE_AC97ADC) { | ||
611 | epcm->capture_cr_val = emu->audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE; | ||
612 | if (runtime->channels > 1) | ||
613 | epcm->capture_cr_val |= emu->audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE; | ||
614 | epcm->capture_cr_val |= emu->audigy ? | ||
615 | snd_emu10k1_audigy_capture_rate_reg(runtime->rate) : | ||
616 | snd_emu10k1_capture_rate_reg(runtime->rate); | ||
617 | } | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | static void snd_emu10k1_playback_invalidate_cache(emu10k1_t *emu, int extra, emu10k1_voice_t *evoice) | ||
622 | { | ||
623 | snd_pcm_runtime_t *runtime; | ||
624 | unsigned int voice, stereo, i, ccis, cra = 64, cs, sample; | ||
625 | |||
626 | if (evoice == NULL) | ||
627 | return; | ||
628 | runtime = evoice->epcm->substream->runtime; | ||
629 | voice = evoice->number; | ||
630 | stereo = (!extra && runtime->channels == 2); | ||
631 | sample = snd_pcm_format_width(runtime->format) == 16 ? 0 : 0x80808080; | ||
632 | ccis = emu10k1_ccis(stereo, sample == 0); | ||
633 | // set cs to 2 * number of cache registers beside the invalidated | ||
634 | cs = (sample == 0) ? (32-ccis) : (64-ccis+1) >> 1; | ||
635 | if (cs > 16) cs = 16; | ||
636 | for (i = 0; i < cs; i++) { | ||
637 | snd_emu10k1_ptr_write(emu, CD0 + i, voice, sample); | ||
638 | if (stereo) { | ||
639 | snd_emu10k1_ptr_write(emu, CD0 + i, voice + 1, sample); | ||
640 | } | ||
641 | } | ||
642 | // reset cache | ||
643 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, 0); | ||
644 | snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice, cra); | ||
645 | if (stereo) { | ||
646 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice + 1, 0); | ||
647 | snd_emu10k1_ptr_write(emu, CCR_READADDRESS, voice + 1, cra); | ||
648 | } | ||
649 | // fill cache | ||
650 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice, ccis); | ||
651 | if (stereo) { | ||
652 | snd_emu10k1_ptr_write(emu, CCR_CACHEINVALIDSIZE, voice+1, ccis); | ||
653 | } | ||
654 | } | ||
655 | |||
656 | static void snd_emu10k1_playback_prepare_voice(emu10k1_t *emu, emu10k1_voice_t *evoice, | ||
657 | int master, int extra, | ||
658 | emu10k1_pcm_mixer_t *mix) | ||
659 | { | ||
660 | snd_pcm_substream_t *substream; | ||
661 | snd_pcm_runtime_t *runtime; | ||
662 | unsigned int attn, vattn; | ||
663 | unsigned int voice, tmp; | ||
664 | |||
665 | if (evoice == NULL) /* skip second voice for mono */ | ||
666 | return; | ||
667 | substream = evoice->epcm->substream; | ||
668 | runtime = substream->runtime; | ||
669 | voice = evoice->number; | ||
670 | |||
671 | attn = extra ? 0 : 0x00ff; | ||
672 | tmp = runtime->channels == 2 ? (master ? 1 : 2) : 0; | ||
673 | vattn = mix != NULL ? (mix->attn[tmp] << 16) : 0; | ||
674 | snd_emu10k1_ptr_write(emu, IFATN, voice, attn); | ||
675 | snd_emu10k1_ptr_write(emu, VTFT, voice, vattn | 0xffff); | ||
676 | snd_emu10k1_ptr_write(emu, CVCF, voice, vattn | 0xffff); | ||
677 | snd_emu10k1_ptr_write(emu, DCYSUSV, voice, 0x7f7f); | ||
678 | snd_emu10k1_voice_clear_loop_stop(emu, voice); | ||
679 | } | ||
680 | |||
681 | static void snd_emu10k1_playback_trigger_voice(emu10k1_t *emu, emu10k1_voice_t *evoice, int master, int extra) | ||
682 | { | ||
683 | snd_pcm_substream_t *substream; | ||
684 | snd_pcm_runtime_t *runtime; | ||
685 | unsigned int voice, pitch, pitch_target; | ||
686 | |||
687 | if (evoice == NULL) /* skip second voice for mono */ | ||
688 | return; | ||
689 | substream = evoice->epcm->substream; | ||
690 | runtime = substream->runtime; | ||
691 | voice = evoice->number; | ||
692 | |||
693 | pitch = snd_emu10k1_rate_to_pitch(runtime->rate) >> 8; | ||
694 | pitch_target = emu10k1_calc_pitch_target(runtime->rate); | ||
695 | snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, pitch_target); | ||
696 | if (master || evoice->epcm->type == PLAYBACK_EFX) | ||
697 | snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, pitch_target); | ||
698 | snd_emu10k1_ptr_write(emu, IP, voice, pitch); | ||
699 | if (extra) | ||
700 | snd_emu10k1_voice_intr_enable(emu, voice); | ||
701 | } | ||
702 | |||
703 | static void snd_emu10k1_playback_stop_voice(emu10k1_t *emu, emu10k1_voice_t *evoice) | ||
704 | { | ||
705 | unsigned int voice; | ||
706 | |||
707 | if (evoice == NULL) | ||
708 | return; | ||
709 | voice = evoice->number; | ||
710 | snd_emu10k1_voice_intr_disable(emu, voice); | ||
711 | snd_emu10k1_ptr_write(emu, PTRX_PITCHTARGET, voice, 0); | ||
712 | snd_emu10k1_ptr_write(emu, CPF_CURRENTPITCH, voice, 0); | ||
713 | snd_emu10k1_ptr_write(emu, IFATN, voice, 0xffff); | ||
714 | snd_emu10k1_ptr_write(emu, VTFT, voice, 0xffff); | ||
715 | snd_emu10k1_ptr_write(emu, CVCF, voice, 0xffff); | ||
716 | snd_emu10k1_ptr_write(emu, IP, voice, 0); | ||
717 | } | ||
718 | |||
719 | static int snd_emu10k1_playback_trigger(snd_pcm_substream_t * substream, | ||
720 | int cmd) | ||
721 | { | ||
722 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
723 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
724 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
725 | emu10k1_pcm_mixer_t *mix; | ||
726 | int result = 0; | ||
727 | |||
728 | // printk("trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)); | ||
729 | spin_lock(&emu->reg_lock); | ||
730 | switch (cmd) { | ||
731 | case SNDRV_PCM_TRIGGER_START: | ||
732 | snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra); /* do we need this? */ | ||
733 | snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[0]); | ||
734 | /* follow thru */ | ||
735 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
736 | mix = &emu->pcm_mixer[substream->number]; | ||
737 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix); | ||
738 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix); | ||
739 | snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL); | ||
740 | snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 1, 0); | ||
741 | snd_emu10k1_playback_trigger_voice(emu, epcm->voices[1], 0, 0); | ||
742 | snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); | ||
743 | epcm->running = 1; | ||
744 | break; | ||
745 | case SNDRV_PCM_TRIGGER_STOP: | ||
746 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
747 | epcm->running = 0; | ||
748 | snd_emu10k1_playback_stop_voice(emu, epcm->voices[0]); | ||
749 | snd_emu10k1_playback_stop_voice(emu, epcm->voices[1]); | ||
750 | snd_emu10k1_playback_stop_voice(emu, epcm->extra); | ||
751 | break; | ||
752 | default: | ||
753 | result = -EINVAL; | ||
754 | break; | ||
755 | } | ||
756 | spin_unlock(&emu->reg_lock); | ||
757 | return result; | ||
758 | } | ||
759 | |||
760 | static int snd_emu10k1_capture_trigger(snd_pcm_substream_t * substream, | ||
761 | int cmd) | ||
762 | { | ||
763 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
764 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
765 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
766 | int result = 0; | ||
767 | |||
768 | spin_lock(&emu->reg_lock); | ||
769 | switch (cmd) { | ||
770 | case SNDRV_PCM_TRIGGER_START: | ||
771 | // hmm this should cause full and half full interrupt to be raised? | ||
772 | outl(epcm->capture_ipr, emu->port + IPR); | ||
773 | snd_emu10k1_intr_enable(emu, epcm->capture_inte); | ||
774 | // printk("adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); | ||
775 | switch (epcm->type) { | ||
776 | case CAPTURE_AC97ADC: | ||
777 | snd_emu10k1_ptr_write(emu, ADCCR, 0, epcm->capture_cr_val); | ||
778 | break; | ||
779 | case CAPTURE_EFX: | ||
780 | if (emu->audigy) { | ||
781 | snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); | ||
782 | snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); | ||
783 | } else | ||
784 | snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); | ||
785 | break; | ||
786 | default: | ||
787 | break; | ||
788 | } | ||
789 | snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, epcm->capture_bs_val); | ||
790 | epcm->running = 1; | ||
791 | epcm->first_ptr = 1; | ||
792 | break; | ||
793 | case SNDRV_PCM_TRIGGER_STOP: | ||
794 | epcm->running = 0; | ||
795 | snd_emu10k1_intr_disable(emu, epcm->capture_inte); | ||
796 | outl(epcm->capture_ipr, emu->port + IPR); | ||
797 | snd_emu10k1_ptr_write(emu, epcm->capture_bs_reg, 0, 0); | ||
798 | switch (epcm->type) { | ||
799 | case CAPTURE_AC97ADC: | ||
800 | snd_emu10k1_ptr_write(emu, ADCCR, 0, 0); | ||
801 | break; | ||
802 | case CAPTURE_EFX: | ||
803 | if (emu->audigy) { | ||
804 | snd_emu10k1_ptr_write(emu, A_FXWC1, 0, 0); | ||
805 | snd_emu10k1_ptr_write(emu, A_FXWC2, 0, 0); | ||
806 | } else | ||
807 | snd_emu10k1_ptr_write(emu, FXWC, 0, 0); | ||
808 | break; | ||
809 | default: | ||
810 | break; | ||
811 | } | ||
812 | break; | ||
813 | default: | ||
814 | result = -EINVAL; | ||
815 | } | ||
816 | spin_unlock(&emu->reg_lock); | ||
817 | return result; | ||
818 | } | ||
819 | |||
820 | static snd_pcm_uframes_t snd_emu10k1_playback_pointer(snd_pcm_substream_t * substream) | ||
821 | { | ||
822 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
823 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
824 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
825 | unsigned int ptr; | ||
826 | |||
827 | if (!epcm->running) | ||
828 | return 0; | ||
829 | ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->voices[0]->number) & 0x00ffffff; | ||
830 | #if 0 /* Perex's code */ | ||
831 | ptr += runtime->buffer_size; | ||
832 | ptr -= epcm->ccca_start_addr; | ||
833 | ptr %= runtime->buffer_size; | ||
834 | #else /* EMU10K1 Open Source code from Creative */ | ||
835 | if (ptr < epcm->ccca_start_addr) | ||
836 | ptr += runtime->buffer_size - epcm->ccca_start_addr; | ||
837 | else { | ||
838 | ptr -= epcm->ccca_start_addr; | ||
839 | if (ptr >= runtime->buffer_size) | ||
840 | ptr -= runtime->buffer_size; | ||
841 | } | ||
842 | #endif | ||
843 | // printk("ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n", ptr, runtime->buffer_size, runtime->period_size); | ||
844 | return ptr; | ||
845 | } | ||
846 | |||
847 | |||
848 | static int snd_emu10k1_efx_playback_trigger(snd_pcm_substream_t * substream, | ||
849 | int cmd) | ||
850 | { | ||
851 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
852 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
853 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
854 | int i; | ||
855 | int result = 0; | ||
856 | |||
857 | spin_lock(&emu->reg_lock); | ||
858 | switch (cmd) { | ||
859 | case SNDRV_PCM_TRIGGER_START: | ||
860 | // prepare voices | ||
861 | for (i = 0; i < NUM_EFX_PLAYBACK; i++) { | ||
862 | snd_emu10k1_playback_invalidate_cache(emu, 0, epcm->voices[i]); | ||
863 | } | ||
864 | snd_emu10k1_playback_invalidate_cache(emu, 1, epcm->extra); | ||
865 | |||
866 | /* follow thru */ | ||
867 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
868 | snd_emu10k1_playback_prepare_voice(emu, epcm->extra, 1, 1, NULL); | ||
869 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 0, 0, | ||
870 | &emu->efx_pcm_mixer[0]); | ||
871 | for (i = 1; i < NUM_EFX_PLAYBACK; i++) | ||
872 | snd_emu10k1_playback_prepare_voice(emu, epcm->voices[i], 0, 0, | ||
873 | &emu->efx_pcm_mixer[i]); | ||
874 | snd_emu10k1_playback_trigger_voice(emu, epcm->voices[0], 0, 0); | ||
875 | snd_emu10k1_playback_trigger_voice(emu, epcm->extra, 1, 1); | ||
876 | for (i = 1; i < NUM_EFX_PLAYBACK; i++) | ||
877 | snd_emu10k1_playback_trigger_voice(emu, epcm->voices[i], 0, 0); | ||
878 | epcm->running = 1; | ||
879 | break; | ||
880 | case SNDRV_PCM_TRIGGER_STOP: | ||
881 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
882 | epcm->running = 0; | ||
883 | for (i = 0; i < NUM_EFX_PLAYBACK; i++) { | ||
884 | snd_emu10k1_playback_stop_voice(emu, epcm->voices[i]); | ||
885 | } | ||
886 | snd_emu10k1_playback_stop_voice(emu, epcm->extra); | ||
887 | break; | ||
888 | default: | ||
889 | result = -EINVAL; | ||
890 | break; | ||
891 | } | ||
892 | spin_unlock(&emu->reg_lock); | ||
893 | return result; | ||
894 | } | ||
895 | |||
896 | |||
897 | static snd_pcm_uframes_t snd_emu10k1_capture_pointer(snd_pcm_substream_t * substream) | ||
898 | { | ||
899 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
900 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
901 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
902 | unsigned int ptr; | ||
903 | |||
904 | if (!epcm->running) | ||
905 | return 0; | ||
906 | if (epcm->first_ptr) { | ||
907 | udelay(50); // hack, it takes awhile until capture is started | ||
908 | epcm->first_ptr = 0; | ||
909 | } | ||
910 | ptr = snd_emu10k1_ptr_read(emu, epcm->capture_idx_reg, 0) & 0x0000ffff; | ||
911 | return bytes_to_frames(runtime, ptr); | ||
912 | } | ||
913 | |||
914 | /* | ||
915 | * Playback support device description | ||
916 | */ | ||
917 | |||
918 | static snd_pcm_hardware_t snd_emu10k1_playback = | ||
919 | { | ||
920 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
921 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
922 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), | ||
923 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, | ||
924 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_96000, | ||
925 | .rate_min = 4000, | ||
926 | .rate_max = 96000, | ||
927 | .channels_min = 1, | ||
928 | .channels_max = 2, | ||
929 | .buffer_bytes_max = (128*1024), | ||
930 | .period_bytes_min = 64, | ||
931 | .period_bytes_max = (128*1024), | ||
932 | .periods_min = 1, | ||
933 | .periods_max = 1024, | ||
934 | .fifo_size = 0, | ||
935 | }; | ||
936 | |||
937 | /* | ||
938 | * Capture support device description | ||
939 | */ | ||
940 | |||
941 | static snd_pcm_hardware_t snd_emu10k1_capture = | ||
942 | { | ||
943 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
944 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
945 | SNDRV_PCM_INFO_MMAP_VALID), | ||
946 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
947 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
948 | .rate_min = 8000, | ||
949 | .rate_max = 48000, | ||
950 | .channels_min = 1, | ||
951 | .channels_max = 2, | ||
952 | .buffer_bytes_max = (64*1024), | ||
953 | .period_bytes_min = 384, | ||
954 | .period_bytes_max = (64*1024), | ||
955 | .periods_min = 2, | ||
956 | .periods_max = 2, | ||
957 | .fifo_size = 0, | ||
958 | }; | ||
959 | |||
960 | /* | ||
961 | * | ||
962 | */ | ||
963 | |||
964 | static void snd_emu10k1_pcm_mixer_notify1(emu10k1_t *emu, snd_kcontrol_t *kctl, int idx, int activate) | ||
965 | { | ||
966 | snd_ctl_elem_id_t id; | ||
967 | |||
968 | snd_runtime_check(kctl != NULL, return); | ||
969 | if (activate) | ||
970 | kctl->vd[idx].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
971 | else | ||
972 | kctl->vd[idx].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
973 | snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
974 | SNDRV_CTL_EVENT_MASK_INFO, | ||
975 | snd_ctl_build_ioff(&id, kctl, idx)); | ||
976 | } | ||
977 | |||
978 | static void snd_emu10k1_pcm_mixer_notify(emu10k1_t *emu, int idx, int activate) | ||
979 | { | ||
980 | snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_send_routing, idx, activate); | ||
981 | snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_send_volume, idx, activate); | ||
982 | snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_attn, idx, activate); | ||
983 | } | ||
984 | |||
985 | static void snd_emu10k1_pcm_efx_mixer_notify(emu10k1_t *emu, int idx, int activate) | ||
986 | { | ||
987 | snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_routing, idx, activate); | ||
988 | snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_send_volume, idx, activate); | ||
989 | snd_emu10k1_pcm_mixer_notify1(emu, emu->ctl_efx_attn, idx, activate); | ||
990 | } | ||
991 | |||
992 | static void snd_emu10k1_pcm_free_substream(snd_pcm_runtime_t *runtime) | ||
993 | { | ||
994 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
995 | |||
996 | kfree(epcm); | ||
997 | } | ||
998 | |||
999 | static int snd_emu10k1_efx_playback_close(snd_pcm_substream_t * substream) | ||
1000 | { | ||
1001 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1002 | emu10k1_pcm_mixer_t *mix; | ||
1003 | int i; | ||
1004 | |||
1005 | for (i=0; i < NUM_EFX_PLAYBACK; i++) { | ||
1006 | mix = &emu->efx_pcm_mixer[i]; | ||
1007 | mix->epcm = NULL; | ||
1008 | snd_emu10k1_pcm_efx_mixer_notify(emu, i, 0); | ||
1009 | } | ||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static int snd_emu10k1_efx_playback_open(snd_pcm_substream_t * substream) | ||
1014 | { | ||
1015 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1016 | emu10k1_pcm_t *epcm; | ||
1017 | emu10k1_pcm_mixer_t *mix; | ||
1018 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1019 | int i; | ||
1020 | |||
1021 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
1022 | if (epcm == NULL) | ||
1023 | return -ENOMEM; | ||
1024 | epcm->emu = emu; | ||
1025 | epcm->type = PLAYBACK_EFX; | ||
1026 | epcm->substream = substream; | ||
1027 | |||
1028 | emu->pcm_playback_efx_substream = substream; | ||
1029 | |||
1030 | runtime->private_data = epcm; | ||
1031 | runtime->private_free = snd_emu10k1_pcm_free_substream; | ||
1032 | runtime->hw = snd_emu10k1_efx_playback; | ||
1033 | |||
1034 | for (i=0; i < NUM_EFX_PLAYBACK; i++) { | ||
1035 | mix = &emu->efx_pcm_mixer[i]; | ||
1036 | mix->send_routing[0][0] = i; | ||
1037 | memset(&mix->send_volume, 0, sizeof(mix->send_volume)); | ||
1038 | mix->send_volume[0][0] = 255; | ||
1039 | mix->attn[0] = 0xffff; | ||
1040 | mix->epcm = epcm; | ||
1041 | snd_emu10k1_pcm_efx_mixer_notify(emu, i, 1); | ||
1042 | } | ||
1043 | return 0; | ||
1044 | } | ||
1045 | |||
1046 | static int snd_emu10k1_playback_open(snd_pcm_substream_t * substream) | ||
1047 | { | ||
1048 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1049 | emu10k1_pcm_t *epcm; | ||
1050 | emu10k1_pcm_mixer_t *mix; | ||
1051 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1052 | int i, err; | ||
1053 | |||
1054 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
1055 | if (epcm == NULL) | ||
1056 | return -ENOMEM; | ||
1057 | epcm->emu = emu; | ||
1058 | epcm->type = PLAYBACK_EMUVOICE; | ||
1059 | epcm->substream = substream; | ||
1060 | runtime->private_data = epcm; | ||
1061 | runtime->private_free = snd_emu10k1_pcm_free_substream; | ||
1062 | runtime->hw = snd_emu10k1_playback; | ||
1063 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) { | ||
1064 | kfree(epcm); | ||
1065 | return err; | ||
1066 | } | ||
1067 | if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0) { | ||
1068 | kfree(epcm); | ||
1069 | return err; | ||
1070 | } | ||
1071 | mix = &emu->pcm_mixer[substream->number]; | ||
1072 | for (i = 0; i < 4; i++) | ||
1073 | mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i; | ||
1074 | memset(&mix->send_volume, 0, sizeof(mix->send_volume)); | ||
1075 | mix->send_volume[0][0] = mix->send_volume[0][1] = | ||
1076 | mix->send_volume[1][0] = mix->send_volume[2][1] = 255; | ||
1077 | mix->attn[0] = mix->attn[1] = mix->attn[2] = 0xffff; | ||
1078 | mix->epcm = epcm; | ||
1079 | snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1); | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | static int snd_emu10k1_playback_close(snd_pcm_substream_t * substream) | ||
1084 | { | ||
1085 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1086 | emu10k1_pcm_mixer_t *mix = &emu->pcm_mixer[substream->number]; | ||
1087 | |||
1088 | mix->epcm = NULL; | ||
1089 | snd_emu10k1_pcm_mixer_notify(emu, substream->number, 0); | ||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | static int snd_emu10k1_capture_open(snd_pcm_substream_t * substream) | ||
1094 | { | ||
1095 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1096 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1097 | emu10k1_pcm_t *epcm; | ||
1098 | |||
1099 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
1100 | if (epcm == NULL) | ||
1101 | return -ENOMEM; | ||
1102 | epcm->emu = emu; | ||
1103 | epcm->type = CAPTURE_AC97ADC; | ||
1104 | epcm->substream = substream; | ||
1105 | epcm->capture_ipr = IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL; | ||
1106 | epcm->capture_inte = INTE_ADCBUFENABLE; | ||
1107 | epcm->capture_ba_reg = ADCBA; | ||
1108 | epcm->capture_bs_reg = ADCBS; | ||
1109 | epcm->capture_idx_reg = emu->audigy ? A_ADCIDX : ADCIDX; | ||
1110 | runtime->private_data = epcm; | ||
1111 | runtime->private_free = snd_emu10k1_pcm_free_substream; | ||
1112 | runtime->hw = snd_emu10k1_capture; | ||
1113 | emu->capture_interrupt = snd_emu10k1_pcm_ac97adc_interrupt; | ||
1114 | emu->pcm_capture_substream = substream; | ||
1115 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); | ||
1116 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_capture_rates); | ||
1117 | return 0; | ||
1118 | } | ||
1119 | |||
1120 | static int snd_emu10k1_capture_close(snd_pcm_substream_t * substream) | ||
1121 | { | ||
1122 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1123 | |||
1124 | emu->capture_interrupt = NULL; | ||
1125 | emu->pcm_capture_substream = NULL; | ||
1126 | return 0; | ||
1127 | } | ||
1128 | |||
1129 | static int snd_emu10k1_capture_mic_open(snd_pcm_substream_t * substream) | ||
1130 | { | ||
1131 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1132 | emu10k1_pcm_t *epcm; | ||
1133 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1134 | |||
1135 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
1136 | if (epcm == NULL) | ||
1137 | return -ENOMEM; | ||
1138 | epcm->emu = emu; | ||
1139 | epcm->type = CAPTURE_AC97MIC; | ||
1140 | epcm->substream = substream; | ||
1141 | epcm->capture_ipr = IPR_MICBUFFULL|IPR_MICBUFHALFFULL; | ||
1142 | epcm->capture_inte = INTE_MICBUFENABLE; | ||
1143 | epcm->capture_ba_reg = MICBA; | ||
1144 | epcm->capture_bs_reg = MICBS; | ||
1145 | epcm->capture_idx_reg = emu->audigy ? A_MICIDX : MICIDX; | ||
1146 | substream->runtime->private_data = epcm; | ||
1147 | substream->runtime->private_free = snd_emu10k1_pcm_free_substream; | ||
1148 | runtime->hw = snd_emu10k1_capture; | ||
1149 | runtime->hw.rates = SNDRV_PCM_RATE_8000; | ||
1150 | runtime->hw.rate_min = runtime->hw.rate_max = 8000; | ||
1151 | runtime->hw.channels_min = 1; | ||
1152 | emu->capture_mic_interrupt = snd_emu10k1_pcm_ac97mic_interrupt; | ||
1153 | emu->pcm_capture_mic_substream = substream; | ||
1154 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); | ||
1155 | return 0; | ||
1156 | } | ||
1157 | |||
1158 | static int snd_emu10k1_capture_mic_close(snd_pcm_substream_t * substream) | ||
1159 | { | ||
1160 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1161 | |||
1162 | emu->capture_interrupt = NULL; | ||
1163 | emu->pcm_capture_mic_substream = NULL; | ||
1164 | return 0; | ||
1165 | } | ||
1166 | |||
1167 | static int snd_emu10k1_capture_efx_open(snd_pcm_substream_t * substream) | ||
1168 | { | ||
1169 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1170 | emu10k1_pcm_t *epcm; | ||
1171 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1172 | int nefx = emu->audigy ? 64 : 32; | ||
1173 | int idx; | ||
1174 | |||
1175 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
1176 | if (epcm == NULL) | ||
1177 | return -ENOMEM; | ||
1178 | epcm->emu = emu; | ||
1179 | epcm->type = CAPTURE_EFX; | ||
1180 | epcm->substream = substream; | ||
1181 | epcm->capture_ipr = IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL; | ||
1182 | epcm->capture_inte = INTE_EFXBUFENABLE; | ||
1183 | epcm->capture_ba_reg = FXBA; | ||
1184 | epcm->capture_bs_reg = FXBS; | ||
1185 | epcm->capture_idx_reg = FXIDX; | ||
1186 | substream->runtime->private_data = epcm; | ||
1187 | substream->runtime->private_free = snd_emu10k1_pcm_free_substream; | ||
1188 | runtime->hw = snd_emu10k1_capture; | ||
1189 | runtime->hw.rates = SNDRV_PCM_RATE_48000; | ||
1190 | runtime->hw.rate_min = runtime->hw.rate_max = 48000; | ||
1191 | spin_lock_irq(&emu->reg_lock); | ||
1192 | runtime->hw.channels_min = runtime->hw.channels_max = 0; | ||
1193 | for (idx = 0; idx < nefx; idx++) { | ||
1194 | if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) { | ||
1195 | runtime->hw.channels_min++; | ||
1196 | runtime->hw.channels_max++; | ||
1197 | } | ||
1198 | } | ||
1199 | epcm->capture_cr_val = emu->efx_voices_mask[0]; | ||
1200 | epcm->capture_cr_val2 = emu->efx_voices_mask[1]; | ||
1201 | spin_unlock_irq(&emu->reg_lock); | ||
1202 | emu->capture_efx_interrupt = snd_emu10k1_pcm_efx_interrupt; | ||
1203 | emu->pcm_capture_efx_substream = substream; | ||
1204 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, &hw_constraints_capture_period_sizes); | ||
1205 | return 0; | ||
1206 | } | ||
1207 | |||
1208 | static int snd_emu10k1_capture_efx_close(snd_pcm_substream_t * substream) | ||
1209 | { | ||
1210 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1211 | |||
1212 | emu->capture_interrupt = NULL; | ||
1213 | emu->pcm_capture_efx_substream = NULL; | ||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static snd_pcm_ops_t snd_emu10k1_playback_ops = { | ||
1218 | .open = snd_emu10k1_playback_open, | ||
1219 | .close = snd_emu10k1_playback_close, | ||
1220 | .ioctl = snd_pcm_lib_ioctl, | ||
1221 | .hw_params = snd_emu10k1_playback_hw_params, | ||
1222 | .hw_free = snd_emu10k1_playback_hw_free, | ||
1223 | .prepare = snd_emu10k1_playback_prepare, | ||
1224 | .trigger = snd_emu10k1_playback_trigger, | ||
1225 | .pointer = snd_emu10k1_playback_pointer, | ||
1226 | .page = snd_pcm_sgbuf_ops_page, | ||
1227 | }; | ||
1228 | |||
1229 | static snd_pcm_ops_t snd_emu10k1_capture_ops = { | ||
1230 | .open = snd_emu10k1_capture_open, | ||
1231 | .close = snd_emu10k1_capture_close, | ||
1232 | .ioctl = snd_pcm_lib_ioctl, | ||
1233 | .hw_params = snd_emu10k1_capture_hw_params, | ||
1234 | .hw_free = snd_emu10k1_capture_hw_free, | ||
1235 | .prepare = snd_emu10k1_capture_prepare, | ||
1236 | .trigger = snd_emu10k1_capture_trigger, | ||
1237 | .pointer = snd_emu10k1_capture_pointer, | ||
1238 | }; | ||
1239 | |||
1240 | /* EFX playback */ | ||
1241 | static snd_pcm_ops_t snd_emu10k1_efx_playback_ops = { | ||
1242 | .open = snd_emu10k1_efx_playback_open, | ||
1243 | .close = snd_emu10k1_efx_playback_close, | ||
1244 | .ioctl = snd_pcm_lib_ioctl, | ||
1245 | .hw_params = snd_emu10k1_playback_hw_params, | ||
1246 | .hw_free = snd_emu10k1_efx_playback_hw_free, | ||
1247 | .prepare = snd_emu10k1_efx_playback_prepare, | ||
1248 | .trigger = snd_emu10k1_efx_playback_trigger, | ||
1249 | .pointer = snd_emu10k1_efx_playback_pointer, | ||
1250 | .page = snd_pcm_sgbuf_ops_page, | ||
1251 | }; | ||
1252 | |||
1253 | static void snd_emu10k1_pcm_free(snd_pcm_t *pcm) | ||
1254 | { | ||
1255 | emu10k1_t *emu = pcm->private_data; | ||
1256 | emu->pcm = NULL; | ||
1257 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
1258 | } | ||
1259 | |||
1260 | int __devinit snd_emu10k1_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm) | ||
1261 | { | ||
1262 | snd_pcm_t *pcm; | ||
1263 | snd_pcm_substream_t *substream; | ||
1264 | int err; | ||
1265 | |||
1266 | if (rpcm) | ||
1267 | *rpcm = NULL; | ||
1268 | |||
1269 | if ((err = snd_pcm_new(emu->card, "emu10k1", device, 32, 1, &pcm)) < 0) | ||
1270 | return err; | ||
1271 | |||
1272 | pcm->private_data = emu; | ||
1273 | pcm->private_free = snd_emu10k1_pcm_free; | ||
1274 | |||
1275 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_playback_ops); | ||
1276 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_ops); | ||
1277 | |||
1278 | pcm->info_flags = 0; | ||
1279 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | ||
1280 | strcpy(pcm->name, "ADC Capture/Standard PCM Playback"); | ||
1281 | emu->pcm = pcm; | ||
1282 | |||
1283 | for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) | ||
1284 | if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) | ||
1285 | return err; | ||
1286 | |||
1287 | for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) | ||
1288 | snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); | ||
1289 | |||
1290 | if (rpcm) | ||
1291 | *rpcm = pcm; | ||
1292 | |||
1293 | return 0; | ||
1294 | } | ||
1295 | |||
1296 | int __devinit snd_emu10k1_pcm_multi(emu10k1_t * emu, int device, snd_pcm_t ** rpcm) | ||
1297 | { | ||
1298 | snd_pcm_t *pcm; | ||
1299 | snd_pcm_substream_t *substream; | ||
1300 | int err; | ||
1301 | |||
1302 | if (rpcm) | ||
1303 | *rpcm = NULL; | ||
1304 | |||
1305 | if ((err = snd_pcm_new(emu->card, "emu10k1", device, 1, 0, &pcm)) < 0) | ||
1306 | return err; | ||
1307 | |||
1308 | pcm->private_data = emu; | ||
1309 | pcm->private_free = snd_emu10k1_pcm_free; | ||
1310 | |||
1311 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_efx_playback_ops); | ||
1312 | |||
1313 | pcm->info_flags = 0; | ||
1314 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | ||
1315 | strcpy(pcm->name, "Multichannel Playback"); | ||
1316 | emu->pcm = pcm; | ||
1317 | |||
1318 | for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) | ||
1319 | if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) | ||
1320 | return err; | ||
1321 | |||
1322 | if (rpcm) | ||
1323 | *rpcm = pcm; | ||
1324 | |||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | |||
1329 | static snd_pcm_ops_t snd_emu10k1_capture_mic_ops = { | ||
1330 | .open = snd_emu10k1_capture_mic_open, | ||
1331 | .close = snd_emu10k1_capture_mic_close, | ||
1332 | .ioctl = snd_pcm_lib_ioctl, | ||
1333 | .hw_params = snd_emu10k1_capture_hw_params, | ||
1334 | .hw_free = snd_emu10k1_capture_hw_free, | ||
1335 | .prepare = snd_emu10k1_capture_prepare, | ||
1336 | .trigger = snd_emu10k1_capture_trigger, | ||
1337 | .pointer = snd_emu10k1_capture_pointer, | ||
1338 | }; | ||
1339 | |||
1340 | static void snd_emu10k1_pcm_mic_free(snd_pcm_t *pcm) | ||
1341 | { | ||
1342 | emu10k1_t *emu = pcm->private_data; | ||
1343 | emu->pcm_mic = NULL; | ||
1344 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
1345 | } | ||
1346 | |||
1347 | int __devinit snd_emu10k1_pcm_mic(emu10k1_t * emu, int device, snd_pcm_t ** rpcm) | ||
1348 | { | ||
1349 | snd_pcm_t *pcm; | ||
1350 | int err; | ||
1351 | |||
1352 | if (rpcm) | ||
1353 | *rpcm = NULL; | ||
1354 | |||
1355 | if ((err = snd_pcm_new(emu->card, "emu10k1 mic", device, 0, 1, &pcm)) < 0) | ||
1356 | return err; | ||
1357 | |||
1358 | pcm->private_data = emu; | ||
1359 | pcm->private_free = snd_emu10k1_pcm_mic_free; | ||
1360 | |||
1361 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_mic_ops); | ||
1362 | |||
1363 | pcm->info_flags = 0; | ||
1364 | strcpy(pcm->name, "Mic Capture"); | ||
1365 | emu->pcm_mic = pcm; | ||
1366 | |||
1367 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); | ||
1368 | |||
1369 | if (rpcm) | ||
1370 | *rpcm = pcm; | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | static int snd_emu10k1_pcm_efx_voices_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
1375 | { | ||
1376 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
1377 | int nefx = emu->audigy ? 64 : 32; | ||
1378 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
1379 | uinfo->count = nefx; | ||
1380 | uinfo->value.integer.min = 0; | ||
1381 | uinfo->value.integer.max = 1; | ||
1382 | return 0; | ||
1383 | } | ||
1384 | |||
1385 | static int snd_emu10k1_pcm_efx_voices_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1386 | { | ||
1387 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
1388 | int nefx = emu->audigy ? 64 : 32; | ||
1389 | int idx; | ||
1390 | |||
1391 | spin_lock_irq(&emu->reg_lock); | ||
1392 | for (idx = 0; idx < nefx; idx++) | ||
1393 | ucontrol->value.integer.value[idx] = (emu->efx_voices_mask[idx / 32] & (1 << (idx % 32))) ? 1 : 0; | ||
1394 | spin_unlock_irq(&emu->reg_lock); | ||
1395 | return 0; | ||
1396 | } | ||
1397 | |||
1398 | static int snd_emu10k1_pcm_efx_voices_mask_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
1399 | { | ||
1400 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
1401 | unsigned int nval[2], bits; | ||
1402 | int nefx = emu->audigy ? 64 : 32; | ||
1403 | int nefxb = emu->audigy ? 7 : 6; | ||
1404 | int change, idx; | ||
1405 | |||
1406 | nval[0] = nval[1] = 0; | ||
1407 | for (idx = 0, bits = 0; idx < nefx; idx++) | ||
1408 | if (ucontrol->value.integer.value[idx]) { | ||
1409 | nval[idx / 32] |= 1 << (idx % 32); | ||
1410 | bits++; | ||
1411 | } | ||
1412 | |||
1413 | for (idx = 0; idx < nefxb; idx++) | ||
1414 | if (1 << idx == bits) | ||
1415 | break; | ||
1416 | |||
1417 | if (idx >= nefxb) | ||
1418 | return -EINVAL; | ||
1419 | |||
1420 | spin_lock_irq(&emu->reg_lock); | ||
1421 | change = (nval[0] != emu->efx_voices_mask[0]) || | ||
1422 | (nval[1] != emu->efx_voices_mask[1]); | ||
1423 | emu->efx_voices_mask[0] = nval[0]; | ||
1424 | emu->efx_voices_mask[1] = nval[1]; | ||
1425 | spin_unlock_irq(&emu->reg_lock); | ||
1426 | return change; | ||
1427 | } | ||
1428 | |||
1429 | static snd_kcontrol_new_t snd_emu10k1_pcm_efx_voices_mask = { | ||
1430 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
1431 | .name = "Captured FX8010 Outputs", | ||
1432 | .info = snd_emu10k1_pcm_efx_voices_mask_info, | ||
1433 | .get = snd_emu10k1_pcm_efx_voices_mask_get, | ||
1434 | .put = snd_emu10k1_pcm_efx_voices_mask_put | ||
1435 | }; | ||
1436 | |||
1437 | static snd_pcm_ops_t snd_emu10k1_capture_efx_ops = { | ||
1438 | .open = snd_emu10k1_capture_efx_open, | ||
1439 | .close = snd_emu10k1_capture_efx_close, | ||
1440 | .ioctl = snd_pcm_lib_ioctl, | ||
1441 | .hw_params = snd_emu10k1_capture_hw_params, | ||
1442 | .hw_free = snd_emu10k1_capture_hw_free, | ||
1443 | .prepare = snd_emu10k1_capture_prepare, | ||
1444 | .trigger = snd_emu10k1_capture_trigger, | ||
1445 | .pointer = snd_emu10k1_capture_pointer, | ||
1446 | }; | ||
1447 | |||
1448 | |||
1449 | /* EFX playback */ | ||
1450 | |||
1451 | #define INITIAL_TRAM_SHIFT 14 | ||
1452 | #define INITIAL_TRAM_POS(size) ((((size) / 2) - INITIAL_TRAM_SHIFT) - 1) | ||
1453 | |||
1454 | static void snd_emu10k1_fx8010_playback_irq(emu10k1_t *emu, void *private_data) | ||
1455 | { | ||
1456 | snd_pcm_substream_t *substream = private_data; | ||
1457 | snd_pcm_period_elapsed(substream); | ||
1458 | } | ||
1459 | |||
1460 | static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left, | ||
1461 | unsigned short *dst_right, | ||
1462 | unsigned short *src, | ||
1463 | unsigned int count, | ||
1464 | unsigned int tram_shift) | ||
1465 | { | ||
1466 | // printk("tram_poke1: dst_left = 0x%p, dst_right = 0x%p, src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); | ||
1467 | if ((tram_shift & 1) == 0) { | ||
1468 | while (count--) { | ||
1469 | *dst_left-- = *src++; | ||
1470 | *dst_right-- = *src++; | ||
1471 | } | ||
1472 | } else { | ||
1473 | while (count--) { | ||
1474 | *dst_right-- = *src++; | ||
1475 | *dst_left-- = *src++; | ||
1476 | } | ||
1477 | } | ||
1478 | } | ||
1479 | |||
1480 | static void fx8010_pb_trans_copy(snd_pcm_substream_t *substream, | ||
1481 | snd_pcm_indirect_t *rec, size_t bytes) | ||
1482 | { | ||
1483 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1484 | snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; | ||
1485 | unsigned int tram_size = pcm->buffer_size; | ||
1486 | unsigned short *src = (unsigned short *)(substream->runtime->dma_area + rec->sw_data); | ||
1487 | unsigned int frames = bytes >> 2, count; | ||
1488 | unsigned int tram_pos = pcm->tram_pos; | ||
1489 | unsigned int tram_shift = pcm->tram_shift; | ||
1490 | |||
1491 | while (frames > tram_pos) { | ||
1492 | count = tram_pos + 1; | ||
1493 | snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos, | ||
1494 | (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2, | ||
1495 | src, count, tram_shift); | ||
1496 | src += count * 2; | ||
1497 | frames -= count; | ||
1498 | tram_pos = (tram_size / 2) - 1; | ||
1499 | tram_shift++; | ||
1500 | } | ||
1501 | snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + tram_pos, | ||
1502 | (unsigned short *)emu->fx8010.etram_pages.area + tram_pos + tram_size / 2, | ||
1503 | src, frames, tram_shift); | ||
1504 | tram_pos -= frames; | ||
1505 | pcm->tram_pos = tram_pos; | ||
1506 | pcm->tram_shift = tram_shift; | ||
1507 | } | ||
1508 | |||
1509 | static int snd_emu10k1_fx8010_playback_transfer(snd_pcm_substream_t *substream) | ||
1510 | { | ||
1511 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1512 | snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; | ||
1513 | |||
1514 | snd_pcm_indirect_playback_transfer(substream, &pcm->pcm_rec, fx8010_pb_trans_copy); | ||
1515 | return 0; | ||
1516 | } | ||
1517 | |||
1518 | static int snd_emu10k1_fx8010_playback_hw_params(snd_pcm_substream_t * substream, | ||
1519 | snd_pcm_hw_params_t * hw_params) | ||
1520 | { | ||
1521 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | ||
1522 | } | ||
1523 | |||
1524 | static int snd_emu10k1_fx8010_playback_hw_free(snd_pcm_substream_t * substream) | ||
1525 | { | ||
1526 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1527 | snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; | ||
1528 | unsigned int i; | ||
1529 | |||
1530 | for (i = 0; i < pcm->channels; i++) | ||
1531 | snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, 0); | ||
1532 | snd_pcm_lib_free_pages(substream); | ||
1533 | return 0; | ||
1534 | } | ||
1535 | |||
1536 | static int snd_emu10k1_fx8010_playback_prepare(snd_pcm_substream_t * substream) | ||
1537 | { | ||
1538 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1539 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1540 | snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; | ||
1541 | unsigned int i; | ||
1542 | |||
1543 | // printk("prepare: etram_pages = 0x%p, dma_area = 0x%x, buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); | ||
1544 | memset(&pcm->pcm_rec, 0, sizeof(pcm->pcm_rec)); | ||
1545 | pcm->pcm_rec.hw_buffer_size = pcm->buffer_size * 2; /* byte size */ | ||
1546 | pcm->pcm_rec.sw_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
1547 | pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); | ||
1548 | pcm->tram_shift = 0; | ||
1549 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_running, 0, 0); /* reset */ | ||
1550 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); /* reset */ | ||
1551 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_size, 0, runtime->buffer_size); | ||
1552 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_ptr, 0, 0); /* reset ptr number */ | ||
1553 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_count, 0, runtime->period_size); | ||
1554 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_tmpcount, 0, runtime->period_size); | ||
1555 | for (i = 0; i < pcm->channels; i++) | ||
1556 | snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + 0x80 + pcm->etram[i], 0, (TANKMEMADDRREG_READ|TANKMEMADDRREG_ALIGN) + i * (runtime->buffer_size / pcm->channels)); | ||
1557 | return 0; | ||
1558 | } | ||
1559 | |||
1560 | static int snd_emu10k1_fx8010_playback_trigger(snd_pcm_substream_t * substream, int cmd) | ||
1561 | { | ||
1562 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1563 | snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; | ||
1564 | int result = 0; | ||
1565 | |||
1566 | spin_lock(&emu->reg_lock); | ||
1567 | switch (cmd) { | ||
1568 | case SNDRV_PCM_TRIGGER_START: | ||
1569 | /* follow thru */ | ||
1570 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1571 | #ifdef EMU10K1_SET_AC3_IEC958 | ||
1572 | { | ||
1573 | int i; | ||
1574 | for (i = 0; i < 3; i++) { | ||
1575 | unsigned int bits; | ||
1576 | bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | | ||
1577 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | | ||
1578 | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT | SPCS_NOTAUDIODATA; | ||
1579 | snd_emu10k1_ptr_write(emu, SPCS0 + i, 0, bits); | ||
1580 | } | ||
1581 | } | ||
1582 | #endif | ||
1583 | result = snd_emu10k1_fx8010_register_irq_handler(emu, snd_emu10k1_fx8010_playback_irq, pcm->gpr_running, substream, &pcm->irq); | ||
1584 | if (result < 0) | ||
1585 | goto __err; | ||
1586 | snd_emu10k1_fx8010_playback_transfer(substream); /* roll the ball */ | ||
1587 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 1); | ||
1588 | break; | ||
1589 | case SNDRV_PCM_TRIGGER_STOP: | ||
1590 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1591 | snd_emu10k1_fx8010_unregister_irq_handler(emu, pcm->irq); pcm->irq = NULL; | ||
1592 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); | ||
1593 | pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); | ||
1594 | pcm->tram_shift = 0; | ||
1595 | break; | ||
1596 | default: | ||
1597 | result = -EINVAL; | ||
1598 | break; | ||
1599 | } | ||
1600 | __err: | ||
1601 | spin_unlock(&emu->reg_lock); | ||
1602 | return result; | ||
1603 | } | ||
1604 | |||
1605 | static snd_pcm_uframes_t snd_emu10k1_fx8010_playback_pointer(snd_pcm_substream_t * substream) | ||
1606 | { | ||
1607 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1608 | snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; | ||
1609 | size_t ptr; /* byte pointer */ | ||
1610 | |||
1611 | if (!snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_trigger, 0)) | ||
1612 | return 0; | ||
1613 | ptr = snd_emu10k1_ptr_read(emu, emu->gpr_base + pcm->gpr_ptr, 0) << 2; | ||
1614 | return snd_pcm_indirect_playback_pointer(substream, &pcm->pcm_rec, ptr); | ||
1615 | } | ||
1616 | |||
1617 | static snd_pcm_hardware_t snd_emu10k1_fx8010_playback = | ||
1618 | { | ||
1619 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
1620 | /* SNDRV_PCM_INFO_MMAP_VALID | */ SNDRV_PCM_INFO_PAUSE), | ||
1621 | .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, | ||
1622 | .rates = SNDRV_PCM_RATE_48000, | ||
1623 | .rate_min = 48000, | ||
1624 | .rate_max = 48000, | ||
1625 | .channels_min = 1, | ||
1626 | .channels_max = 1, | ||
1627 | .buffer_bytes_max = (128*1024), | ||
1628 | .period_bytes_min = 1024, | ||
1629 | .period_bytes_max = (128*1024), | ||
1630 | .periods_min = 1, | ||
1631 | .periods_max = 1024, | ||
1632 | .fifo_size = 0, | ||
1633 | }; | ||
1634 | |||
1635 | static int snd_emu10k1_fx8010_playback_open(snd_pcm_substream_t * substream) | ||
1636 | { | ||
1637 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1638 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1639 | snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; | ||
1640 | |||
1641 | runtime->hw = snd_emu10k1_fx8010_playback; | ||
1642 | runtime->hw.channels_min = runtime->hw.channels_max = pcm->channels; | ||
1643 | runtime->hw.period_bytes_max = (pcm->buffer_size * 2) / 2; | ||
1644 | spin_lock_irq(&emu->reg_lock); | ||
1645 | if (pcm->valid == 0) { | ||
1646 | spin_unlock_irq(&emu->reg_lock); | ||
1647 | return -ENODEV; | ||
1648 | } | ||
1649 | pcm->opened = 1; | ||
1650 | spin_unlock_irq(&emu->reg_lock); | ||
1651 | return 0; | ||
1652 | } | ||
1653 | |||
1654 | static int snd_emu10k1_fx8010_playback_close(snd_pcm_substream_t * substream) | ||
1655 | { | ||
1656 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
1657 | snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; | ||
1658 | |||
1659 | spin_lock_irq(&emu->reg_lock); | ||
1660 | pcm->opened = 0; | ||
1661 | spin_unlock_irq(&emu->reg_lock); | ||
1662 | return 0; | ||
1663 | } | ||
1664 | |||
1665 | static snd_pcm_ops_t snd_emu10k1_fx8010_playback_ops = { | ||
1666 | .open = snd_emu10k1_fx8010_playback_open, | ||
1667 | .close = snd_emu10k1_fx8010_playback_close, | ||
1668 | .ioctl = snd_pcm_lib_ioctl, | ||
1669 | .hw_params = snd_emu10k1_fx8010_playback_hw_params, | ||
1670 | .hw_free = snd_emu10k1_fx8010_playback_hw_free, | ||
1671 | .prepare = snd_emu10k1_fx8010_playback_prepare, | ||
1672 | .trigger = snd_emu10k1_fx8010_playback_trigger, | ||
1673 | .pointer = snd_emu10k1_fx8010_playback_pointer, | ||
1674 | .ack = snd_emu10k1_fx8010_playback_transfer, | ||
1675 | }; | ||
1676 | |||
1677 | static void snd_emu10k1_pcm_efx_free(snd_pcm_t *pcm) | ||
1678 | { | ||
1679 | emu10k1_t *emu = pcm->private_data; | ||
1680 | emu->pcm_efx = NULL; | ||
1681 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
1682 | } | ||
1683 | |||
1684 | int __devinit snd_emu10k1_pcm_efx(emu10k1_t * emu, int device, snd_pcm_t ** rpcm) | ||
1685 | { | ||
1686 | snd_pcm_t *pcm; | ||
1687 | int err; | ||
1688 | |||
1689 | if (rpcm) | ||
1690 | *rpcm = NULL; | ||
1691 | |||
1692 | if ((err = snd_pcm_new(emu->card, "emu10k1 efx", device, 8, 1, &pcm)) < 0) | ||
1693 | return err; | ||
1694 | |||
1695 | pcm->private_data = emu; | ||
1696 | pcm->private_free = snd_emu10k1_pcm_efx_free; | ||
1697 | |||
1698 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops); | ||
1699 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1_capture_efx_ops); | ||
1700 | |||
1701 | pcm->info_flags = 0; | ||
1702 | strcpy(pcm->name, "Multichannel Capture/PT Playback"); | ||
1703 | emu->pcm_efx = pcm; | ||
1704 | if (rpcm) | ||
1705 | *rpcm = pcm; | ||
1706 | |||
1707 | /* EFX capture - record the "FXBUS2" channels, by default we connect the EXTINs | ||
1708 | * to these | ||
1709 | */ | ||
1710 | |||
1711 | /* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */ | ||
1712 | if (emu->audigy) { | ||
1713 | emu->efx_voices_mask[0] = 0; | ||
1714 | emu->efx_voices_mask[1] = 0xffff; | ||
1715 | } else { | ||
1716 | emu->efx_voices_mask[0] = 0xffff0000; | ||
1717 | emu->efx_voices_mask[1] = 0; | ||
1718 | } | ||
1719 | snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu)); | ||
1720 | |||
1721 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); | ||
1722 | |||
1723 | return 0; | ||
1724 | } | ||
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c new file mode 100644 index 000000000000..d990d5eb45a8 --- /dev/null +++ b/sound/pci/emu10k1/emuproc.c | |||
@@ -0,0 +1,568 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Creative Labs, Inc. | ||
4 | * Routines for control of EMU10K1 chips / proc interface routines | ||
5 | * | ||
6 | * BUGS: | ||
7 | * -- | ||
8 | * | ||
9 | * TODO: | ||
10 | * -- | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <sound/driver.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <sound/core.h> | ||
32 | #include <sound/emu10k1.h> | ||
33 | |||
34 | static void snd_emu10k1_proc_spdif_status(emu10k1_t * emu, | ||
35 | snd_info_buffer_t * buffer, | ||
36 | char *title, | ||
37 | int status_reg, | ||
38 | int rate_reg) | ||
39 | { | ||
40 | static char *clkaccy[4] = { "1000ppm", "50ppm", "variable", "unknown" }; | ||
41 | static int samplerate[16] = { 44100, 1, 48000, 32000, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; | ||
42 | static char *channel[16] = { "unspec", "left", "right", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" }; | ||
43 | static char *emphasis[8] = { "none", "50/15 usec 2 channel", "2", "3", "4", "5", "6", "7" }; | ||
44 | unsigned int status, rate = 0; | ||
45 | |||
46 | status = snd_emu10k1_ptr_read(emu, status_reg, 0); | ||
47 | if (rate_reg > 0) | ||
48 | rate = snd_emu10k1_ptr_read(emu, rate_reg, 0); | ||
49 | |||
50 | snd_iprintf(buffer, "\n%s\n", title); | ||
51 | |||
52 | snd_iprintf(buffer, "Professional Mode : %s\n", (status & SPCS_PROFESSIONAL) ? "yes" : "no"); | ||
53 | snd_iprintf(buffer, "Not Audio Data : %s\n", (status & SPCS_NOTAUDIODATA) ? "yes" : "no"); | ||
54 | snd_iprintf(buffer, "Copyright : %s\n", (status & SPCS_COPYRIGHT) ? "yes" : "no"); | ||
55 | snd_iprintf(buffer, "Emphasis : %s\n", emphasis[(status & SPCS_EMPHASISMASK) >> 3]); | ||
56 | snd_iprintf(buffer, "Mode : %i\n", (status & SPCS_MODEMASK) >> 6); | ||
57 | snd_iprintf(buffer, "Category Code : 0x%x\n", (status & SPCS_CATEGORYCODEMASK) >> 8); | ||
58 | snd_iprintf(buffer, "Generation Status : %s\n", status & SPCS_GENERATIONSTATUS ? "original" : "copy"); | ||
59 | snd_iprintf(buffer, "Source Mask : %i\n", (status & SPCS_SOURCENUMMASK) >> 16); | ||
60 | snd_iprintf(buffer, "Channel Number : %s\n", channel[(status & SPCS_CHANNELNUMMASK) >> 20]); | ||
61 | snd_iprintf(buffer, "Sample Rate : %iHz\n", samplerate[(status & SPCS_SAMPLERATEMASK) >> 24]); | ||
62 | snd_iprintf(buffer, "Clock Accuracy : %s\n", clkaccy[(status & SPCS_CLKACCYMASK) >> 28]); | ||
63 | |||
64 | if (rate_reg > 0) { | ||
65 | snd_iprintf(buffer, "S/PDIF Locked : %s\n", rate & SRCS_SPDIFLOCKED ? "on" : "off"); | ||
66 | snd_iprintf(buffer, "Rate Locked : %s\n", rate & SRCS_RATELOCKED ? "on" : "off"); | ||
67 | snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", rate & SRCS_ESTSAMPLERATE); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static void snd_emu10k1_proc_read(snd_info_entry_t *entry, | ||
72 | snd_info_buffer_t * buffer) | ||
73 | { | ||
74 | /* FIXME - output names are in emufx.c too */ | ||
75 | static char *creative_outs[32] = { | ||
76 | /* 00 */ "AC97 Left", | ||
77 | /* 01 */ "AC97 Right", | ||
78 | /* 02 */ "Optical IEC958 Left", | ||
79 | /* 03 */ "Optical IEC958 Right", | ||
80 | /* 04 */ "Center", | ||
81 | /* 05 */ "LFE", | ||
82 | /* 06 */ "Headphone Left", | ||
83 | /* 07 */ "Headphone Right", | ||
84 | /* 08 */ "Surround Left", | ||
85 | /* 09 */ "Surround Right", | ||
86 | /* 10 */ "PCM Capture Left", | ||
87 | /* 11 */ "PCM Capture Right", | ||
88 | /* 12 */ "MIC Capture", | ||
89 | /* 13 */ "AC97 Surround Left", | ||
90 | /* 14 */ "AC97 Surround Right", | ||
91 | /* 15 */ "???", | ||
92 | /* 16 */ "???", | ||
93 | /* 17 */ "Analog Center", | ||
94 | /* 18 */ "Analog LFE", | ||
95 | /* 19 */ "???", | ||
96 | /* 20 */ "???", | ||
97 | /* 21 */ "???", | ||
98 | /* 22 */ "???", | ||
99 | /* 23 */ "???", | ||
100 | /* 24 */ "???", | ||
101 | /* 25 */ "???", | ||
102 | /* 26 */ "???", | ||
103 | /* 27 */ "???", | ||
104 | /* 28 */ "???", | ||
105 | /* 29 */ "???", | ||
106 | /* 30 */ "???", | ||
107 | /* 31 */ "???" | ||
108 | }; | ||
109 | |||
110 | static char *audigy_outs[64] = { | ||
111 | /* 00 */ "Digital Front Left", | ||
112 | /* 01 */ "Digital Front Right", | ||
113 | /* 02 */ "Digital Center", | ||
114 | /* 03 */ "Digital LEF", | ||
115 | /* 04 */ "Headphone Left", | ||
116 | /* 05 */ "Headphone Right", | ||
117 | /* 06 */ "Digital Rear Left", | ||
118 | /* 07 */ "Digital Rear Right", | ||
119 | /* 08 */ "Front Left", | ||
120 | /* 09 */ "Front Right", | ||
121 | /* 10 */ "Center", | ||
122 | /* 11 */ "LFE", | ||
123 | /* 12 */ "???", | ||
124 | /* 13 */ "???", | ||
125 | /* 14 */ "Rear Left", | ||
126 | /* 15 */ "Rear Right", | ||
127 | /* 16 */ "AC97 Front Left", | ||
128 | /* 17 */ "AC97 Front Right", | ||
129 | /* 18 */ "ADC Caputre Left", | ||
130 | /* 19 */ "ADC Capture Right", | ||
131 | /* 20 */ "???", | ||
132 | /* 21 */ "???", | ||
133 | /* 22 */ "???", | ||
134 | /* 23 */ "???", | ||
135 | /* 24 */ "???", | ||
136 | /* 25 */ "???", | ||
137 | /* 26 */ "???", | ||
138 | /* 27 */ "???", | ||
139 | /* 28 */ "???", | ||
140 | /* 29 */ "???", | ||
141 | /* 30 */ "???", | ||
142 | /* 31 */ "???", | ||
143 | /* 32 */ "FXBUS2_0", | ||
144 | /* 33 */ "FXBUS2_1", | ||
145 | /* 34 */ "FXBUS2_2", | ||
146 | /* 35 */ "FXBUS2_3", | ||
147 | /* 36 */ "FXBUS2_4", | ||
148 | /* 37 */ "FXBUS2_5", | ||
149 | /* 38 */ "FXBUS2_6", | ||
150 | /* 39 */ "FXBUS2_7", | ||
151 | /* 40 */ "FXBUS2_8", | ||
152 | /* 41 */ "FXBUS2_9", | ||
153 | /* 42 */ "FXBUS2_10", | ||
154 | /* 43 */ "FXBUS2_11", | ||
155 | /* 44 */ "FXBUS2_12", | ||
156 | /* 45 */ "FXBUS2_13", | ||
157 | /* 46 */ "FXBUS2_14", | ||
158 | /* 47 */ "FXBUS2_15", | ||
159 | /* 48 */ "FXBUS2_16", | ||
160 | /* 49 */ "FXBUS2_17", | ||
161 | /* 50 */ "FXBUS2_18", | ||
162 | /* 51 */ "FXBUS2_19", | ||
163 | /* 52 */ "FXBUS2_20", | ||
164 | /* 53 */ "FXBUS2_21", | ||
165 | /* 54 */ "FXBUS2_22", | ||
166 | /* 55 */ "FXBUS2_23", | ||
167 | /* 56 */ "FXBUS2_24", | ||
168 | /* 57 */ "FXBUS2_25", | ||
169 | /* 58 */ "FXBUS2_26", | ||
170 | /* 59 */ "FXBUS2_27", | ||
171 | /* 60 */ "FXBUS2_28", | ||
172 | /* 61 */ "FXBUS2_29", | ||
173 | /* 62 */ "FXBUS2_30", | ||
174 | /* 63 */ "FXBUS2_31" | ||
175 | }; | ||
176 | |||
177 | emu10k1_t *emu = entry->private_data; | ||
178 | unsigned int val, val1; | ||
179 | int nefx = emu->audigy ? 64 : 32; | ||
180 | char **outputs = emu->audigy ? audigy_outs : creative_outs; | ||
181 | int idx; | ||
182 | |||
183 | snd_iprintf(buffer, "EMU10K1\n\n"); | ||
184 | snd_iprintf(buffer, "Card : %s\n", | ||
185 | emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative")); | ||
186 | snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size); | ||
187 | snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", (int)emu->fx8010.etram_pages.bytes / 2); | ||
188 | snd_iprintf(buffer, "\n"); | ||
189 | snd_iprintf(buffer, "Effect Send Routing :\n"); | ||
190 | for (idx = 0; idx < NUM_G; idx++) { | ||
191 | val = emu->audigy ? | ||
192 | snd_emu10k1_ptr_read(emu, A_FXRT1, idx) : | ||
193 | snd_emu10k1_ptr_read(emu, FXRT, idx); | ||
194 | val1 = emu->audigy ? | ||
195 | snd_emu10k1_ptr_read(emu, A_FXRT2, idx) : | ||
196 | 0; | ||
197 | if (emu->audigy) { | ||
198 | snd_iprintf(buffer, "Ch%i: A=%i, B=%i, C=%i, D=%i, ", | ||
199 | idx, | ||
200 | val & 0x3f, | ||
201 | (val >> 8) & 0x3f, | ||
202 | (val >> 16) & 0x3f, | ||
203 | (val >> 24) & 0x3f); | ||
204 | snd_iprintf(buffer, "E=%i, F=%i, G=%i, H=%i\n", | ||
205 | val1 & 0x3f, | ||
206 | (val1 >> 8) & 0x3f, | ||
207 | (val1 >> 16) & 0x3f, | ||
208 | (val1 >> 24) & 0x3f); | ||
209 | } else { | ||
210 | snd_iprintf(buffer, "Ch%i: A=%i, B=%i, C=%i, D=%i\n", | ||
211 | idx, | ||
212 | (val >> 16) & 0x0f, | ||
213 | (val >> 20) & 0x0f, | ||
214 | (val >> 24) & 0x0f, | ||
215 | (val >> 28) & 0x0f); | ||
216 | } | ||
217 | } | ||
218 | snd_iprintf(buffer, "\nCaptured FX Outputs :\n"); | ||
219 | for (idx = 0; idx < nefx; idx++) { | ||
220 | if (emu->efx_voices_mask[idx/32] & (1 << (idx%32))) | ||
221 | snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); | ||
222 | } | ||
223 | snd_iprintf(buffer, "\nAll FX Outputs :\n"); | ||
224 | for (idx = 0; idx < (emu->audigy ? 64 : 32); idx++) | ||
225 | snd_iprintf(buffer, " Output %02i [%s]\n", idx, outputs[idx]); | ||
226 | snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 0", SPCS0, -1); | ||
227 | snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 1", SPCS1, -1); | ||
228 | snd_emu10k1_proc_spdif_status(emu, buffer, "S/PDIF Output 2/3", SPCS2, -1); | ||
229 | snd_emu10k1_proc_spdif_status(emu, buffer, "CD-ROM S/PDIF", CDCS, CDSRCS); | ||
230 | snd_emu10k1_proc_spdif_status(emu, buffer, "General purpose S/PDIF", GPSCS, GPSRCS); | ||
231 | val = snd_emu10k1_ptr_read(emu, ZVSRCS, 0); | ||
232 | snd_iprintf(buffer, "\nZoomed Video\n"); | ||
233 | snd_iprintf(buffer, "Rate Locked : %s\n", val & SRCS_RATELOCKED ? "on" : "off"); | ||
234 | snd_iprintf(buffer, "Estimated Sample Rate : 0x%x\n", val & SRCS_ESTSAMPLERATE); | ||
235 | } | ||
236 | |||
237 | static void snd_emu10k1_proc_acode_read(snd_info_entry_t *entry, | ||
238 | snd_info_buffer_t * buffer) | ||
239 | { | ||
240 | u32 pc; | ||
241 | emu10k1_t *emu = entry->private_data; | ||
242 | |||
243 | snd_iprintf(buffer, "FX8010 Instruction List '%s'\n", emu->fx8010.name); | ||
244 | snd_iprintf(buffer, " Code dump :\n"); | ||
245 | for (pc = 0; pc < (emu->audigy ? 1024 : 512); pc++) { | ||
246 | u32 low, high; | ||
247 | |||
248 | low = snd_emu10k1_efx_read(emu, pc * 2); | ||
249 | high = snd_emu10k1_efx_read(emu, pc * 2 + 1); | ||
250 | if (emu->audigy) | ||
251 | snd_iprintf(buffer, " OP(0x%02x, 0x%03x, 0x%03x, 0x%03x, 0x%03x) /* 0x%04x: 0x%08x%08x */\n", | ||
252 | (high >> 24) & 0x0f, | ||
253 | (high >> 12) & 0x7ff, | ||
254 | (high >> 0) & 0x7ff, | ||
255 | (low >> 12) & 0x7ff, | ||
256 | (low >> 0) & 0x7ff, | ||
257 | pc, | ||
258 | high, low); | ||
259 | else | ||
260 | snd_iprintf(buffer, " OP(0x%02x, 0x%03x, 0x%03x, 0x%03x, 0x%03x) /* 0x%04x: 0x%08x%08x */\n", | ||
261 | (high >> 20) & 0x0f, | ||
262 | (high >> 10) & 0x3ff, | ||
263 | (high >> 0) & 0x3ff, | ||
264 | (low >> 10) & 0x3ff, | ||
265 | (low >> 0) & 0x3ff, | ||
266 | pc, | ||
267 | high, low); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | #define TOTAL_SIZE_GPR (0x100*4) | ||
272 | #define A_TOTAL_SIZE_GPR (0x200*4) | ||
273 | #define TOTAL_SIZE_TANKMEM_DATA (0xa0*4) | ||
274 | #define TOTAL_SIZE_TANKMEM_ADDR (0xa0*4) | ||
275 | #define A_TOTAL_SIZE_TANKMEM_DATA (0x100*4) | ||
276 | #define A_TOTAL_SIZE_TANKMEM_ADDR (0x100*4) | ||
277 | #define TOTAL_SIZE_CODE (0x200*8) | ||
278 | #define A_TOTAL_SIZE_CODE (0x400*8) | ||
279 | |||
280 | static long snd_emu10k1_fx8010_read(snd_info_entry_t *entry, void *file_private_data, | ||
281 | struct file *file, char __user *buf, | ||
282 | unsigned long count, unsigned long pos) | ||
283 | { | ||
284 | long size; | ||
285 | emu10k1_t *emu = entry->private_data; | ||
286 | unsigned int offset; | ||
287 | int tram_addr = 0; | ||
288 | |||
289 | if (!strcmp(entry->name, "fx8010_tram_addr")) { | ||
290 | offset = TANKMEMADDRREGBASE; | ||
291 | tram_addr = 1; | ||
292 | } else if (!strcmp(entry->name, "fx8010_tram_data")) { | ||
293 | offset = TANKMEMDATAREGBASE; | ||
294 | } else if (!strcmp(entry->name, "fx8010_code")) { | ||
295 | offset = emu->audigy ? A_MICROCODEBASE : MICROCODEBASE; | ||
296 | } else { | ||
297 | offset = emu->audigy ? A_FXGPREGBASE : FXGPREGBASE; | ||
298 | } | ||
299 | size = count; | ||
300 | if (pos + size > entry->size) | ||
301 | size = (long)entry->size - pos; | ||
302 | if (size > 0) { | ||
303 | unsigned int *tmp; | ||
304 | long res; | ||
305 | unsigned int idx; | ||
306 | if ((tmp = kmalloc(size + 8, GFP_KERNEL)) == NULL) | ||
307 | return -ENOMEM; | ||
308 | for (idx = 0; idx < ((pos & 3) + size + 3) >> 2; idx++) | ||
309 | if (tram_addr && emu->audigy) { | ||
310 | tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0) >> 11; | ||
311 | tmp[idx] |= snd_emu10k1_ptr_read(emu, 0x100 + idx + (pos >> 2), 0) << 20; | ||
312 | } else | ||
313 | tmp[idx] = snd_emu10k1_ptr_read(emu, offset + idx + (pos >> 2), 0); | ||
314 | if (copy_to_user(buf, ((char *)tmp) + (pos & 3), size)) | ||
315 | res = -EFAULT; | ||
316 | else { | ||
317 | res = size; | ||
318 | } | ||
319 | kfree(tmp); | ||
320 | return res; | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static void snd_emu10k1_proc_voices_read(snd_info_entry_t *entry, | ||
326 | snd_info_buffer_t * buffer) | ||
327 | { | ||
328 | emu10k1_t *emu = entry->private_data; | ||
329 | emu10k1_voice_t *voice; | ||
330 | int idx; | ||
331 | |||
332 | snd_iprintf(buffer, "ch\tuse\tpcm\tefx\tsynth\tmidi\n"); | ||
333 | for (idx = 0; idx < NUM_G; idx++) { | ||
334 | voice = &emu->voices[idx]; | ||
335 | snd_iprintf(buffer, "%i\t%i\t%i\t%i\t%i\t%i\n", | ||
336 | idx, | ||
337 | voice->use, | ||
338 | voice->pcm, | ||
339 | voice->efx, | ||
340 | voice->synth, | ||
341 | voice->midi); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | #ifdef CONFIG_SND_DEBUG | ||
346 | static void snd_emu_proc_io_reg_read(snd_info_entry_t *entry, | ||
347 | snd_info_buffer_t * buffer) | ||
348 | { | ||
349 | emu10k1_t *emu = entry->private_data; | ||
350 | unsigned long value; | ||
351 | unsigned long flags; | ||
352 | int i; | ||
353 | snd_iprintf(buffer, "IO Registers:\n\n"); | ||
354 | for(i = 0; i < 0x40; i+=4) { | ||
355 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
356 | value = inl(emu->port + i); | ||
357 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
358 | snd_iprintf(buffer, "%02X: %08lX\n", i, value); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | static void snd_emu_proc_io_reg_write(snd_info_entry_t *entry, | ||
363 | snd_info_buffer_t * buffer) | ||
364 | { | ||
365 | emu10k1_t *emu = entry->private_data; | ||
366 | unsigned long flags; | ||
367 | char line[64]; | ||
368 | u32 reg, val; | ||
369 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | ||
370 | if (sscanf(line, "%x %x", ®, &val) != 2) | ||
371 | continue; | ||
372 | if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) { | ||
373 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
374 | outl(val, emu->port + (reg & 0xfffffffc)); | ||
375 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
376 | } | ||
377 | } | ||
378 | } | ||
379 | |||
380 | static unsigned int snd_ptr_read(emu10k1_t * emu, | ||
381 | unsigned int iobase, | ||
382 | unsigned int reg, | ||
383 | unsigned int chn) | ||
384 | { | ||
385 | unsigned long flags; | ||
386 | unsigned int regptr, val; | ||
387 | |||
388 | regptr = (reg << 16) | chn; | ||
389 | |||
390 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
391 | outl(regptr, emu->port + iobase + PTR); | ||
392 | val = inl(emu->port + iobase + DATA); | ||
393 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
394 | return val; | ||
395 | } | ||
396 | |||
397 | static void snd_ptr_write(emu10k1_t *emu, | ||
398 | unsigned int iobase, | ||
399 | unsigned int reg, | ||
400 | unsigned int chn, | ||
401 | unsigned int data) | ||
402 | { | ||
403 | unsigned int regptr; | ||
404 | unsigned long flags; | ||
405 | |||
406 | regptr = (reg << 16) | chn; | ||
407 | |||
408 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
409 | outl(regptr, emu->port + iobase + PTR); | ||
410 | outl(data, emu->port + iobase + DATA); | ||
411 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
412 | } | ||
413 | |||
414 | |||
415 | static void snd_emu_proc_ptr_reg_read(snd_info_entry_t *entry, | ||
416 | snd_info_buffer_t * buffer, int iobase, int offset, int length, int voices) | ||
417 | { | ||
418 | emu10k1_t *emu = entry->private_data; | ||
419 | unsigned long value; | ||
420 | int i,j; | ||
421 | if (offset+length > 0x80) { | ||
422 | snd_iprintf(buffer, "Input values out of range\n"); | ||
423 | return; | ||
424 | } | ||
425 | snd_iprintf(buffer, "Registers 0x%x\n", iobase); | ||
426 | for(i = offset; i < offset+length; i++) { | ||
427 | snd_iprintf(buffer, "%02X: ",i); | ||
428 | for (j = 0; j < voices; j++) { | ||
429 | if(iobase == 0) | ||
430 | value = snd_ptr_read(emu, 0, i, j); | ||
431 | else | ||
432 | value = snd_ptr_read(emu, 0x20, i, j); | ||
433 | snd_iprintf(buffer, "%08lX ", value); | ||
434 | } | ||
435 | snd_iprintf(buffer, "\n"); | ||
436 | } | ||
437 | } | ||
438 | |||
439 | static void snd_emu_proc_ptr_reg_write(snd_info_entry_t *entry, | ||
440 | snd_info_buffer_t * buffer, int iobase) | ||
441 | { | ||
442 | emu10k1_t *emu = entry->private_data; | ||
443 | char line[64]; | ||
444 | unsigned int reg, channel_id , val; | ||
445 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | ||
446 | if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) | ||
447 | continue; | ||
448 | if ((reg < 0x80) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) ) | ||
449 | snd_ptr_write(emu, iobase, reg, channel_id, val); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | static void snd_emu_proc_ptr_reg_write00(snd_info_entry_t *entry, | ||
454 | snd_info_buffer_t * buffer) | ||
455 | { | ||
456 | snd_emu_proc_ptr_reg_write(entry, buffer, 0); | ||
457 | } | ||
458 | |||
459 | static void snd_emu_proc_ptr_reg_write20(snd_info_entry_t *entry, | ||
460 | snd_info_buffer_t * buffer) | ||
461 | { | ||
462 | snd_emu_proc_ptr_reg_write(entry, buffer, 0x20); | ||
463 | } | ||
464 | |||
465 | |||
466 | static void snd_emu_proc_ptr_reg_read00a(snd_info_entry_t *entry, | ||
467 | snd_info_buffer_t * buffer) | ||
468 | { | ||
469 | snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0, 0x40, 64); | ||
470 | } | ||
471 | |||
472 | static void snd_emu_proc_ptr_reg_read00b(snd_info_entry_t *entry, | ||
473 | snd_info_buffer_t * buffer) | ||
474 | { | ||
475 | snd_emu_proc_ptr_reg_read(entry, buffer, 0, 0x40, 0x40, 64); | ||
476 | } | ||
477 | |||
478 | static void snd_emu_proc_ptr_reg_read20a(snd_info_entry_t *entry, | ||
479 | snd_info_buffer_t * buffer) | ||
480 | { | ||
481 | snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0, 0x40, 4); | ||
482 | } | ||
483 | |||
484 | static void snd_emu_proc_ptr_reg_read20b(snd_info_entry_t *entry, | ||
485 | snd_info_buffer_t * buffer) | ||
486 | { | ||
487 | snd_emu_proc_ptr_reg_read(entry, buffer, 0x20, 0x40, 0x40, 4); | ||
488 | } | ||
489 | #endif | ||
490 | |||
491 | static struct snd_info_entry_ops snd_emu10k1_proc_ops_fx8010 = { | ||
492 | .read = snd_emu10k1_fx8010_read, | ||
493 | }; | ||
494 | |||
495 | int __devinit snd_emu10k1_proc_init(emu10k1_t * emu) | ||
496 | { | ||
497 | snd_info_entry_t *entry; | ||
498 | #ifdef CONFIG_SND_DEBUG | ||
499 | if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { | ||
500 | snd_info_set_text_ops(entry, emu, 1024, snd_emu_proc_io_reg_read); | ||
501 | entry->c.text.write_size = 64; | ||
502 | entry->c.text.write = snd_emu_proc_io_reg_write; | ||
503 | } | ||
504 | if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { | ||
505 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00a); | ||
506 | entry->c.text.write_size = 64; | ||
507 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; | ||
508 | } | ||
509 | if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { | ||
510 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read00b); | ||
511 | entry->c.text.write_size = 64; | ||
512 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; | ||
513 | } | ||
514 | if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { | ||
515 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20a); | ||
516 | entry->c.text.write_size = 64; | ||
517 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | ||
518 | } | ||
519 | if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { | ||
520 | snd_info_set_text_ops(entry, emu, 65536, snd_emu_proc_ptr_reg_read20b); | ||
521 | entry->c.text.write_size = 64; | ||
522 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | ||
523 | } | ||
524 | #endif | ||
525 | |||
526 | if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) | ||
527 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_read); | ||
528 | |||
529 | if (! snd_card_proc_new(emu->card, "voices", &entry)) | ||
530 | snd_info_set_text_ops(entry, emu, 2048, snd_emu10k1_proc_voices_read); | ||
531 | |||
532 | if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { | ||
533 | entry->content = SNDRV_INFO_CONTENT_DATA; | ||
534 | entry->private_data = emu; | ||
535 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | ||
536 | entry->size = emu->audigy ? A_TOTAL_SIZE_GPR : TOTAL_SIZE_GPR; | ||
537 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; | ||
538 | } | ||
539 | if (! snd_card_proc_new(emu->card, "fx8010_tram_data", &entry)) { | ||
540 | entry->content = SNDRV_INFO_CONTENT_DATA; | ||
541 | entry->private_data = emu; | ||
542 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | ||
543 | entry->size = emu->audigy ? A_TOTAL_SIZE_TANKMEM_DATA : TOTAL_SIZE_TANKMEM_DATA ; | ||
544 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; | ||
545 | } | ||
546 | if (! snd_card_proc_new(emu->card, "fx8010_tram_addr", &entry)) { | ||
547 | entry->content = SNDRV_INFO_CONTENT_DATA; | ||
548 | entry->private_data = emu; | ||
549 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | ||
550 | entry->size = emu->audigy ? A_TOTAL_SIZE_TANKMEM_ADDR : TOTAL_SIZE_TANKMEM_ADDR ; | ||
551 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; | ||
552 | } | ||
553 | if (! snd_card_proc_new(emu->card, "fx8010_code", &entry)) { | ||
554 | entry->content = SNDRV_INFO_CONTENT_DATA; | ||
555 | entry->private_data = emu; | ||
556 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | ||
557 | entry->size = emu->audigy ? A_TOTAL_SIZE_CODE : TOTAL_SIZE_CODE; | ||
558 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; | ||
559 | } | ||
560 | if (! snd_card_proc_new(emu->card, "fx8010_acode", &entry)) { | ||
561 | entry->content = SNDRV_INFO_CONTENT_TEXT; | ||
562 | entry->private_data = emu; | ||
563 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | ||
564 | entry->c.text.read_size = 128*1024; | ||
565 | entry->c.text.read = snd_emu10k1_proc_acode_read; | ||
566 | } | ||
567 | return 0; | ||
568 | } | ||
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c new file mode 100644 index 000000000000..b9d3ae0dcab7 --- /dev/null +++ b/sound/pci/emu10k1/io.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Creative Labs, Inc. | ||
4 | * Routines for control of EMU10K1 chips | ||
5 | * | ||
6 | * BUGS: | ||
7 | * -- | ||
8 | * | ||
9 | * TODO: | ||
10 | * -- | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/emu10k1.h> | ||
32 | |||
33 | unsigned int snd_emu10k1_ptr_read(emu10k1_t * emu, unsigned int reg, unsigned int chn) | ||
34 | { | ||
35 | unsigned long flags; | ||
36 | unsigned int regptr, val; | ||
37 | unsigned int mask; | ||
38 | |||
39 | mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; | ||
40 | regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); | ||
41 | |||
42 | if (reg & 0xff000000) { | ||
43 | unsigned char size, offset; | ||
44 | |||
45 | size = (reg >> 24) & 0x3f; | ||
46 | offset = (reg >> 16) & 0x1f; | ||
47 | mask = ((1 << size) - 1) << offset; | ||
48 | |||
49 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
50 | outl(regptr, emu->port + PTR); | ||
51 | val = inl(emu->port + DATA); | ||
52 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
53 | |||
54 | return (val & mask) >> offset; | ||
55 | } else { | ||
56 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
57 | outl(regptr, emu->port + PTR); | ||
58 | val = inl(emu->port + DATA); | ||
59 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
60 | return val; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | void snd_emu10k1_ptr_write(emu10k1_t *emu, unsigned int reg, unsigned int chn, unsigned int data) | ||
65 | { | ||
66 | unsigned int regptr; | ||
67 | unsigned long flags; | ||
68 | unsigned int mask; | ||
69 | |||
70 | mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; | ||
71 | regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); | ||
72 | |||
73 | if (reg & 0xff000000) { | ||
74 | unsigned char size, offset; | ||
75 | |||
76 | size = (reg >> 24) & 0x3f; | ||
77 | offset = (reg >> 16) & 0x1f; | ||
78 | mask = ((1 << size) - 1) << offset; | ||
79 | data = (data << offset) & mask; | ||
80 | |||
81 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
82 | outl(regptr, emu->port + PTR); | ||
83 | data |= inl(emu->port + DATA) & ~mask; | ||
84 | outl(data, emu->port + DATA); | ||
85 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
86 | } else { | ||
87 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
88 | outl(regptr, emu->port + PTR); | ||
89 | outl(data, emu->port + DATA); | ||
90 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | unsigned int snd_emu10k1_ptr20_read(emu10k1_t * emu, | ||
95 | unsigned int reg, | ||
96 | unsigned int chn) | ||
97 | { | ||
98 | unsigned long flags; | ||
99 | unsigned int regptr, val; | ||
100 | |||
101 | regptr = (reg << 16) | chn; | ||
102 | |||
103 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
104 | outl(regptr, emu->port + 0x20 + PTR); | ||
105 | val = inl(emu->port + 0x20 + DATA); | ||
106 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
107 | return val; | ||
108 | } | ||
109 | |||
110 | void snd_emu10k1_ptr20_write(emu10k1_t *emu, | ||
111 | unsigned int reg, | ||
112 | unsigned int chn, | ||
113 | unsigned int data) | ||
114 | { | ||
115 | unsigned int regptr; | ||
116 | unsigned long flags; | ||
117 | |||
118 | regptr = (reg << 16) | chn; | ||
119 | |||
120 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
121 | outl(regptr, emu->port + 0x20 + PTR); | ||
122 | outl(data, emu->port + 0x20 + DATA); | ||
123 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
124 | } | ||
125 | |||
126 | void snd_emu10k1_intr_enable(emu10k1_t *emu, unsigned int intrenb) | ||
127 | { | ||
128 | unsigned long flags; | ||
129 | unsigned int enable; | ||
130 | |||
131 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
132 | enable = inl(emu->port + INTE) | intrenb; | ||
133 | outl(enable, emu->port + INTE); | ||
134 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
135 | } | ||
136 | |||
137 | void snd_emu10k1_intr_disable(emu10k1_t *emu, unsigned int intrenb) | ||
138 | { | ||
139 | unsigned long flags; | ||
140 | unsigned int enable; | ||
141 | |||
142 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
143 | enable = inl(emu->port + INTE) & ~intrenb; | ||
144 | outl(enable, emu->port + INTE); | ||
145 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
146 | } | ||
147 | |||
148 | void snd_emu10k1_voice_intr_enable(emu10k1_t *emu, unsigned int voicenum) | ||
149 | { | ||
150 | unsigned long flags; | ||
151 | unsigned int val; | ||
152 | |||
153 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
154 | /* voice interrupt */ | ||
155 | if (voicenum >= 32) { | ||
156 | outl(CLIEH << 16, emu->port + PTR); | ||
157 | val = inl(emu->port + DATA); | ||
158 | val |= 1 << (voicenum - 32); | ||
159 | } else { | ||
160 | outl(CLIEL << 16, emu->port + PTR); | ||
161 | val = inl(emu->port + DATA); | ||
162 | val |= 1 << voicenum; | ||
163 | } | ||
164 | outl(val, emu->port + DATA); | ||
165 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
166 | } | ||
167 | |||
168 | void snd_emu10k1_voice_intr_disable(emu10k1_t *emu, unsigned int voicenum) | ||
169 | { | ||
170 | unsigned long flags; | ||
171 | unsigned int val; | ||
172 | |||
173 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
174 | /* voice interrupt */ | ||
175 | if (voicenum >= 32) { | ||
176 | outl(CLIEH << 16, emu->port + PTR); | ||
177 | val = inl(emu->port + DATA); | ||
178 | val &= ~(1 << (voicenum - 32)); | ||
179 | } else { | ||
180 | outl(CLIEL << 16, emu->port + PTR); | ||
181 | val = inl(emu->port + DATA); | ||
182 | val &= ~(1 << voicenum); | ||
183 | } | ||
184 | outl(val, emu->port + DATA); | ||
185 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
186 | } | ||
187 | |||
188 | void snd_emu10k1_voice_intr_ack(emu10k1_t *emu, unsigned int voicenum) | ||
189 | { | ||
190 | unsigned long flags; | ||
191 | |||
192 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
193 | /* voice interrupt */ | ||
194 | if (voicenum >= 32) { | ||
195 | outl(CLIPH << 16, emu->port + PTR); | ||
196 | voicenum = 1 << (voicenum - 32); | ||
197 | } else { | ||
198 | outl(CLIPL << 16, emu->port + PTR); | ||
199 | voicenum = 1 << voicenum; | ||
200 | } | ||
201 | outl(voicenum, emu->port + DATA); | ||
202 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
203 | } | ||
204 | |||
205 | void snd_emu10k1_voice_half_loop_intr_enable(emu10k1_t *emu, unsigned int voicenum) | ||
206 | { | ||
207 | unsigned long flags; | ||
208 | unsigned int val; | ||
209 | |||
210 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
211 | /* voice interrupt */ | ||
212 | if (voicenum >= 32) { | ||
213 | outl(HLIEH << 16, emu->port + PTR); | ||
214 | val = inl(emu->port + DATA); | ||
215 | val |= 1 << (voicenum - 32); | ||
216 | } else { | ||
217 | outl(HLIEL << 16, emu->port + PTR); | ||
218 | val = inl(emu->port + DATA); | ||
219 | val |= 1 << voicenum; | ||
220 | } | ||
221 | outl(val, emu->port + DATA); | ||
222 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
223 | } | ||
224 | |||
225 | void snd_emu10k1_voice_half_loop_intr_disable(emu10k1_t *emu, unsigned int voicenum) | ||
226 | { | ||
227 | unsigned long flags; | ||
228 | unsigned int val; | ||
229 | |||
230 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
231 | /* voice interrupt */ | ||
232 | if (voicenum >= 32) { | ||
233 | outl(HLIEH << 16, emu->port + PTR); | ||
234 | val = inl(emu->port + DATA); | ||
235 | val &= ~(1 << (voicenum - 32)); | ||
236 | } else { | ||
237 | outl(HLIEL << 16, emu->port + PTR); | ||
238 | val = inl(emu->port + DATA); | ||
239 | val &= ~(1 << voicenum); | ||
240 | } | ||
241 | outl(val, emu->port + DATA); | ||
242 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
243 | } | ||
244 | |||
245 | void snd_emu10k1_voice_half_loop_intr_ack(emu10k1_t *emu, unsigned int voicenum) | ||
246 | { | ||
247 | unsigned long flags; | ||
248 | |||
249 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
250 | /* voice interrupt */ | ||
251 | if (voicenum >= 32) { | ||
252 | outl(HLIPH << 16, emu->port + PTR); | ||
253 | voicenum = 1 << (voicenum - 32); | ||
254 | } else { | ||
255 | outl(HLIPL << 16, emu->port + PTR); | ||
256 | voicenum = 1 << voicenum; | ||
257 | } | ||
258 | outl(voicenum, emu->port + DATA); | ||
259 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
260 | } | ||
261 | |||
262 | void snd_emu10k1_voice_set_loop_stop(emu10k1_t *emu, unsigned int voicenum) | ||
263 | { | ||
264 | unsigned long flags; | ||
265 | unsigned int sol; | ||
266 | |||
267 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
268 | /* voice interrupt */ | ||
269 | if (voicenum >= 32) { | ||
270 | outl(SOLEH << 16, emu->port + PTR); | ||
271 | sol = inl(emu->port + DATA); | ||
272 | sol |= 1 << (voicenum - 32); | ||
273 | } else { | ||
274 | outl(SOLEL << 16, emu->port + PTR); | ||
275 | sol = inl(emu->port + DATA); | ||
276 | sol |= 1 << voicenum; | ||
277 | } | ||
278 | outl(sol, emu->port + DATA); | ||
279 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
280 | } | ||
281 | |||
282 | void snd_emu10k1_voice_clear_loop_stop(emu10k1_t *emu, unsigned int voicenum) | ||
283 | { | ||
284 | unsigned long flags; | ||
285 | unsigned int sol; | ||
286 | |||
287 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
288 | /* voice interrupt */ | ||
289 | if (voicenum >= 32) { | ||
290 | outl(SOLEH << 16, emu->port + PTR); | ||
291 | sol = inl(emu->port + DATA); | ||
292 | sol &= ~(1 << (voicenum - 32)); | ||
293 | } else { | ||
294 | outl(SOLEL << 16, emu->port + PTR); | ||
295 | sol = inl(emu->port + DATA); | ||
296 | sol &= ~(1 << voicenum); | ||
297 | } | ||
298 | outl(sol, emu->port + DATA); | ||
299 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
300 | } | ||
301 | |||
302 | void snd_emu10k1_wait(emu10k1_t *emu, unsigned int wait) | ||
303 | { | ||
304 | volatile unsigned count; | ||
305 | unsigned int newtime = 0, curtime; | ||
306 | |||
307 | curtime = inl(emu->port + WC) >> 6; | ||
308 | while (wait-- > 0) { | ||
309 | count = 0; | ||
310 | while (count++ < 16384) { | ||
311 | newtime = inl(emu->port + WC) >> 6; | ||
312 | if (newtime != curtime) | ||
313 | break; | ||
314 | } | ||
315 | if (count >= 16384) | ||
316 | break; | ||
317 | curtime = newtime; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | unsigned short snd_emu10k1_ac97_read(ac97_t *ac97, unsigned short reg) | ||
322 | { | ||
323 | emu10k1_t *emu = ac97->private_data; | ||
324 | unsigned long flags; | ||
325 | unsigned short val; | ||
326 | |||
327 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
328 | outb(reg, emu->port + AC97ADDRESS); | ||
329 | val = inw(emu->port + AC97DATA); | ||
330 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
331 | return val; | ||
332 | } | ||
333 | |||
334 | void snd_emu10k1_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short data) | ||
335 | { | ||
336 | emu10k1_t *emu = ac97->private_data; | ||
337 | unsigned long flags; | ||
338 | |||
339 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
340 | outb(reg, emu->port + AC97ADDRESS); | ||
341 | outw(data, emu->port + AC97DATA); | ||
342 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * convert rate to pitch | ||
347 | */ | ||
348 | |||
349 | unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate) | ||
350 | { | ||
351 | static u32 logMagTable[128] = { | ||
352 | 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2, | ||
353 | 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5, | ||
354 | 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081, | ||
355 | 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191, | ||
356 | 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7, | ||
357 | 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829, | ||
358 | 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e, | ||
359 | 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26, | ||
360 | 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d, | ||
361 | 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885, | ||
362 | 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899, | ||
363 | 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c, | ||
364 | 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3, | ||
365 | 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3, | ||
366 | 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83, | ||
367 | 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df | ||
368 | }; | ||
369 | static char logSlopeTable[128] = { | ||
370 | 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58, | ||
371 | 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53, | ||
372 | 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f, | ||
373 | 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b, | ||
374 | 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47, | ||
375 | 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44, | ||
376 | 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41, | ||
377 | 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e, | ||
378 | 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c, | ||
379 | 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39, | ||
380 | 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37, | ||
381 | 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35, | ||
382 | 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34, | ||
383 | 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32, | ||
384 | 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, | ||
385 | 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f | ||
386 | }; | ||
387 | int i; | ||
388 | |||
389 | if (rate == 0) | ||
390 | return 0; /* Bail out if no leading "1" */ | ||
391 | rate *= 11185; /* Scale 48000 to 0x20002380 */ | ||
392 | for (i = 31; i > 0; i--) { | ||
393 | if (rate & 0x80000000) { /* Detect leading "1" */ | ||
394 | return (((unsigned int) (i - 15) << 20) + | ||
395 | logMagTable[0x7f & (rate >> 24)] + | ||
396 | (0x7f & (rate >> 17)) * | ||
397 | logSlopeTable[0x7f & (rate >> 24)]); | ||
398 | } | ||
399 | rate <<= 1; | ||
400 | } | ||
401 | |||
402 | return 0; /* Should never reach this point */ | ||
403 | } | ||
404 | |||
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c new file mode 100644 index 000000000000..b81a7cafff39 --- /dev/null +++ b/sound/pci/emu10k1/irq.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Creative Labs, Inc. | ||
4 | * Routines for IRQ control of EMU10K1 chips | ||
5 | * | ||
6 | * BUGS: | ||
7 | * -- | ||
8 | * | ||
9 | * TODO: | ||
10 | * -- | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/emu10k1.h> | ||
32 | |||
33 | irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
34 | { | ||
35 | emu10k1_t *emu = dev_id; | ||
36 | unsigned int status, status2, orig_status, orig_status2; | ||
37 | int handled = 0; | ||
38 | |||
39 | while ((status = inl(emu->port + IPR)) != 0) { | ||
40 | // printk("irq - status = 0x%x\n", status); | ||
41 | orig_status = status; | ||
42 | handled = 1; | ||
43 | if (status & IPR_PCIERROR) { | ||
44 | snd_printk("interrupt: PCI error\n"); | ||
45 | snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); | ||
46 | status &= ~IPR_PCIERROR; | ||
47 | } | ||
48 | if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) { | ||
49 | if (emu->hwvol_interrupt) | ||
50 | emu->hwvol_interrupt(emu, status); | ||
51 | else | ||
52 | snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE); | ||
53 | status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE); | ||
54 | } | ||
55 | if (status & IPR_CHANNELLOOP) { | ||
56 | int voice; | ||
57 | int voice_max = status & IPR_CHANNELNUMBERMASK; | ||
58 | u32 val; | ||
59 | emu10k1_voice_t *pvoice = emu->voices; | ||
60 | |||
61 | val = snd_emu10k1_ptr_read(emu, CLIPL, 0); | ||
62 | for (voice = 0; voice <= voice_max; voice++) { | ||
63 | if (voice == 0x20) | ||
64 | val = snd_emu10k1_ptr_read(emu, CLIPH, 0); | ||
65 | if (val & 1) { | ||
66 | if (pvoice->use && pvoice->interrupt != NULL) { | ||
67 | pvoice->interrupt(emu, pvoice); | ||
68 | snd_emu10k1_voice_intr_ack(emu, voice); | ||
69 | } else { | ||
70 | snd_emu10k1_voice_intr_disable(emu, voice); | ||
71 | } | ||
72 | } | ||
73 | val >>= 1; | ||
74 | pvoice++; | ||
75 | } | ||
76 | val = snd_emu10k1_ptr_read(emu, HLIPL, 0); | ||
77 | for (voice = 0; voice <= voice_max; voice++) { | ||
78 | if (voice == 0x20) | ||
79 | val = snd_emu10k1_ptr_read(emu, HLIPH, 0); | ||
80 | if (val & 1) { | ||
81 | if (pvoice->use && pvoice->interrupt != NULL) { | ||
82 | pvoice->interrupt(emu, pvoice); | ||
83 | snd_emu10k1_voice_half_loop_intr_ack(emu, voice); | ||
84 | } else { | ||
85 | snd_emu10k1_voice_half_loop_intr_disable(emu, voice); | ||
86 | } | ||
87 | } | ||
88 | val >>= 1; | ||
89 | pvoice++; | ||
90 | } | ||
91 | status &= ~IPR_CHANNELLOOP; | ||
92 | } | ||
93 | status &= ~IPR_CHANNELNUMBERMASK; | ||
94 | if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) { | ||
95 | if (emu->capture_interrupt) | ||
96 | emu->capture_interrupt(emu, status); | ||
97 | else | ||
98 | snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE); | ||
99 | status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL); | ||
100 | } | ||
101 | if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) { | ||
102 | if (emu->capture_mic_interrupt) | ||
103 | emu->capture_mic_interrupt(emu, status); | ||
104 | else | ||
105 | snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE); | ||
106 | status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL); | ||
107 | } | ||
108 | if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) { | ||
109 | if (emu->capture_efx_interrupt) | ||
110 | emu->capture_efx_interrupt(emu, status); | ||
111 | else | ||
112 | snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE); | ||
113 | status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL); | ||
114 | } | ||
115 | if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) { | ||
116 | if (emu->midi.interrupt) | ||
117 | emu->midi.interrupt(emu, status); | ||
118 | else | ||
119 | snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE); | ||
120 | status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY); | ||
121 | } | ||
122 | if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) { | ||
123 | if (emu->midi2.interrupt) | ||
124 | emu->midi2.interrupt(emu, status); | ||
125 | else | ||
126 | snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2); | ||
127 | status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2); | ||
128 | } | ||
129 | if (status & IPR_INTERVALTIMER) { | ||
130 | if (emu->timer) | ||
131 | snd_timer_interrupt(emu->timer, emu->timer->sticks); | ||
132 | else | ||
133 | snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); | ||
134 | status &= ~IPR_INTERVALTIMER; | ||
135 | } | ||
136 | if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) { | ||
137 | if (emu->spdif_interrupt) | ||
138 | emu->spdif_interrupt(emu, status); | ||
139 | else | ||
140 | snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE); | ||
141 | status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE); | ||
142 | } | ||
143 | if (status & IPR_FXDSP) { | ||
144 | if (emu->dsp_interrupt) | ||
145 | emu->dsp_interrupt(emu); | ||
146 | else | ||
147 | snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); | ||
148 | status &= ~IPR_FXDSP; | ||
149 | } | ||
150 | if (status) { | ||
151 | unsigned int bits; | ||
152 | //snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); | ||
153 | //make sure any interrupts we don't handle are disabled: | ||
154 | bits = INTE_FXDSPENABLE | | ||
155 | INTE_PCIERRORENABLE | | ||
156 | INTE_VOLINCRENABLE | | ||
157 | INTE_VOLDECRENABLE | | ||
158 | INTE_MUTEENABLE | | ||
159 | INTE_MICBUFENABLE | | ||
160 | INTE_ADCBUFENABLE | | ||
161 | INTE_EFXBUFENABLE | | ||
162 | INTE_GPSPDIFENABLE | | ||
163 | INTE_CDSPDIFENABLE | | ||
164 | INTE_INTERVALTIMERENB | | ||
165 | INTE_MIDITXENABLE | | ||
166 | INTE_MIDIRXENABLE; | ||
167 | if (emu->audigy) | ||
168 | bits |= INTE_A_MIDITXENABLE2 | INTE_A_MIDIRXENABLE2; | ||
169 | snd_emu10k1_intr_disable(emu, bits); | ||
170 | } | ||
171 | outl(orig_status, emu->port + IPR); /* ack all */ | ||
172 | } | ||
173 | if (emu->audigy && emu->revision == 4) { /* P16V */ | ||
174 | while ((status2 = inl(emu->port + IPR2)) != 0) { | ||
175 | u32 mask = INTE2_PLAYBACK_CH_0_LOOP; /* Full Loop */ | ||
176 | emu10k1_voice_t *pvoice = &(emu->p16v_voices[0]); | ||
177 | orig_status2 = status2; | ||
178 | if(status2 & mask) { | ||
179 | if(pvoice->use) { | ||
180 | snd_pcm_period_elapsed(pvoice->epcm->substream); | ||
181 | } else { | ||
182 | snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); | ||
183 | } | ||
184 | } | ||
185 | outl(orig_status2, emu->port + IPR2); /* ack all */ | ||
186 | } | ||
187 | } | ||
188 | return IRQ_RETVAL(handled); | ||
189 | } | ||
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c new file mode 100644 index 000000000000..7a595f0dd7a1 --- /dev/null +++ b/sound/pci/emu10k1/memory.c | |||
@@ -0,0 +1,564 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Copyright (c) by Takashi Iwai <tiwai@suse.de> | ||
4 | * | ||
5 | * EMU10K1 memory page allocation (PTB area) | ||
6 | * | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <sound/driver.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/time.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/emu10k1.h> | ||
29 | |||
30 | /* page arguments of these two macros are Emu page (4096 bytes), not like | ||
31 | * aligned pages in others | ||
32 | */ | ||
33 | #define __set_ptb_entry(emu,page,addr) \ | ||
34 | (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page))) | ||
35 | |||
36 | #define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE) | ||
37 | #define MAX_ALIGN_PAGES (MAXPAGES / UNIT_PAGES) | ||
38 | /* get aligned page from offset address */ | ||
39 | #define get_aligned_page(offset) ((offset) >> PAGE_SHIFT) | ||
40 | /* get offset address from aligned page */ | ||
41 | #define aligned_page_offset(page) ((page) << PAGE_SHIFT) | ||
42 | |||
43 | #if PAGE_SIZE == 4096 | ||
44 | /* page size == EMUPAGESIZE */ | ||
45 | /* fill PTB entrie(s) corresponding to page with addr */ | ||
46 | #define set_ptb_entry(emu,page,addr) __set_ptb_entry(emu,page,addr) | ||
47 | /* fill PTB entrie(s) corresponding to page with silence pointer */ | ||
48 | #define set_silent_ptb(emu,page) __set_ptb_entry(emu,page,emu->silent_page.addr) | ||
49 | #else | ||
50 | /* fill PTB entries -- we need to fill UNIT_PAGES entries */ | ||
51 | static inline void set_ptb_entry(emu10k1_t *emu, int page, dma_addr_t addr) | ||
52 | { | ||
53 | int i; | ||
54 | page *= UNIT_PAGES; | ||
55 | for (i = 0; i < UNIT_PAGES; i++, page++) { | ||
56 | __set_ptb_entry(emu, page, addr); | ||
57 | addr += EMUPAGESIZE; | ||
58 | } | ||
59 | } | ||
60 | static inline void set_silent_ptb(emu10k1_t *emu, int page) | ||
61 | { | ||
62 | int i; | ||
63 | page *= UNIT_PAGES; | ||
64 | for (i = 0; i < UNIT_PAGES; i++, page++) | ||
65 | /* do not increment ptr */ | ||
66 | __set_ptb_entry(emu, page, emu->silent_page.addr); | ||
67 | } | ||
68 | #endif /* PAGE_SIZE */ | ||
69 | |||
70 | |||
71 | /* | ||
72 | */ | ||
73 | static int synth_alloc_pages(emu10k1_t *hw, emu10k1_memblk_t *blk); | ||
74 | static int synth_free_pages(emu10k1_t *hw, emu10k1_memblk_t *blk); | ||
75 | |||
76 | #define get_emu10k1_memblk(l,member) list_entry(l, emu10k1_memblk_t, member) | ||
77 | |||
78 | |||
79 | /* initialize emu10k1 part */ | ||
80 | static void emu10k1_memblk_init(emu10k1_memblk_t *blk) | ||
81 | { | ||
82 | blk->mapped_page = -1; | ||
83 | INIT_LIST_HEAD(&blk->mapped_link); | ||
84 | INIT_LIST_HEAD(&blk->mapped_order_link); | ||
85 | blk->map_locked = 0; | ||
86 | |||
87 | blk->first_page = get_aligned_page(blk->mem.offset); | ||
88 | blk->last_page = get_aligned_page(blk->mem.offset + blk->mem.size - 1); | ||
89 | blk->pages = blk->last_page - blk->first_page + 1; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * search empty region on PTB with the given size | ||
94 | * | ||
95 | * if an empty region is found, return the page and store the next mapped block | ||
96 | * in nextp | ||
97 | * if not found, return a negative error code. | ||
98 | */ | ||
99 | static int search_empty_map_area(emu10k1_t *emu, int npages, struct list_head **nextp) | ||
100 | { | ||
101 | int page = 0, found_page = -ENOMEM; | ||
102 | int max_size = npages; | ||
103 | int size; | ||
104 | struct list_head *candidate = &emu->mapped_link_head; | ||
105 | struct list_head *pos; | ||
106 | |||
107 | list_for_each (pos, &emu->mapped_link_head) { | ||
108 | emu10k1_memblk_t *blk = get_emu10k1_memblk(pos, mapped_link); | ||
109 | snd_assert(blk->mapped_page >= 0, continue); | ||
110 | size = blk->mapped_page - page; | ||
111 | if (size == npages) { | ||
112 | *nextp = pos; | ||
113 | return page; | ||
114 | } | ||
115 | else if (size > max_size) { | ||
116 | /* we look for the maximum empty hole */ | ||
117 | max_size = size; | ||
118 | candidate = pos; | ||
119 | found_page = page; | ||
120 | } | ||
121 | page = blk->mapped_page + blk->pages; | ||
122 | } | ||
123 | size = MAX_ALIGN_PAGES - page; | ||
124 | if (size >= max_size) { | ||
125 | *nextp = pos; | ||
126 | return page; | ||
127 | } | ||
128 | *nextp = candidate; | ||
129 | return found_page; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * map a memory block onto emu10k1's PTB | ||
134 | * | ||
135 | * call with memblk_lock held | ||
136 | */ | ||
137 | static int map_memblk(emu10k1_t *emu, emu10k1_memblk_t *blk) | ||
138 | { | ||
139 | int page, pg; | ||
140 | struct list_head *next; | ||
141 | |||
142 | page = search_empty_map_area(emu, blk->pages, &next); | ||
143 | if (page < 0) /* not found */ | ||
144 | return page; | ||
145 | /* insert this block in the proper position of mapped list */ | ||
146 | list_add_tail(&blk->mapped_link, next); | ||
147 | /* append this as a newest block in order list */ | ||
148 | list_add_tail(&blk->mapped_order_link, &emu->mapped_order_link_head); | ||
149 | blk->mapped_page = page; | ||
150 | /* fill PTB */ | ||
151 | for (pg = blk->first_page; pg <= blk->last_page; pg++) { | ||
152 | set_ptb_entry(emu, page, emu->page_addr_table[pg]); | ||
153 | page++; | ||
154 | } | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * unmap the block | ||
160 | * return the size of resultant empty pages | ||
161 | * | ||
162 | * call with memblk_lock held | ||
163 | */ | ||
164 | static int unmap_memblk(emu10k1_t *emu, emu10k1_memblk_t *blk) | ||
165 | { | ||
166 | int start_page, end_page, mpage, pg; | ||
167 | struct list_head *p; | ||
168 | emu10k1_memblk_t *q; | ||
169 | |||
170 | /* calculate the expected size of empty region */ | ||
171 | if ((p = blk->mapped_link.prev) != &emu->mapped_link_head) { | ||
172 | q = get_emu10k1_memblk(p, mapped_link); | ||
173 | start_page = q->mapped_page + q->pages; | ||
174 | } else | ||
175 | start_page = 0; | ||
176 | if ((p = blk->mapped_link.next) != &emu->mapped_link_head) { | ||
177 | q = get_emu10k1_memblk(p, mapped_link); | ||
178 | end_page = q->mapped_page; | ||
179 | } else | ||
180 | end_page = MAX_ALIGN_PAGES; | ||
181 | |||
182 | /* remove links */ | ||
183 | list_del(&blk->mapped_link); | ||
184 | list_del(&blk->mapped_order_link); | ||
185 | /* clear PTB */ | ||
186 | mpage = blk->mapped_page; | ||
187 | for (pg = blk->first_page; pg <= blk->last_page; pg++) { | ||
188 | set_silent_ptb(emu, mpage); | ||
189 | mpage++; | ||
190 | } | ||
191 | blk->mapped_page = -1; | ||
192 | return end_page - start_page; /* return the new empty size */ | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * search empty pages with the given size, and create a memory block | ||
197 | * | ||
198 | * unlike synth_alloc the memory block is aligned to the page start | ||
199 | */ | ||
200 | static emu10k1_memblk_t * | ||
201 | search_empty(emu10k1_t *emu, int size) | ||
202 | { | ||
203 | struct list_head *p; | ||
204 | emu10k1_memblk_t *blk; | ||
205 | int page, psize; | ||
206 | |||
207 | psize = get_aligned_page(size + PAGE_SIZE -1); | ||
208 | page = 0; | ||
209 | list_for_each(p, &emu->memhdr->block) { | ||
210 | blk = get_emu10k1_memblk(p, mem.list); | ||
211 | if (page + psize <= blk->first_page) | ||
212 | goto __found_pages; | ||
213 | page = blk->last_page + 1; | ||
214 | } | ||
215 | if (page + psize > emu->max_cache_pages) | ||
216 | return NULL; | ||
217 | |||
218 | __found_pages: | ||
219 | /* create a new memory block */ | ||
220 | blk = (emu10k1_memblk_t *)__snd_util_memblk_new(emu->memhdr, psize << PAGE_SHIFT, p->prev); | ||
221 | if (blk == NULL) | ||
222 | return NULL; | ||
223 | blk->mem.offset = aligned_page_offset(page); /* set aligned offset */ | ||
224 | emu10k1_memblk_init(blk); | ||
225 | return blk; | ||
226 | } | ||
227 | |||
228 | |||
229 | /* | ||
230 | * check if the given pointer is valid for pages | ||
231 | */ | ||
232 | static int is_valid_page(emu10k1_t *emu, dma_addr_t addr) | ||
233 | { | ||
234 | if (addr & ~emu->dma_mask) { | ||
235 | snd_printk("max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr); | ||
236 | return 0; | ||
237 | } | ||
238 | if (addr & (EMUPAGESIZE-1)) { | ||
239 | snd_printk("page is not aligned\n"); | ||
240 | return 0; | ||
241 | } | ||
242 | return 1; | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * map the given memory block on PTB. | ||
247 | * if the block is already mapped, update the link order. | ||
248 | * if no empty pages are found, tries to release unsed memory blocks | ||
249 | * and retry the mapping. | ||
250 | */ | ||
251 | int snd_emu10k1_memblk_map(emu10k1_t *emu, emu10k1_memblk_t *blk) | ||
252 | { | ||
253 | int err; | ||
254 | int size; | ||
255 | struct list_head *p, *nextp; | ||
256 | emu10k1_memblk_t *deleted; | ||
257 | unsigned long flags; | ||
258 | |||
259 | spin_lock_irqsave(&emu->memblk_lock, flags); | ||
260 | if (blk->mapped_page >= 0) { | ||
261 | /* update order link */ | ||
262 | list_del(&blk->mapped_order_link); | ||
263 | list_add_tail(&blk->mapped_order_link, &emu->mapped_order_link_head); | ||
264 | spin_unlock_irqrestore(&emu->memblk_lock, flags); | ||
265 | return 0; | ||
266 | } | ||
267 | if ((err = map_memblk(emu, blk)) < 0) { | ||
268 | /* no enough page - try to unmap some blocks */ | ||
269 | /* starting from the oldest block */ | ||
270 | p = emu->mapped_order_link_head.next; | ||
271 | for (; p != &emu->mapped_order_link_head; p = nextp) { | ||
272 | nextp = p->next; | ||
273 | deleted = get_emu10k1_memblk(p, mapped_order_link); | ||
274 | if (deleted->map_locked) | ||
275 | continue; | ||
276 | size = unmap_memblk(emu, deleted); | ||
277 | if (size >= blk->pages) { | ||
278 | /* ok the empty region is enough large */ | ||
279 | err = map_memblk(emu, blk); | ||
280 | break; | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | spin_unlock_irqrestore(&emu->memblk_lock, flags); | ||
285 | return err; | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * page allocation for DMA | ||
290 | */ | ||
291 | snd_util_memblk_t * | ||
292 | snd_emu10k1_alloc_pages(emu10k1_t *emu, snd_pcm_substream_t *substream) | ||
293 | { | ||
294 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
295 | struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); | ||
296 | snd_util_memhdr_t *hdr; | ||
297 | emu10k1_memblk_t *blk; | ||
298 | int page, err, idx; | ||
299 | |||
300 | snd_assert(emu, return NULL); | ||
301 | snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes < MAXPAGES * EMUPAGESIZE, return NULL); | ||
302 | hdr = emu->memhdr; | ||
303 | snd_assert(hdr, return NULL); | ||
304 | |||
305 | down(&hdr->block_mutex); | ||
306 | blk = search_empty(emu, runtime->dma_bytes); | ||
307 | if (blk == NULL) { | ||
308 | up(&hdr->block_mutex); | ||
309 | return NULL; | ||
310 | } | ||
311 | /* fill buffer addresses but pointers are not stored so that | ||
312 | * snd_free_pci_page() is not called in in synth_free() | ||
313 | */ | ||
314 | idx = 0; | ||
315 | for (page = blk->first_page; page <= blk->last_page; page++, idx++) { | ||
316 | dma_addr_t addr; | ||
317 | #ifdef CONFIG_SND_DEBUG | ||
318 | if (idx >= sgbuf->pages) { | ||
319 | printk(KERN_ERR "emu: pages overflow! (%d-%d) for %d\n", | ||
320 | blk->first_page, blk->last_page, sgbuf->pages); | ||
321 | up(&hdr->block_mutex); | ||
322 | return NULL; | ||
323 | } | ||
324 | #endif | ||
325 | addr = sgbuf->table[idx].addr; | ||
326 | if (! is_valid_page(emu, addr)) { | ||
327 | printk(KERN_ERR "emu: failure page = %d\n", idx); | ||
328 | up(&hdr->block_mutex); | ||
329 | return NULL; | ||
330 | } | ||
331 | emu->page_addr_table[page] = addr; | ||
332 | emu->page_ptr_table[page] = NULL; | ||
333 | } | ||
334 | |||
335 | /* set PTB entries */ | ||
336 | blk->map_locked = 1; /* do not unmap this block! */ | ||
337 | err = snd_emu10k1_memblk_map(emu, blk); | ||
338 | if (err < 0) { | ||
339 | __snd_util_mem_free(hdr, (snd_util_memblk_t *)blk); | ||
340 | up(&hdr->block_mutex); | ||
341 | return NULL; | ||
342 | } | ||
343 | up(&hdr->block_mutex); | ||
344 | return (snd_util_memblk_t *)blk; | ||
345 | } | ||
346 | |||
347 | |||
348 | /* | ||
349 | * release DMA buffer from page table | ||
350 | */ | ||
351 | int snd_emu10k1_free_pages(emu10k1_t *emu, snd_util_memblk_t *blk) | ||
352 | { | ||
353 | snd_assert(emu && blk, return -EINVAL); | ||
354 | return snd_emu10k1_synth_free(emu, blk); | ||
355 | } | ||
356 | |||
357 | |||
358 | /* | ||
359 | * memory allocation using multiple pages (for synth) | ||
360 | * Unlike the DMA allocation above, non-contiguous pages are assined. | ||
361 | */ | ||
362 | |||
363 | /* | ||
364 | * allocate a synth sample area | ||
365 | */ | ||
366 | snd_util_memblk_t * | ||
367 | snd_emu10k1_synth_alloc(emu10k1_t *hw, unsigned int size) | ||
368 | { | ||
369 | emu10k1_memblk_t *blk; | ||
370 | snd_util_memhdr_t *hdr = hw->memhdr; | ||
371 | |||
372 | down(&hdr->block_mutex); | ||
373 | blk = (emu10k1_memblk_t *)__snd_util_mem_alloc(hdr, size); | ||
374 | if (blk == NULL) { | ||
375 | up(&hdr->block_mutex); | ||
376 | return NULL; | ||
377 | } | ||
378 | if (synth_alloc_pages(hw, blk)) { | ||
379 | __snd_util_mem_free(hdr, (snd_util_memblk_t *)blk); | ||
380 | up(&hdr->block_mutex); | ||
381 | return NULL; | ||
382 | } | ||
383 | snd_emu10k1_memblk_map(hw, blk); | ||
384 | up(&hdr->block_mutex); | ||
385 | return (snd_util_memblk_t *)blk; | ||
386 | } | ||
387 | |||
388 | |||
389 | /* | ||
390 | * free a synth sample area | ||
391 | */ | ||
392 | int | ||
393 | snd_emu10k1_synth_free(emu10k1_t *emu, snd_util_memblk_t *memblk) | ||
394 | { | ||
395 | snd_util_memhdr_t *hdr = emu->memhdr; | ||
396 | emu10k1_memblk_t *blk = (emu10k1_memblk_t *)memblk; | ||
397 | unsigned long flags; | ||
398 | |||
399 | down(&hdr->block_mutex); | ||
400 | spin_lock_irqsave(&emu->memblk_lock, flags); | ||
401 | if (blk->mapped_page >= 0) | ||
402 | unmap_memblk(emu, blk); | ||
403 | spin_unlock_irqrestore(&emu->memblk_lock, flags); | ||
404 | synth_free_pages(emu, blk); | ||
405 | __snd_util_mem_free(hdr, memblk); | ||
406 | up(&hdr->block_mutex); | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | |||
411 | /* check new allocation range */ | ||
412 | static void get_single_page_range(snd_util_memhdr_t *hdr, emu10k1_memblk_t *blk, int *first_page_ret, int *last_page_ret) | ||
413 | { | ||
414 | struct list_head *p; | ||
415 | emu10k1_memblk_t *q; | ||
416 | int first_page, last_page; | ||
417 | first_page = blk->first_page; | ||
418 | if ((p = blk->mem.list.prev) != &hdr->block) { | ||
419 | q = get_emu10k1_memblk(p, mem.list); | ||
420 | if (q->last_page == first_page) | ||
421 | first_page++; /* first page was already allocated */ | ||
422 | } | ||
423 | last_page = blk->last_page; | ||
424 | if ((p = blk->mem.list.next) != &hdr->block) { | ||
425 | q = get_emu10k1_memblk(p, mem.list); | ||
426 | if (q->first_page == last_page) | ||
427 | last_page--; /* last page was already allocated */ | ||
428 | } | ||
429 | *first_page_ret = first_page; | ||
430 | *last_page_ret = last_page; | ||
431 | } | ||
432 | |||
433 | /* | ||
434 | * allocate kernel pages | ||
435 | */ | ||
436 | static int synth_alloc_pages(emu10k1_t *emu, emu10k1_memblk_t *blk) | ||
437 | { | ||
438 | int page, first_page, last_page; | ||
439 | struct snd_dma_buffer dmab; | ||
440 | |||
441 | emu10k1_memblk_init(blk); | ||
442 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); | ||
443 | /* allocate kernel pages */ | ||
444 | for (page = first_page; page <= last_page; page++) { | ||
445 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), | ||
446 | PAGE_SIZE, &dmab) < 0) | ||
447 | goto __fail; | ||
448 | if (! is_valid_page(emu, dmab.addr)) { | ||
449 | snd_dma_free_pages(&dmab); | ||
450 | goto __fail; | ||
451 | } | ||
452 | emu->page_addr_table[page] = dmab.addr; | ||
453 | emu->page_ptr_table[page] = dmab.area; | ||
454 | } | ||
455 | return 0; | ||
456 | |||
457 | __fail: | ||
458 | /* release allocated pages */ | ||
459 | last_page = page - 1; | ||
460 | for (page = first_page; page <= last_page; page++) { | ||
461 | dmab.area = emu->page_ptr_table[page]; | ||
462 | dmab.addr = emu->page_addr_table[page]; | ||
463 | dmab.bytes = PAGE_SIZE; | ||
464 | snd_dma_free_pages(&dmab); | ||
465 | emu->page_addr_table[page] = 0; | ||
466 | emu->page_ptr_table[page] = NULL; | ||
467 | } | ||
468 | |||
469 | return -ENOMEM; | ||
470 | } | ||
471 | |||
472 | /* | ||
473 | * free pages | ||
474 | */ | ||
475 | static int synth_free_pages(emu10k1_t *emu, emu10k1_memblk_t *blk) | ||
476 | { | ||
477 | int page, first_page, last_page; | ||
478 | struct snd_dma_buffer dmab; | ||
479 | |||
480 | get_single_page_range(emu->memhdr, blk, &first_page, &last_page); | ||
481 | dmab.dev.type = SNDRV_DMA_TYPE_DEV; | ||
482 | dmab.dev.dev = snd_dma_pci_data(emu->pci); | ||
483 | for (page = first_page; page <= last_page; page++) { | ||
484 | if (emu->page_ptr_table[page] == NULL) | ||
485 | continue; | ||
486 | dmab.area = emu->page_ptr_table[page]; | ||
487 | dmab.addr = emu->page_addr_table[page]; | ||
488 | dmab.bytes = PAGE_SIZE; | ||
489 | snd_dma_free_pages(&dmab); | ||
490 | emu->page_addr_table[page] = 0; | ||
491 | emu->page_ptr_table[page] = NULL; | ||
492 | } | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | /* calculate buffer pointer from offset address */ | ||
498 | inline static void *offset_ptr(emu10k1_t *emu, int page, int offset) | ||
499 | { | ||
500 | char *ptr; | ||
501 | snd_assert(page >= 0 && page < emu->max_cache_pages, return NULL); | ||
502 | ptr = emu->page_ptr_table[page]; | ||
503 | if (! ptr) { | ||
504 | printk("emu10k1: access to NULL ptr: page = %d\n", page); | ||
505 | return NULL; | ||
506 | } | ||
507 | ptr += offset & (PAGE_SIZE - 1); | ||
508 | return (void*)ptr; | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * bzero(blk + offset, size) | ||
513 | */ | ||
514 | int snd_emu10k1_synth_bzero(emu10k1_t *emu, snd_util_memblk_t *blk, int offset, int size) | ||
515 | { | ||
516 | int page, nextofs, end_offset, temp, temp1; | ||
517 | void *ptr; | ||
518 | emu10k1_memblk_t *p = (emu10k1_memblk_t *)blk; | ||
519 | |||
520 | offset += blk->offset & (PAGE_SIZE - 1); | ||
521 | end_offset = offset + size; | ||
522 | page = get_aligned_page(offset); | ||
523 | do { | ||
524 | nextofs = aligned_page_offset(page + 1); | ||
525 | temp = nextofs - offset; | ||
526 | temp1 = end_offset - offset; | ||
527 | if (temp1 < temp) | ||
528 | temp = temp1; | ||
529 | ptr = offset_ptr(emu, page + p->first_page, offset); | ||
530 | if (ptr) | ||
531 | memset(ptr, 0, temp); | ||
532 | offset = nextofs; | ||
533 | page++; | ||
534 | } while (offset < end_offset); | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | /* | ||
539 | * copy_from_user(blk + offset, data, size) | ||
540 | */ | ||
541 | int snd_emu10k1_synth_copy_from_user(emu10k1_t *emu, snd_util_memblk_t *blk, int offset, const char __user *data, int size) | ||
542 | { | ||
543 | int page, nextofs, end_offset, temp, temp1; | ||
544 | void *ptr; | ||
545 | emu10k1_memblk_t *p = (emu10k1_memblk_t *)blk; | ||
546 | |||
547 | offset += blk->offset & (PAGE_SIZE - 1); | ||
548 | end_offset = offset + size; | ||
549 | page = get_aligned_page(offset); | ||
550 | do { | ||
551 | nextofs = aligned_page_offset(page + 1); | ||
552 | temp = nextofs - offset; | ||
553 | temp1 = end_offset - offset; | ||
554 | if (temp1 < temp) | ||
555 | temp = temp1; | ||
556 | ptr = offset_ptr(emu, page + p->first_page, offset); | ||
557 | if (ptr && copy_from_user(ptr, data, temp)) | ||
558 | return -EFAULT; | ||
559 | offset = nextofs; | ||
560 | data += temp; | ||
561 | page++; | ||
562 | } while (offset < end_offset); | ||
563 | return 0; | ||
564 | } | ||
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c new file mode 100644 index 000000000000..d03cb2fefc9e --- /dev/null +++ b/sound/pci/emu10k1/p16v.c | |||
@@ -0,0 +1,736 @@ | |||
1 | /* | ||
2 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | ||
3 | * Driver p16v chips | ||
4 | * Version: 0.22 | ||
5 | * | ||
6 | * FEATURES currently supported: | ||
7 | * Output fixed at S32_LE, 2 channel to hw:0,0 | ||
8 | * Rates: 44.1, 48, 96, 192. | ||
9 | * | ||
10 | * Changelog: | ||
11 | * 0.8 | ||
12 | * Use separate card based buffer for periods table. | ||
13 | * 0.9 | ||
14 | * Use 2 channel output streams instead of 8 channel. | ||
15 | * (8 channel output streams might be good for ASIO type output) | ||
16 | * Corrected speaker output, so Front -> Front etc. | ||
17 | * 0.10 | ||
18 | * Fixed missed interrupts. | ||
19 | * 0.11 | ||
20 | * Add Sound card model number and names. | ||
21 | * Add Analog volume controls. | ||
22 | * 0.12 | ||
23 | * Corrected playback interrupts. Now interrupt per period, instead of half period. | ||
24 | * 0.13 | ||
25 | * Use single trigger for multichannel. | ||
26 | * 0.14 | ||
27 | * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo. | ||
28 | * 0.15 | ||
29 | * Force buffer_size / period_size == INTEGER. | ||
30 | * 0.16 | ||
31 | * Update p16v.c to work with changed alsa api. | ||
32 | * 0.17 | ||
33 | * Update p16v.c to work with changed alsa api. Removed boot_devs. | ||
34 | * 0.18 | ||
35 | * Merging with snd-emu10k1 driver. | ||
36 | * 0.19 | ||
37 | * One stereo channel at 24bit now works. | ||
38 | * 0.20 | ||
39 | * Added better register defines. | ||
40 | * 0.21 | ||
41 | * Integrated with snd-emu10k1 driver. | ||
42 | * 0.22 | ||
43 | * Removed #if 0 ... #endif | ||
44 | * | ||
45 | * | ||
46 | * BUGS: | ||
47 | * Some stability problems when unloading the snd-p16v kernel module. | ||
48 | * -- | ||
49 | * | ||
50 | * TODO: | ||
51 | * SPDIF out. | ||
52 | * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz. | ||
53 | * Currently capture fixed at 48000Hz. | ||
54 | * | ||
55 | * -- | ||
56 | * GENERAL INFO: | ||
57 | * Model: SB0240 | ||
58 | * P16V Chip: CA0151-DBS | ||
59 | * Audigy 2 Chip: CA0102-IAT | ||
60 | * AC97 Codec: STAC 9721 | ||
61 | * ADC: Philips 1361T (Stereo 24bit) | ||
62 | * DAC: CS4382-K (8-channel, 24bit, 192Khz) | ||
63 | * | ||
64 | * This code was initally based on code from ALSA's emu10k1x.c which is: | ||
65 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> | ||
66 | * | ||
67 | * This program is free software; you can redistribute it and/or modify | ||
68 | * it under the terms of the GNU General Public License as published by | ||
69 | * the Free Software Foundation; either version 2 of the License, or | ||
70 | * (at your option) any later version. | ||
71 | * | ||
72 | * This program is distributed in the hope that it will be useful, | ||
73 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
74 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
75 | * GNU General Public License for more details. | ||
76 | * | ||
77 | * You should have received a copy of the GNU General Public License | ||
78 | * along with this program; if not, write to the Free Software | ||
79 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
80 | * | ||
81 | */ | ||
82 | #include <sound/driver.h> | ||
83 | #include <linux/delay.h> | ||
84 | #include <linux/init.h> | ||
85 | #include <linux/interrupt.h> | ||
86 | #include <linux/pci.h> | ||
87 | #include <linux/slab.h> | ||
88 | #include <linux/moduleparam.h> | ||
89 | #include <sound/core.h> | ||
90 | #include <sound/initval.h> | ||
91 | #include <sound/pcm.h> | ||
92 | #include <sound/ac97_codec.h> | ||
93 | #include <sound/info.h> | ||
94 | #include <sound/emu10k1.h> | ||
95 | #include "p16v.h" | ||
96 | |||
97 | #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ | ||
98 | #define PCM_FRONT_CHANNEL 0 | ||
99 | #define PCM_REAR_CHANNEL 1 | ||
100 | #define PCM_CENTER_LFE_CHANNEL 2 | ||
101 | #define PCM_UNKNOWN_CHANNEL 3 | ||
102 | #define CONTROL_FRONT_CHANNEL 0 | ||
103 | #define CONTROL_REAR_CHANNEL 3 | ||
104 | #define CONTROL_CENTER_LFE_CHANNEL 1 | ||
105 | #define CONTROL_UNKNOWN_CHANNEL 2 | ||
106 | |||
107 | /* Card IDs: | ||
108 | * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2002 -> Audigy2 ZS 7.1 Model:SB0350 | ||
109 | * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1007 -> Audigy2 6.1 Model:SB0240 | ||
110 | * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:1002 -> Audigy2 Platinum Model:SB msb0240230009266 | ||
111 | * Class 0401: 1102:0004 (rev 04) Subsystem: 1102:2007 -> Audigy4 Pro Model:SB0380 M1SB0380472001901E | ||
112 | * | ||
113 | */ | ||
114 | |||
115 | /* hardware definition */ | ||
116 | static snd_pcm_hardware_t snd_p16v_playback_hw = { | ||
117 | .info = (SNDRV_PCM_INFO_MMAP | | ||
118 | SNDRV_PCM_INFO_INTERLEAVED | | ||
119 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
120 | SNDRV_PCM_INFO_MMAP_VALID), | ||
121 | .formats = SNDRV_PCM_FMTBIT_S32_LE, /* Only supports 24-bit samples padded to 32 bits. */ | ||
122 | .rates = SNDRV_PCM_RATE_192000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_48000 , | ||
123 | .rate_min = 48000, | ||
124 | .rate_max = 192000, | ||
125 | .channels_min = 8, | ||
126 | .channels_max = 8, | ||
127 | .buffer_bytes_max = (32*1024), | ||
128 | .period_bytes_min = 64, | ||
129 | .period_bytes_max = (16*1024), | ||
130 | .periods_min = 2, | ||
131 | .periods_max = 8, | ||
132 | .fifo_size = 0, | ||
133 | }; | ||
134 | |||
135 | static void snd_p16v_pcm_free_substream(snd_pcm_runtime_t *runtime) | ||
136 | { | ||
137 | snd_pcm_t *epcm = runtime->private_data; | ||
138 | |||
139 | if (epcm) { | ||
140 | //snd_printk("epcm free: %p\n", epcm); | ||
141 | kfree(epcm); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /* open_playback callback */ | ||
146 | static int snd_p16v_pcm_open_playback_channel(snd_pcm_substream_t *substream, int channel_id) | ||
147 | { | ||
148 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
149 | emu10k1_voice_t *channel = &(emu->p16v_voices[channel_id]); | ||
150 | emu10k1_pcm_t *epcm; | ||
151 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
152 | int err; | ||
153 | |||
154 | epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); | ||
155 | //snd_printk("epcm kcalloc: %p\n", epcm); | ||
156 | |||
157 | if (epcm == NULL) | ||
158 | return -ENOMEM; | ||
159 | epcm->emu = emu; | ||
160 | epcm->substream = substream; | ||
161 | //snd_printk("epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); | ||
162 | |||
163 | runtime->private_data = epcm; | ||
164 | runtime->private_free = snd_p16v_pcm_free_substream; | ||
165 | |||
166 | runtime->hw = snd_p16v_playback_hw; | ||
167 | |||
168 | channel->emu = emu; | ||
169 | channel->number = channel_id; | ||
170 | |||
171 | channel->use=1; | ||
172 | //snd_printk("p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use); | ||
173 | //printk("open:channel_id=%d, chip=%p, channel=%p\n",channel_id, chip, channel); | ||
174 | //channel->interrupt = snd_p16v_pcm_channel_interrupt; | ||
175 | channel->epcm=epcm; | ||
176 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | ||
177 | return err; | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* close callback */ | ||
183 | static int snd_p16v_pcm_close_playback(snd_pcm_substream_t *substream) | ||
184 | { | ||
185 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
186 | //snd_pcm_runtime_t *runtime = substream->runtime; | ||
187 | //emu10k1_pcm_t *epcm = runtime->private_data; | ||
188 | emu->p16v_voices[substream->pcm->device - emu->p16v_device_offset].use=0; | ||
189 | /* FIXME: maybe zero others */ | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int snd_p16v_pcm_open_playback_front(snd_pcm_substream_t *substream) | ||
194 | { | ||
195 | return snd_p16v_pcm_open_playback_channel(substream, PCM_FRONT_CHANNEL); | ||
196 | } | ||
197 | |||
198 | /* hw_params callback */ | ||
199 | static int snd_p16v_pcm_hw_params_playback(snd_pcm_substream_t *substream, | ||
200 | snd_pcm_hw_params_t * hw_params) | ||
201 | { | ||
202 | int result; | ||
203 | //snd_printk("hw_params alloc: substream=%p\n", substream); | ||
204 | result = snd_pcm_lib_malloc_pages(substream, | ||
205 | params_buffer_bytes(hw_params)); | ||
206 | //snd_printk("hw_params alloc: result=%d\n", result); | ||
207 | //dump_stack(); | ||
208 | return result; | ||
209 | } | ||
210 | |||
211 | /* hw_free callback */ | ||
212 | static int snd_p16v_pcm_hw_free_playback(snd_pcm_substream_t *substream) | ||
213 | { | ||
214 | int result; | ||
215 | //snd_printk("hw_params free: substream=%p\n", substream); | ||
216 | result = snd_pcm_lib_free_pages(substream); | ||
217 | //snd_printk("hw_params free: result=%d\n", result); | ||
218 | //dump_stack(); | ||
219 | return result; | ||
220 | } | ||
221 | |||
222 | /* prepare playback callback */ | ||
223 | static int snd_p16v_pcm_prepare_playback(snd_pcm_substream_t *substream) | ||
224 | { | ||
225 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
226 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
227 | //emu10k1_pcm_t *epcm = runtime->private_data; | ||
228 | int channel = substream->pcm->device - emu->p16v_device_offset; | ||
229 | u32 *table_base = (u32 *)(emu->p16v_buffer.area+(8*16*channel)); | ||
230 | u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); | ||
231 | int i; | ||
232 | u32 tmp; | ||
233 | |||
234 | //snd_printk("prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, periods=%u, frames_to_bytes=%d\n",channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); | ||
235 | //snd_printk("dma_addr=%x, dma_area=%p, table_base=%p\n",runtime->dma_addr, runtime->dma_area, table_base); | ||
236 | //snd_printk("dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n",emu->p16v_buffer.addr, emu->p16v_buffer.area, emu->p16v_buffer.bytes); | ||
237 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, channel); | ||
238 | switch (runtime->rate) { | ||
239 | case 44100: | ||
240 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x8000); /* FIXME: This will change the capture rate as well! */ | ||
241 | break; | ||
242 | case 48000: | ||
243 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x0000); /* FIXME: This will change the capture rate as well! */ | ||
244 | break; | ||
245 | case 96000: | ||
246 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x4000); /* FIXME: This will change the capture rate as well! */ | ||
247 | break; | ||
248 | case 192000: | ||
249 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, (tmp & ~0xe000) | 0x2000); /* FIXME: This will change the capture rate as well! */ | ||
250 | break; | ||
251 | default: | ||
252 | snd_emu10k1_ptr_write(emu, A_SPDIF_SAMPLERATE, channel, 0x0000); /* FIXME: This will change the capture rate as well! */ | ||
253 | break; | ||
254 | } | ||
255 | /* FIXME: Check emu->buffer.size before actually writing to it. */ | ||
256 | for(i=0; i < runtime->periods; i++) { | ||
257 | table_base[i*2]=runtime->dma_addr+(i*period_size_bytes); | ||
258 | table_base[(i*2)+1]=period_size_bytes<<16; | ||
259 | } | ||
260 | |||
261 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_ADDR, channel, emu->p16v_buffer.addr+(8*16*channel)); | ||
262 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_SIZE, channel, (runtime->periods - 1) << 19); | ||
263 | snd_emu10k1_ptr20_write(emu, PLAYBACK_LIST_PTR, channel, 0); | ||
264 | snd_emu10k1_ptr20_write(emu, PLAYBACK_DMA_ADDR, channel, runtime->dma_addr); | ||
265 | snd_emu10k1_ptr20_write(emu, PLAYBACK_PERIOD_SIZE, channel, frames_to_bytes(runtime, runtime->period_size)<<16); // buffer size in bytes | ||
266 | snd_emu10k1_ptr20_write(emu, PLAYBACK_POINTER, channel, 0); | ||
267 | snd_emu10k1_ptr20_write(emu, 0x07, channel, 0x0); | ||
268 | snd_emu10k1_ptr20_write(emu, 0x08, channel, 0); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static void snd_p16v_intr_enable(emu10k1_t *emu, unsigned int intrenb) | ||
274 | { | ||
275 | unsigned long flags; | ||
276 | unsigned int enable; | ||
277 | |||
278 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
279 | enable = inl(emu->port + INTE2) | intrenb; | ||
280 | outl(enable, emu->port + INTE2); | ||
281 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
282 | } | ||
283 | |||
284 | static void snd_p16v_intr_disable(emu10k1_t *emu, unsigned int intrenb) | ||
285 | { | ||
286 | unsigned long flags; | ||
287 | unsigned int disable; | ||
288 | |||
289 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
290 | disable = inl(emu->port + INTE2) & (~intrenb); | ||
291 | outl(disable, emu->port + INTE2); | ||
292 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
293 | } | ||
294 | |||
295 | /* trigger_playback callback */ | ||
296 | static int snd_p16v_pcm_trigger_playback(snd_pcm_substream_t *substream, | ||
297 | int cmd) | ||
298 | { | ||
299 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
300 | snd_pcm_runtime_t *runtime; | ||
301 | emu10k1_pcm_t *epcm; | ||
302 | int channel; | ||
303 | int result = 0; | ||
304 | struct list_head *pos; | ||
305 | snd_pcm_substream_t *s; | ||
306 | u32 basic = 0; | ||
307 | u32 inte = 0; | ||
308 | int running=0; | ||
309 | |||
310 | switch (cmd) { | ||
311 | case SNDRV_PCM_TRIGGER_START: | ||
312 | running=1; | ||
313 | break; | ||
314 | case SNDRV_PCM_TRIGGER_STOP: | ||
315 | default: | ||
316 | running=0; | ||
317 | break; | ||
318 | } | ||
319 | snd_pcm_group_for_each(pos, substream) { | ||
320 | s = snd_pcm_group_substream_entry(pos); | ||
321 | runtime = s->runtime; | ||
322 | epcm = runtime->private_data; | ||
323 | channel = substream->pcm->device-emu->p16v_device_offset; | ||
324 | //snd_printk("p16v channel=%d\n",channel); | ||
325 | epcm->running = running; | ||
326 | basic |= (0x1<<channel); | ||
327 | inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel); | ||
328 | snd_pcm_trigger_done(s, substream); | ||
329 | } | ||
330 | //snd_printk("basic=0x%x, inte=0x%x\n",basic, inte); | ||
331 | |||
332 | switch (cmd) { | ||
333 | case SNDRV_PCM_TRIGGER_START: | ||
334 | snd_p16v_intr_enable(emu, inte); | ||
335 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)| (basic)); | ||
336 | break; | ||
337 | case SNDRV_PCM_TRIGGER_STOP: | ||
338 | snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(basic)); | ||
339 | snd_p16v_intr_disable(emu, inte); | ||
340 | break; | ||
341 | default: | ||
342 | result = -EINVAL; | ||
343 | break; | ||
344 | } | ||
345 | return result; | ||
346 | } | ||
347 | |||
348 | /* pointer_playback callback */ | ||
349 | static snd_pcm_uframes_t | ||
350 | snd_p16v_pcm_pointer_playback(snd_pcm_substream_t *substream) | ||
351 | { | ||
352 | emu10k1_t *emu = snd_pcm_substream_chip(substream); | ||
353 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
354 | emu10k1_pcm_t *epcm = runtime->private_data; | ||
355 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; | ||
356 | int channel = substream->pcm->device - emu->p16v_device_offset; | ||
357 | if (!epcm->running) | ||
358 | return 0; | ||
359 | |||
360 | ptr3 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel); | ||
361 | ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel); | ||
362 | ptr4 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel); | ||
363 | if (ptr3 != ptr4) ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel); | ||
364 | ptr2 = bytes_to_frames(runtime, ptr1); | ||
365 | ptr2+= (ptr4 >> 3) * runtime->period_size; | ||
366 | ptr=ptr2; | ||
367 | if (ptr >= runtime->buffer_size) | ||
368 | ptr -= runtime->buffer_size; | ||
369 | |||
370 | return ptr; | ||
371 | } | ||
372 | |||
373 | /* operators */ | ||
374 | static snd_pcm_ops_t snd_p16v_playback_front_ops = { | ||
375 | .open = snd_p16v_pcm_open_playback_front, | ||
376 | .close = snd_p16v_pcm_close_playback, | ||
377 | .ioctl = snd_pcm_lib_ioctl, | ||
378 | .hw_params = snd_p16v_pcm_hw_params_playback, | ||
379 | .hw_free = snd_p16v_pcm_hw_free_playback, | ||
380 | .prepare = snd_p16v_pcm_prepare_playback, | ||
381 | .trigger = snd_p16v_pcm_trigger_playback, | ||
382 | .pointer = snd_p16v_pcm_pointer_playback, | ||
383 | }; | ||
384 | |||
385 | int snd_p16v_free(emu10k1_t *chip) | ||
386 | { | ||
387 | // release the data | ||
388 | if (chip->p16v_buffer.area) { | ||
389 | snd_dma_free_pages(&chip->p16v_buffer); | ||
390 | //snd_printk("period lables free: %p\n", &chip->p16v_buffer); | ||
391 | } | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static void snd_p16v_pcm_free(snd_pcm_t *pcm) | ||
396 | { | ||
397 | emu10k1_t *emu = pcm->private_data; | ||
398 | //snd_printk("snd_p16v_pcm_free pcm: called\n"); | ||
399 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
400 | emu->pcm = NULL; | ||
401 | } | ||
402 | |||
403 | int snd_p16v_pcm(emu10k1_t *emu, int device, snd_pcm_t **rpcm) | ||
404 | { | ||
405 | snd_pcm_t *pcm; | ||
406 | snd_pcm_substream_t *substream; | ||
407 | int err; | ||
408 | int capture=0; | ||
409 | |||
410 | //snd_printk("snd_p16v_pcm called. device=%d\n", device); | ||
411 | emu->p16v_device_offset = device; | ||
412 | if (rpcm) | ||
413 | *rpcm = NULL; | ||
414 | //if (device == 0) capture=1; | ||
415 | if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) | ||
416 | return err; | ||
417 | |||
418 | pcm->private_data = emu; | ||
419 | pcm->private_free = snd_p16v_pcm_free; | ||
420 | |||
421 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops); | ||
422 | |||
423 | pcm->info_flags = 0; | ||
424 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | ||
425 | strcpy(pcm->name, "p16v"); | ||
426 | emu->pcm = pcm; | ||
427 | |||
428 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | ||
429 | substream; | ||
430 | substream = substream->next) { | ||
431 | if ((err = snd_pcm_lib_preallocate_pages(substream, | ||
432 | SNDRV_DMA_TYPE_DEV, | ||
433 | snd_dma_pci_data(emu->pci), | ||
434 | 64*1024, 64*1024)) < 0) /* FIXME: 32*1024 for sound buffer, between 32and64 for Periods table. */ | ||
435 | return err; | ||
436 | //snd_printk("preallocate playback substream: err=%d\n", err); | ||
437 | } | ||
438 | |||
439 | for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; | ||
440 | substream; | ||
441 | substream = substream->next) { | ||
442 | if ((err = snd_pcm_lib_preallocate_pages(substream, | ||
443 | SNDRV_DMA_TYPE_DEV, | ||
444 | snd_dma_pci_data(emu->pci), | ||
445 | 64*1024, 64*1024)) < 0) | ||
446 | return err; | ||
447 | //snd_printk("preallocate capture substream: err=%d\n", err); | ||
448 | } | ||
449 | |||
450 | if (rpcm) | ||
451 | *rpcm = pcm; | ||
452 | |||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int snd_p16v_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
457 | { | ||
458 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
459 | uinfo->count = 2; | ||
460 | uinfo->value.integer.min = 0; | ||
461 | uinfo->value.integer.max = 255; | ||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static int snd_p16v_volume_get(snd_kcontrol_t * kcontrol, | ||
466 | snd_ctl_elem_value_t * ucontrol, int reg, int high_low) | ||
467 | { | ||
468 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
469 | u32 value; | ||
470 | |||
471 | value = snd_emu10k1_ptr20_read(emu, reg, high_low); | ||
472 | if (high_low == 1) { | ||
473 | ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */ | ||
474 | ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */ | ||
475 | } else { | ||
476 | ucontrol->value.integer.value[0] = 0xff - ((value >> 8) & 0xff); /* Left */ | ||
477 | ucontrol->value.integer.value[1] = 0xff - ((value >> 0) & 0xff); /* Right */ | ||
478 | } | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static int snd_p16v_volume_get_spdif_front(snd_kcontrol_t * kcontrol, | ||
483 | snd_ctl_elem_value_t * ucontrol) | ||
484 | { | ||
485 | int high_low = 0; | ||
486 | int reg = PLAYBACK_VOLUME_MIXER7; | ||
487 | return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low); | ||
488 | } | ||
489 | |||
490 | static int snd_p16v_volume_get_spdif_center_lfe(snd_kcontrol_t * kcontrol, | ||
491 | snd_ctl_elem_value_t * ucontrol) | ||
492 | { | ||
493 | int high_low = 1; | ||
494 | int reg = PLAYBACK_VOLUME_MIXER7; | ||
495 | return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low); | ||
496 | } | ||
497 | static int snd_p16v_volume_get_spdif_unknown(snd_kcontrol_t * kcontrol, | ||
498 | snd_ctl_elem_value_t * ucontrol) | ||
499 | { | ||
500 | int high_low = 0; | ||
501 | int reg = PLAYBACK_VOLUME_MIXER8; | ||
502 | return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low); | ||
503 | } | ||
504 | static int snd_p16v_volume_get_spdif_rear(snd_kcontrol_t * kcontrol, | ||
505 | snd_ctl_elem_value_t * ucontrol) | ||
506 | { | ||
507 | int high_low = 1; | ||
508 | int reg = PLAYBACK_VOLUME_MIXER8; | ||
509 | return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low); | ||
510 | } | ||
511 | |||
512 | static int snd_p16v_volume_get_analog_front(snd_kcontrol_t * kcontrol, | ||
513 | snd_ctl_elem_value_t * ucontrol) | ||
514 | { | ||
515 | int high_low = 0; | ||
516 | int reg = PLAYBACK_VOLUME_MIXER9; | ||
517 | return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low); | ||
518 | } | ||
519 | |||
520 | static int snd_p16v_volume_get_analog_center_lfe(snd_kcontrol_t * kcontrol, | ||
521 | snd_ctl_elem_value_t * ucontrol) | ||
522 | { | ||
523 | int high_low = 1; | ||
524 | int reg = PLAYBACK_VOLUME_MIXER9; | ||
525 | return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low); | ||
526 | } | ||
527 | static int snd_p16v_volume_get_analog_rear(snd_kcontrol_t * kcontrol, | ||
528 | snd_ctl_elem_value_t * ucontrol) | ||
529 | { | ||
530 | int high_low = 1; | ||
531 | int reg = PLAYBACK_VOLUME_MIXER10; | ||
532 | return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low); | ||
533 | } | ||
534 | |||
535 | static int snd_p16v_volume_get_analog_unknown(snd_kcontrol_t * kcontrol, | ||
536 | snd_ctl_elem_value_t * ucontrol) | ||
537 | { | ||
538 | int high_low = 0; | ||
539 | int reg = PLAYBACK_VOLUME_MIXER10; | ||
540 | return snd_p16v_volume_get(kcontrol, ucontrol, reg, high_low); | ||
541 | } | ||
542 | |||
543 | static int snd_p16v_volume_put(snd_kcontrol_t * kcontrol, | ||
544 | snd_ctl_elem_value_t * ucontrol, int reg, int high_low) | ||
545 | { | ||
546 | emu10k1_t *emu = snd_kcontrol_chip(kcontrol); | ||
547 | u32 value; | ||
548 | value = snd_emu10k1_ptr20_read(emu, reg, 0); | ||
549 | //value = value & 0xffff; | ||
550 | if (high_low == 1) { | ||
551 | value &= 0xffff; | ||
552 | value = value | ((0xff - ucontrol->value.integer.value[0]) << 24) | ((0xff - ucontrol->value.integer.value[1]) << 16); | ||
553 | } else { | ||
554 | value &= 0xffff0000; | ||
555 | value = value | ((0xff - ucontrol->value.integer.value[0]) << 8) | ((0xff - ucontrol->value.integer.value[1]) ); | ||
556 | } | ||
557 | snd_emu10k1_ptr20_write(emu, reg, 0, value); | ||
558 | return 1; | ||
559 | } | ||
560 | |||
561 | static int snd_p16v_volume_put_spdif_front(snd_kcontrol_t * kcontrol, | ||
562 | snd_ctl_elem_value_t * ucontrol) | ||
563 | { | ||
564 | int high_low = 0; | ||
565 | int reg = PLAYBACK_VOLUME_MIXER7; | ||
566 | return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low); | ||
567 | } | ||
568 | |||
569 | static int snd_p16v_volume_put_spdif_center_lfe(snd_kcontrol_t * kcontrol, | ||
570 | snd_ctl_elem_value_t * ucontrol) | ||
571 | { | ||
572 | int high_low = 1; | ||
573 | int reg = PLAYBACK_VOLUME_MIXER7; | ||
574 | return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low); | ||
575 | } | ||
576 | |||
577 | static int snd_p16v_volume_put_spdif_unknown(snd_kcontrol_t * kcontrol, | ||
578 | snd_ctl_elem_value_t * ucontrol) | ||
579 | { | ||
580 | int high_low = 0; | ||
581 | int reg = PLAYBACK_VOLUME_MIXER8; | ||
582 | return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low); | ||
583 | } | ||
584 | |||
585 | static int snd_p16v_volume_put_spdif_rear(snd_kcontrol_t * kcontrol, | ||
586 | snd_ctl_elem_value_t * ucontrol) | ||
587 | { | ||
588 | int high_low = 1; | ||
589 | int reg = PLAYBACK_VOLUME_MIXER8; | ||
590 | return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low); | ||
591 | } | ||
592 | |||
593 | static int snd_p16v_volume_put_analog_front(snd_kcontrol_t * kcontrol, | ||
594 | snd_ctl_elem_value_t * ucontrol) | ||
595 | { | ||
596 | int high_low = 0; | ||
597 | int reg = PLAYBACK_VOLUME_MIXER9; | ||
598 | return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low); | ||
599 | } | ||
600 | |||
601 | static int snd_p16v_volume_put_analog_center_lfe(snd_kcontrol_t * kcontrol, | ||
602 | snd_ctl_elem_value_t * ucontrol) | ||
603 | { | ||
604 | int high_low = 1; | ||
605 | int reg = PLAYBACK_VOLUME_MIXER9; | ||
606 | return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low); | ||
607 | } | ||
608 | |||
609 | static int snd_p16v_volume_put_analog_rear(snd_kcontrol_t * kcontrol, | ||
610 | snd_ctl_elem_value_t * ucontrol) | ||
611 | { | ||
612 | int high_low = 1; | ||
613 | int reg = PLAYBACK_VOLUME_MIXER10; | ||
614 | return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low); | ||
615 | } | ||
616 | |||
617 | static int snd_p16v_volume_put_analog_unknown(snd_kcontrol_t * kcontrol, | ||
618 | snd_ctl_elem_value_t * ucontrol) | ||
619 | { | ||
620 | int high_low = 0; | ||
621 | int reg = PLAYBACK_VOLUME_MIXER10; | ||
622 | return snd_p16v_volume_put(kcontrol, ucontrol, reg, high_low); | ||
623 | } | ||
624 | |||
625 | static snd_kcontrol_new_t snd_p16v_volume_control_analog_front = | ||
626 | { | ||
627 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
628 | .name = "HD Analog Front Volume", | ||
629 | .info = snd_p16v_volume_info, | ||
630 | .get = snd_p16v_volume_get_analog_front, | ||
631 | .put = snd_p16v_volume_put_analog_front | ||
632 | }; | ||
633 | |||
634 | static snd_kcontrol_new_t snd_p16v_volume_control_analog_center_lfe = | ||
635 | { | ||
636 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
637 | .name = "HD Analog Center/LFE Volume", | ||
638 | .info = snd_p16v_volume_info, | ||
639 | .get = snd_p16v_volume_get_analog_center_lfe, | ||
640 | .put = snd_p16v_volume_put_analog_center_lfe | ||
641 | }; | ||
642 | |||
643 | static snd_kcontrol_new_t snd_p16v_volume_control_analog_unknown = | ||
644 | { | ||
645 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
646 | .name = "HD Analog Unknown Volume", | ||
647 | .info = snd_p16v_volume_info, | ||
648 | .get = snd_p16v_volume_get_analog_unknown, | ||
649 | .put = snd_p16v_volume_put_analog_unknown | ||
650 | }; | ||
651 | |||
652 | static snd_kcontrol_new_t snd_p16v_volume_control_analog_rear = | ||
653 | { | ||
654 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
655 | .name = "HD Analog Rear Volume", | ||
656 | .info = snd_p16v_volume_info, | ||
657 | .get = snd_p16v_volume_get_analog_rear, | ||
658 | .put = snd_p16v_volume_put_analog_rear | ||
659 | }; | ||
660 | |||
661 | static snd_kcontrol_new_t snd_p16v_volume_control_spdif_front = | ||
662 | { | ||
663 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
664 | .name = "HD SPDIF Front Volume", | ||
665 | .info = snd_p16v_volume_info, | ||
666 | .get = snd_p16v_volume_get_spdif_front, | ||
667 | .put = snd_p16v_volume_put_spdif_front | ||
668 | }; | ||
669 | |||
670 | static snd_kcontrol_new_t snd_p16v_volume_control_spdif_center_lfe = | ||
671 | { | ||
672 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
673 | .name = "HD SPDIF Center/LFE Volume", | ||
674 | .info = snd_p16v_volume_info, | ||
675 | .get = snd_p16v_volume_get_spdif_center_lfe, | ||
676 | .put = snd_p16v_volume_put_spdif_center_lfe | ||
677 | }; | ||
678 | |||
679 | static snd_kcontrol_new_t snd_p16v_volume_control_spdif_unknown = | ||
680 | { | ||
681 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
682 | .name = "HD SPDIF Unknown Volume", | ||
683 | .info = snd_p16v_volume_info, | ||
684 | .get = snd_p16v_volume_get_spdif_unknown, | ||
685 | .put = snd_p16v_volume_put_spdif_unknown | ||
686 | }; | ||
687 | |||
688 | static snd_kcontrol_new_t snd_p16v_volume_control_spdif_rear = | ||
689 | { | ||
690 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
691 | .name = "HD SPDIF Rear Volume", | ||
692 | .info = snd_p16v_volume_info, | ||
693 | .get = snd_p16v_volume_get_spdif_rear, | ||
694 | .put = snd_p16v_volume_put_spdif_rear | ||
695 | }; | ||
696 | |||
697 | int snd_p16v_mixer(emu10k1_t *emu) | ||
698 | { | ||
699 | int err; | ||
700 | snd_kcontrol_t *kctl; | ||
701 | snd_card_t *card = emu->card; | ||
702 | if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_front, emu)) == NULL) | ||
703 | return -ENOMEM; | ||
704 | if ((err = snd_ctl_add(card, kctl))) | ||
705 | return err; | ||
706 | if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_rear, emu)) == NULL) | ||
707 | return -ENOMEM; | ||
708 | if ((err = snd_ctl_add(card, kctl))) | ||
709 | return err; | ||
710 | if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_center_lfe, emu)) == NULL) | ||
711 | return -ENOMEM; | ||
712 | if ((err = snd_ctl_add(card, kctl))) | ||
713 | return err; | ||
714 | if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_analog_unknown, emu)) == NULL) | ||
715 | return -ENOMEM; | ||
716 | if ((err = snd_ctl_add(card, kctl))) | ||
717 | return err; | ||
718 | if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_front, emu)) == NULL) | ||
719 | return -ENOMEM; | ||
720 | if ((err = snd_ctl_add(card, kctl))) | ||
721 | return err; | ||
722 | if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_rear, emu)) == NULL) | ||
723 | return -ENOMEM; | ||
724 | if ((err = snd_ctl_add(card, kctl))) | ||
725 | return err; | ||
726 | if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_center_lfe, emu)) == NULL) | ||
727 | return -ENOMEM; | ||
728 | if ((err = snd_ctl_add(card, kctl))) | ||
729 | return err; | ||
730 | if ((kctl = snd_ctl_new1(&snd_p16v_volume_control_spdif_unknown, emu)) == NULL) | ||
731 | return -ENOMEM; | ||
732 | if ((err = snd_ctl_add(card, kctl))) | ||
733 | return err; | ||
734 | return 0; | ||
735 | } | ||
736 | |||
diff --git a/sound/pci/emu10k1/p16v.h b/sound/pci/emu10k1/p16v.h new file mode 100644 index 000000000000..153214940336 --- /dev/null +++ b/sound/pci/emu10k1/p16v.h | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * Copyright (c) by James Courtier-Dutton <James@superbug.demon.co.uk> | ||
3 | * Driver p16v chips | ||
4 | * Version: 0.21 | ||
5 | * | ||
6 | * FEATURES currently supported: | ||
7 | * Output fixed at S32_LE, 2 channel to hw:0,0 | ||
8 | * Rates: 44.1, 48, 96, 192. | ||
9 | * | ||
10 | * Changelog: | ||
11 | * 0.8 | ||
12 | * Use separate card based buffer for periods table. | ||
13 | * 0.9 | ||
14 | * Use 2 channel output streams instead of 8 channel. | ||
15 | * (8 channel output streams might be good for ASIO type output) | ||
16 | * Corrected speaker output, so Front -> Front etc. | ||
17 | * 0.10 | ||
18 | * Fixed missed interrupts. | ||
19 | * 0.11 | ||
20 | * Add Sound card model number and names. | ||
21 | * Add Analog volume controls. | ||
22 | * 0.12 | ||
23 | * Corrected playback interrupts. Now interrupt per period, instead of half period. | ||
24 | * 0.13 | ||
25 | * Use single trigger for multichannel. | ||
26 | * 0.14 | ||
27 | * Mic capture now works at fixed: S32_LE, 96000Hz, Stereo. | ||
28 | * 0.15 | ||
29 | * Force buffer_size / period_size == INTEGER. | ||
30 | * 0.16 | ||
31 | * Update p16v.c to work with changed alsa api. | ||
32 | * 0.17 | ||
33 | * Update p16v.c to work with changed alsa api. Removed boot_devs. | ||
34 | * 0.18 | ||
35 | * Merging with snd-emu10k1 driver. | ||
36 | * 0.19 | ||
37 | * One stereo channel at 24bit now works. | ||
38 | * 0.20 | ||
39 | * Added better register defines. | ||
40 | * 0.21 | ||
41 | * Split from p16v.c | ||
42 | * | ||
43 | * | ||
44 | * BUGS: | ||
45 | * Some stability problems when unloading the snd-p16v kernel module. | ||
46 | * -- | ||
47 | * | ||
48 | * TODO: | ||
49 | * SPDIF out. | ||
50 | * Find out how to change capture sample rates. E.g. To record SPDIF at 48000Hz. | ||
51 | * Currently capture fixed at 48000Hz. | ||
52 | * | ||
53 | * -- | ||
54 | * GENERAL INFO: | ||
55 | * Model: SB0240 | ||
56 | * P16V Chip: CA0151-DBS | ||
57 | * Audigy 2 Chip: CA0102-IAT | ||
58 | * AC97 Codec: STAC 9721 | ||
59 | * ADC: Philips 1361T (Stereo 24bit) | ||
60 | * DAC: CS4382-K (8-channel, 24bit, 192Khz) | ||
61 | * | ||
62 | * This code was initally based on code from ALSA's emu10k1x.c which is: | ||
63 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> | ||
64 | * | ||
65 | * This program is free software; you can redistribute it and/or modify | ||
66 | * it under the terms of the GNU General Public License as published by | ||
67 | * the Free Software Foundation; either version 2 of the License, or | ||
68 | * (at your option) any later version. | ||
69 | * | ||
70 | * This program is distributed in the hope that it will be useful, | ||
71 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
72 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
73 | * GNU General Public License for more details. | ||
74 | * | ||
75 | * You should have received a copy of the GNU General Public License | ||
76 | * along with this program; if not, write to the Free Software | ||
77 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
78 | * | ||
79 | */ | ||
80 | |||
81 | /********************************************************************************************************/ | ||
82 | /* Audigy2 P16V pointer-offset register set, accessed through the PTR2 and DATA2 registers */ | ||
83 | /********************************************************************************************************/ | ||
84 | |||
85 | /* The sample rate of the SPDIF outputs is set by modifying a register in the EMU10K2 PTR register A_SPDIF_SAMPLERATE. | ||
86 | * The sample rate is also controlled by the same registers that control the rate of the EMU10K2 sample rate converters. | ||
87 | */ | ||
88 | |||
89 | /* Initally all registers from 0x00 to 0x3f have zero contents. */ | ||
90 | #define PLAYBACK_LIST_ADDR 0x00 /* Base DMA address of a list of pointers to each period/size */ | ||
91 | /* One list entry: 4 bytes for DMA address, | ||
92 | * 4 bytes for period_size << 16. | ||
93 | * One list entry is 8 bytes long. | ||
94 | * One list entry for each period in the buffer. | ||
95 | */ | ||
96 | #define PLAYBACK_LIST_SIZE 0x01 /* Size of list in bytes << 16. E.g. 8 periods -> 0x00380000 */ | ||
97 | #define PLAYBACK_LIST_PTR 0x02 /* Pointer to the current period being played */ | ||
98 | #define PLAYBACK_UNKNOWN3 0x03 /* Not used */ | ||
99 | #define PLAYBACK_DMA_ADDR 0x04 /* Playback DMA addresss */ | ||
100 | #define PLAYBACK_PERIOD_SIZE 0x05 /* Playback period size. win2000 uses 0x04000000 */ | ||
101 | #define PLAYBACK_POINTER 0x06 /* Playback period pointer. Used with PLAYBACK_LIST_PTR to determine buffer position currently in DAC */ | ||
102 | #define PLAYBACK_FIFO_END_ADDRESS 0x07 /* Playback FIFO end address */ | ||
103 | #define PLAYBACK_FIFO_POINTER 0x08 /* Playback FIFO pointer and number of valid sound samples in cache */ | ||
104 | #define PLAYBACK_UNKNOWN9 0x09 /* Not used */ | ||
105 | #define CAPTURE_DMA_ADDR 0x10 /* Capture DMA address */ | ||
106 | #define CAPTURE_BUFFER_SIZE 0x11 /* Capture buffer size */ | ||
107 | #define CAPTURE_POINTER 0x12 /* Capture buffer pointer. Sample currently in ADC */ | ||
108 | #define CAPTURE_FIFO_POINTER 0x13 /* Capture FIFO pointer and number of valid sound samples in cache */ | ||
109 | #define CAPTURE_P16V_VOLUME1 0x14 /* Low: Capture volume 0xXXXX3030 */ | ||
110 | #define CAPTURE_P16V_VOLUME2 0x15 /* High:Has no effect on capture volume */ | ||
111 | #define CAPTURE_P16V_SOURCE 0x16 /* P16V source select. Set to 0x0700E4E5 for AC97 CAPTURE */ | ||
112 | /* [0:1] Capture input 0 channel select. 0 = Capture output 0. | ||
113 | * 1 = Capture output 1. | ||
114 | * 2 = Capture output 2. | ||
115 | * 3 = Capture output 3. | ||
116 | * [3:2] Capture input 1 channel select. 0 = Capture output 0. | ||
117 | * 1 = Capture output 1. | ||
118 | * 2 = Capture output 2. | ||
119 | * 3 = Capture output 3. | ||
120 | * [5:4] Capture input 2 channel select. 0 = Capture output 0. | ||
121 | * 1 = Capture output 1. | ||
122 | * 2 = Capture output 2. | ||
123 | * 3 = Capture output 3. | ||
124 | * [7:6] Capture input 3 channel select. 0 = Capture output 0. | ||
125 | * 1 = Capture output 1. | ||
126 | * 2 = Capture output 2. | ||
127 | * 3 = Capture output 3. | ||
128 | * [9:8] Playback input 0 channel select. 0 = Play output 0. | ||
129 | * 1 = Play output 1. | ||
130 | * 2 = Play output 2. | ||
131 | * 3 = Play output 3. | ||
132 | * [11:10] Playback input 1 channel select. 0 = Play output 0. | ||
133 | * 1 = Play output 1. | ||
134 | * 2 = Play output 2. | ||
135 | * 3 = Play output 3. | ||
136 | * [13:12] Playback input 2 channel select. 0 = Play output 0. | ||
137 | * 1 = Play output 1. | ||
138 | * 2 = Play output 2. | ||
139 | * 3 = Play output 3. | ||
140 | * [15:14] Playback input 3 channel select. 0 = Play output 0. | ||
141 | * 1 = Play output 1. | ||
142 | * 2 = Play output 2. | ||
143 | * 3 = Play output 3. | ||
144 | * [19:16] Playback mixer output enable. 1 bit per channel. | ||
145 | * [23:20] Capture mixer output enable. 1 bit per channel. | ||
146 | * [26:24] FX engine channel capture 0 = 0x60-0x67. | ||
147 | * 1 = 0x68-0x6f. | ||
148 | * 2 = 0x70-0x77. | ||
149 | * 3 = 0x78-0x7f. | ||
150 | * 4 = 0x80-0x87. | ||
151 | * 5 = 0x88-0x8f. | ||
152 | * 6 = 0x90-0x97. | ||
153 | * 7 = 0x98-0x9f. | ||
154 | * [31:27] Not used. | ||
155 | */ | ||
156 | |||
157 | /* 0x1 = capture on. | ||
158 | * 0x100 = capture off. | ||
159 | * 0x200 = capture off. | ||
160 | * 0x1000 = capture off. | ||
161 | */ | ||
162 | #define CAPTURE_RATE_STATUS 0x17 /* Capture sample rate. Read only */ | ||
163 | /* [15:0] Not used. | ||
164 | * [18:16] Channel 0 Detected sample rate. 0 - 44.1khz | ||
165 | * 1 - 48 khz | ||
166 | * 2 - 96 khz | ||
167 | * 3 - 192 khz | ||
168 | * 7 - undefined rate. | ||
169 | * [19] Channel 0. 1 - Valid, 0 - Not Valid. | ||
170 | * [22:20] Channel 1 Detected sample rate. | ||
171 | * [23] Channel 1. 1 - Valid, 0 - Not Valid. | ||
172 | * [26:24] Channel 2 Detected sample rate. | ||
173 | * [27] Channel 2. 1 - Valid, 0 - Not Valid. | ||
174 | * [30:28] Channel 3 Detected sample rate. | ||
175 | * [31] Channel 3. 1 - Valid, 0 - Not Valid. | ||
176 | */ | ||
177 | /* 0x18 - 0x1f unused */ | ||
178 | #define PLAYBACK_LAST_SAMPLE 0x20 /* The sample currently being played. Read only */ | ||
179 | /* 0x21 - 0x3f unused */ | ||
180 | #define BASIC_INTERRUPT 0x40 /* Used by both playback and capture interrupt handler */ | ||
181 | /* Playback (0x1<<channel_id) Don't touch high 16bits. */ | ||
182 | /* Capture (0x100<<channel_id). not tested */ | ||
183 | /* Start Playback [3:0] (one bit per channel) | ||
184 | * Start Capture [11:8] (one bit per channel) | ||
185 | * Record source select for channel 0 [18:16] | ||
186 | * Record source select for channel 1 [22:20] | ||
187 | * Record source select for channel 2 [26:24] | ||
188 | * Record source select for channel 3 [30:28] | ||
189 | * 0 - SPDIF channel. | ||
190 | * 1 - I2S channel. | ||
191 | * 2 - SRC48 channel. | ||
192 | * 3 - SRCMulti_SPDIF channel. | ||
193 | * 4 - SRCMulti_I2S channel. | ||
194 | * 5 - SPDIF channel. | ||
195 | * 6 - fxengine capture. | ||
196 | * 7 - AC97 capture. | ||
197 | */ | ||
198 | /* Default 41110000. | ||
199 | * Writing 0xffffffff hangs the PC. | ||
200 | * Writing 0xffff0000 -> 77770000 so it must be some sort of route. | ||
201 | * bit 0x1 starts DMA playback on channel_id 0 | ||
202 | */ | ||
203 | /* 0x41,42 take values from 0 - 0xffffffff, but have no effect on playback */ | ||
204 | /* 0x43,0x48 do not remember settings */ | ||
205 | /* 0x41-45 unused */ | ||
206 | #define WATERMARK 0x46 /* Test bit to indicate cache level usage */ | ||
207 | /* Values it can have while playing on channel 0. | ||
208 | * 0000f000, 0000f004, 0000f008, 0000f00c. | ||
209 | * Readonly. | ||
210 | */ | ||
211 | /* 0x47-0x4f unused */ | ||
212 | /* 0x50-0x5f Capture cache data */ | ||
213 | #define SRCSel 0x60 /* SRCSel. Default 0x4. Bypass P16V 0x14 */ | ||
214 | /* [0] 0 = 10K2 audio, 1 = SRC48 mixer output. | ||
215 | * [2] 0 = 10K2 audio, 1 = SRCMulti SPDIF mixer output. | ||
216 | * [4] 0 = 10K2 audio, 1 = SRCMulti I2S mixer output. | ||
217 | */ | ||
218 | /* SRC48 converts samples rates 44.1, 48, 96, 192 to 48 khz. */ | ||
219 | /* SRCMulti converts 48khz samples rates to 44.1, 48, 96, 192 to 48. */ | ||
220 | /* SRC48 and SRCMULTI sample rate select and output select. */ | ||
221 | /* 0xffffffff -> 0xC0000015 | ||
222 | * 0xXXXXXXX4 = Enable Front Left/Right | ||
223 | * Enable PCMs | ||
224 | */ | ||
225 | |||
226 | /* 0x61 -> 0x6c are Volume controls */ | ||
227 | #define PLAYBACK_VOLUME_MIXER1 0x61 /* SRC48 Low to mixer input volume control. */ | ||
228 | #define PLAYBACK_VOLUME_MIXER2 0x62 /* SRC48 High to mixer input volume control. */ | ||
229 | #define PLAYBACK_VOLUME_MIXER3 0x63 /* SRCMULTI SPDIF Low to mixer input volume control. */ | ||
230 | #define PLAYBACK_VOLUME_MIXER4 0x64 /* SRCMULTI SPDIF High to mixer input volume control. */ | ||
231 | #define PLAYBACK_VOLUME_MIXER5 0x65 /* SRCMULTI I2S Low to mixer input volume control. */ | ||
232 | #define PLAYBACK_VOLUME_MIXER6 0x66 /* SRCMULTI I2S High to mixer input volume control. */ | ||
233 | #define PLAYBACK_VOLUME_MIXER7 0x67 /* P16V Low to SRCMULTI SPDIF mixer input volume control. */ | ||
234 | #define PLAYBACK_VOLUME_MIXER8 0x68 /* P16V High to SRCMULTI SPDIF mixer input volume control. */ | ||
235 | #define PLAYBACK_VOLUME_MIXER9 0x69 /* P16V Low to SRCMULTI I2S mixer input volume control. */ | ||
236 | /* 0xXXXX3030 = PCM0 Volume (Front). | ||
237 | * 0x3030XXXX = PCM1 Volume (Center) | ||
238 | */ | ||
239 | #define PLAYBACK_VOLUME_MIXER10 0x6a /* P16V High to SRCMULTI I2S mixer input volume control. */ | ||
240 | /* 0x3030XXXX = PCM3 Volume (Rear). */ | ||
241 | #define PLAYBACK_VOLUME_MIXER11 0x6b /* E10K2 Low to SRC48 mixer input volume control. */ | ||
242 | #define PLAYBACK_VOLUME_MIXER12 0x6c /* E10K2 High to SRC48 mixer input volume control. */ | ||
243 | |||
244 | #define SRC48_ENABLE 0x6d /* SRC48 input audio enable */ | ||
245 | /* SRC48 converts samples rates 44.1, 48, 96, 192 to 48 khz. */ | ||
246 | /* [23:16] The corresponding P16V channel to SRC48 enabled if == 1. | ||
247 | * [31:24] The corresponding E10K2 channel to SRC48 enabled. | ||
248 | */ | ||
249 | #define SRCMULTI_ENABLE 0x6e /* SRCMulti input audio enable. Default 0xffffffff */ | ||
250 | /* SRCMulti converts 48khz samples rates to 44.1, 48, 96, 192 to 48. */ | ||
251 | /* [7:0] The corresponding P16V channel to SRCMulti_I2S enabled if == 1. | ||
252 | * [15:8] The corresponding E10K2 channel to SRCMulti I2S enabled. | ||
253 | * [23:16] The corresponding P16V channel to SRCMulti SPDIF enabled. | ||
254 | * [31:24] The corresponding E10K2 channel to SRCMulti SPDIF enabled. | ||
255 | */ | ||
256 | /* Bypass P16V 0xff00ff00 | ||
257 | * Bitmap. 0 = Off, 1 = On. | ||
258 | * P16V playback outputs: | ||
259 | * 0xXXXXXXX1 = PCM0 Left. (Front) | ||
260 | * 0xXXXXXXX2 = PCM0 Right. | ||
261 | * 0xXXXXXXX4 = PCM1 Left. (Center/LFE) | ||
262 | * 0xXXXXXXX8 = PCM1 Right. | ||
263 | * 0xXXXXXX1X = PCM2 Left. (Unknown) | ||
264 | * 0xXXXXXX2X = PCM2 Right. | ||
265 | * 0xXXXXXX4X = PCM3 Left. (Rear) | ||
266 | * 0xXXXXXX8X = PCM3 Right. | ||
267 | */ | ||
268 | #define AUDIO_OUT_ENABLE 0x6f /* Default: 000100FF */ | ||
269 | /* [3:0] Does something, but not documented. Probably capture enable. | ||
270 | * [7:4] Playback channels enable. not documented. | ||
271 | * [16] AC97 output enable if == 1 | ||
272 | * [30] 0 = SRCMulti_I2S input from fxengine 0x68-0x6f. | ||
273 | * 1 = SRCMulti_I2S input from SRC48 output. | ||
274 | * [31] 0 = SRCMulti_SPDIF input from fxengine 0x60-0x67. | ||
275 | * 1 = SRCMulti_SPDIF input from SRC48 output. | ||
276 | */ | ||
277 | /* 0xffffffff -> C00100FF */ | ||
278 | /* 0 -> Not playback sound, irq still running */ | ||
279 | /* 0xXXXXXX10 = PCM0 Left/Right On. (Front) | ||
280 | * 0xXXXXXX20 = PCM1 Left/Right On. (Center/LFE) | ||
281 | * 0xXXXXXX40 = PCM2 Left/Right On. (Unknown) | ||
282 | * 0xXXXXXX80 = PCM3 Left/Right On. (Rear) | ||
283 | */ | ||
284 | #define PLAYBACK_SPDIF_SELECT 0x70 /* Default: 12030F00 */ | ||
285 | /* 0xffffffff -> 3FF30FFF */ | ||
286 | /* 0x00000001 pauses stream/irq fail. */ | ||
287 | /* All other bits do not effect playback */ | ||
288 | #define PLAYBACK_SPDIF_SRC_SELECT 0x71 /* Default: 0000E4E4 */ | ||
289 | /* 0xffffffff -> F33FFFFF */ | ||
290 | /* All bits do not effect playback */ | ||
291 | #define PLAYBACK_SPDIF_USER_DATA0 0x72 /* SPDIF out user data 0 */ | ||
292 | #define PLAYBACK_SPDIF_USER_DATA1 0x73 /* SPDIF out user data 1 */ | ||
293 | /* 0x74-0x75 unknown */ | ||
294 | #define CAPTURE_SPDIF_CONTROL 0x76 /* SPDIF in control setting */ | ||
295 | #define CAPTURE_SPDIF_STATUS 0x77 /* SPDIF in status */ | ||
296 | #define CAPURE_SPDIF_USER_DATA0 0x78 /* SPDIF in user data 0 */ | ||
297 | #define CAPURE_SPDIF_USER_DATA1 0x79 /* SPDIF in user data 1 */ | ||
298 | #define CAPURE_SPDIF_USER_DATA2 0x7a /* SPDIF in user data 2 */ | ||
299 | |||
diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c new file mode 100644 index 000000000000..d2e364607c1d --- /dev/null +++ b/sound/pci/emu10k1/timer.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Lee Revell <rlrevell@joe-job.com> | ||
3 | * Clemens Ladisch <clemens@ladisch.de> | ||
4 | * Routines for control of EMU10K1 chips | ||
5 | * | ||
6 | * BUGS: | ||
7 | * -- | ||
8 | * | ||
9 | * TODO: | ||
10 | * -- | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <sound/driver.h> | ||
29 | #include <linux/time.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/emu10k1.h> | ||
32 | |||
33 | static int snd_emu10k1_timer_start(snd_timer_t *timer) | ||
34 | { | ||
35 | emu10k1_t *emu; | ||
36 | unsigned long flags; | ||
37 | unsigned int delay; | ||
38 | |||
39 | emu = snd_timer_chip(timer); | ||
40 | delay = timer->sticks - 1; | ||
41 | if (delay < 5 ) /* minimum time is 5 ticks */ | ||
42 | delay = 5; | ||
43 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
44 | snd_emu10k1_intr_enable(emu, INTE_INTERVALTIMERENB); | ||
45 | outw(delay & TIMER_RATE_MASK, emu->port + TIMER); | ||
46 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static int snd_emu10k1_timer_stop(snd_timer_t *timer) | ||
51 | { | ||
52 | emu10k1_t *emu; | ||
53 | unsigned long flags; | ||
54 | |||
55 | emu = snd_timer_chip(timer); | ||
56 | spin_lock_irqsave(&emu->reg_lock, flags); | ||
57 | snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); | ||
58 | spin_unlock_irqrestore(&emu->reg_lock, flags); | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int snd_emu10k1_timer_precise_resolution(snd_timer_t *timer, | ||
63 | unsigned long *num, unsigned long *den) | ||
64 | { | ||
65 | *num = 1; | ||
66 | *den = 48000; | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static struct _snd_timer_hardware snd_emu10k1_timer_hw = { | ||
71 | .flags = SNDRV_TIMER_HW_AUTO, | ||
72 | .resolution = 20833, /* 1 sample @ 48KHZ = 20.833...us */ | ||
73 | .ticks = 1024, | ||
74 | .start = snd_emu10k1_timer_start, | ||
75 | .stop = snd_emu10k1_timer_stop, | ||
76 | .precise_resolution = snd_emu10k1_timer_precise_resolution, | ||
77 | }; | ||
78 | |||
79 | int __devinit snd_emu10k1_timer(emu10k1_t *emu, int device) | ||
80 | { | ||
81 | snd_timer_t *timer = NULL; | ||
82 | snd_timer_id_t tid; | ||
83 | int err; | ||
84 | |||
85 | tid.dev_class = SNDRV_TIMER_CLASS_CARD; | ||
86 | tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; | ||
87 | tid.card = emu->card->number; | ||
88 | tid.device = device; | ||
89 | tid.subdevice = 0; | ||
90 | if ((err = snd_timer_new(emu->card, "EMU10K1", &tid, &timer)) >= 0) { | ||
91 | strcpy(timer->name, "EMU10K1 timer"); | ||
92 | timer->private_data = emu; | ||
93 | timer->hw = snd_emu10k1_timer_hw; | ||
94 | } | ||
95 | emu->timer = timer; | ||
96 | return err; | ||
97 | } | ||
diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c new file mode 100644 index 000000000000..d251d3440eec --- /dev/null +++ b/sound/pci/emu10k1/voice.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Creative Labs, Inc. | ||
4 | * Lee Revell <rlrevell@joe-job.com> | ||
5 | * Routines for control of EMU10K1 chips - voice manager | ||
6 | * | ||
7 | * Rewrote voice allocator for multichannel support - rlrevell 12/2004 | ||
8 | * | ||
9 | * BUGS: | ||
10 | * -- | ||
11 | * | ||
12 | * TODO: | ||
13 | * -- | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <sound/driver.h> | ||
32 | #include <linux/time.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/emu10k1.h> | ||
35 | |||
36 | /* Previously the voice allocator started at 0 every time. The new voice | ||
37 | * allocator uses a round robin scheme. The next free voice is tracked in | ||
38 | * the card record and each allocation begins where the last left off. The | ||
39 | * hardware requires stereo interleaved voices be aligned to an even/odd | ||
40 | * boundary. For multichannel voice allocation we ensure than the block of | ||
41 | * voices does not cross the 32 voice boundary. This simplifies the | ||
42 | * multichannel support and ensures we can use a single write to the | ||
43 | * (set|clear)_loop_stop registers. Otherwise (for example) the voices would | ||
44 | * get out of sync when pausing/resuming a stream. | ||
45 | * --rlrevell | ||
46 | */ | ||
47 | |||
48 | static int voice_alloc(emu10k1_t *emu, emu10k1_voice_type_t type, int number, emu10k1_voice_t **rvoice) | ||
49 | { | ||
50 | emu10k1_voice_t *voice; | ||
51 | int i, j, k, first_voice, last_voice, skip; | ||
52 | |||
53 | *rvoice = NULL; | ||
54 | first_voice = last_voice = 0; | ||
55 | for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) { | ||
56 | // printk("i %d j %d next free %d!\n", i, j, emu->next_free_voice); | ||
57 | i %= NUM_G; | ||
58 | |||
59 | /* stereo voices must be even/odd */ | ||
60 | if ((number == 2) && (i % 2)) { | ||
61 | i++; | ||
62 | continue; | ||
63 | } | ||
64 | |||
65 | skip = 0; | ||
66 | for (k = 0; k < number; k++) { | ||
67 | voice = &emu->voices[(i+k) % NUM_G]; | ||
68 | if (voice->use) { | ||
69 | skip = 1; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | if (!skip) { | ||
74 | // printk("allocated voice %d\n", i); | ||
75 | first_voice = i; | ||
76 | last_voice = (i + number) % NUM_G; | ||
77 | emu->next_free_voice = last_voice; | ||
78 | break; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | if (first_voice == last_voice) | ||
83 | return -ENOMEM; | ||
84 | |||
85 | for (i=0; i < number; i++) { | ||
86 | voice = &emu->voices[(first_voice + i) % NUM_G]; | ||
87 | // printk("voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number); | ||
88 | voice->use = 1; | ||
89 | switch (type) { | ||
90 | case EMU10K1_PCM: | ||
91 | voice->pcm = 1; | ||
92 | break; | ||
93 | case EMU10K1_SYNTH: | ||
94 | voice->synth = 1; | ||
95 | break; | ||
96 | case EMU10K1_MIDI: | ||
97 | voice->midi = 1; | ||
98 | break; | ||
99 | case EMU10K1_EFX: | ||
100 | voice->efx = 1; | ||
101 | break; | ||
102 | } | ||
103 | } | ||
104 | *rvoice = &emu->voices[first_voice]; | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | int snd_emu10k1_voice_alloc(emu10k1_t *emu, emu10k1_voice_type_t type, int number, emu10k1_voice_t **rvoice) | ||
109 | { | ||
110 | unsigned long flags; | ||
111 | int result; | ||
112 | |||
113 | snd_assert(rvoice != NULL, return -EINVAL); | ||
114 | snd_assert(number, return -EINVAL); | ||
115 | |||
116 | spin_lock_irqsave(&emu->voice_lock, flags); | ||
117 | for (;;) { | ||
118 | result = voice_alloc(emu, type, number, rvoice); | ||
119 | if (result == 0 || type == EMU10K1_SYNTH || type == EMU10K1_MIDI) | ||
120 | break; | ||
121 | |||
122 | /* free a voice from synth */ | ||
123 | if (emu->get_synth_voice) { | ||
124 | result = emu->get_synth_voice(emu); | ||
125 | if (result >= 0) { | ||
126 | emu10k1_voice_t *pvoice = &emu->voices[result]; | ||
127 | pvoice->interrupt = NULL; | ||
128 | pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0; | ||
129 | pvoice->epcm = NULL; | ||
130 | } | ||
131 | } | ||
132 | if (result < 0) | ||
133 | break; | ||
134 | } | ||
135 | spin_unlock_irqrestore(&emu->voice_lock, flags); | ||
136 | |||
137 | return result; | ||
138 | } | ||
139 | |||
140 | int snd_emu10k1_voice_free(emu10k1_t *emu, emu10k1_voice_t *pvoice) | ||
141 | { | ||
142 | unsigned long flags; | ||
143 | |||
144 | snd_assert(pvoice != NULL, return -EINVAL); | ||
145 | spin_lock_irqsave(&emu->voice_lock, flags); | ||
146 | pvoice->interrupt = NULL; | ||
147 | pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = pvoice->efx = 0; | ||
148 | pvoice->epcm = NULL; | ||
149 | snd_emu10k1_voice_init(emu, pvoice->number); | ||
150 | spin_unlock_irqrestore(&emu->voice_lock, flags); | ||
151 | return 0; | ||
152 | } | ||