2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 * Routines for control of EMU10K1 chips
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.
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.
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
28 #include <sound/driver.h>
29 #include <linux/time.h>
30 #include <sound/core.h>
31 #include <sound/emu10k1.h>
33 unsigned int snd_emu10k1_ptr_read(emu10k1_t * emu, unsigned int reg, unsigned int chn)
36 unsigned int regptr, val;
39 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
40 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
42 if (reg & 0xff000000) {
43 unsigned char size, offset;
45 size = (reg >> 24) & 0x3f;
46 offset = (reg >> 16) & 0x1f;
47 mask = ((1 << size) - 1) << offset;
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);
54 return (val & mask) >> offset;
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);
64 void snd_emu10k1_ptr_write(emu10k1_t *emu, unsigned int reg, unsigned int chn, unsigned int data)
70 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
71 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
73 if (reg & 0xff000000) {
74 unsigned char size, offset;
76 size = (reg >> 24) & 0x3f;
77 offset = (reg >> 16) & 0x1f;
78 mask = ((1 << size) - 1) << offset;
79 data = (data << offset) & mask;
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);
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);
94 void snd_emu10k1_intr_enable(emu10k1_t *emu, unsigned int intrenb)
99 spin_lock_irqsave(&emu->emu_lock, flags);
100 enable = inl(emu->port + INTE) | intrenb;
101 outl(enable, emu->port + INTE);
102 spin_unlock_irqrestore(&emu->emu_lock, flags);
105 void snd_emu10k1_intr_disable(emu10k1_t *emu, unsigned int intrenb)
110 spin_lock_irqsave(&emu->emu_lock, flags);
111 enable = inl(emu->port + INTE) & ~intrenb;
112 outl(enable, emu->port + INTE);
113 spin_unlock_irqrestore(&emu->emu_lock, flags);
116 void snd_emu10k1_voice_intr_enable(emu10k1_t *emu, unsigned int voicenum)
121 spin_lock_irqsave(&emu->emu_lock, flags);
122 /* voice interrupt */
123 if (voicenum >= 32) {
124 outl(CLIEH << 16, emu->port + PTR);
125 val = inl(emu->port + DATA);
126 val |= 1 << (voicenum - 32);
128 outl(CLIEL << 16, emu->port + PTR);
129 val = inl(emu->port + DATA);
130 val |= 1 << voicenum;
132 outl(val, emu->port + DATA);
133 spin_unlock_irqrestore(&emu->emu_lock, flags);
136 void snd_emu10k1_voice_intr_disable(emu10k1_t *emu, unsigned int voicenum)
141 spin_lock_irqsave(&emu->emu_lock, flags);
142 /* voice interrupt */
143 if (voicenum >= 32) {
144 outl(CLIEH << 16, emu->port + PTR);
145 val = inl(emu->port + DATA);
146 val &= ~(1 << (voicenum - 32));
148 outl(CLIEL << 16, emu->port + PTR);
149 val = inl(emu->port + DATA);
150 val &= ~(1 << voicenum);
152 outl(val, emu->port + DATA);
153 spin_unlock_irqrestore(&emu->emu_lock, flags);
156 void snd_emu10k1_voice_intr_ack(emu10k1_t *emu, unsigned int voicenum)
160 spin_lock_irqsave(&emu->emu_lock, flags);
161 /* voice interrupt */
162 if (voicenum >= 32) {
163 outl(CLIPH << 16, emu->port + PTR);
164 voicenum = 1 << (voicenum - 32);
166 outl(CLIPL << 16, emu->port + PTR);
167 voicenum = 1 << voicenum;
169 outl(voicenum, emu->port + DATA);
170 spin_unlock_irqrestore(&emu->emu_lock, flags);
173 void snd_emu10k1_voice_set_loop_stop(emu10k1_t *emu, unsigned int voicenum)
178 spin_lock_irqsave(&emu->emu_lock, flags);
179 /* voice interrupt */
180 if (voicenum >= 32) {
181 outl(SOLEH << 16, emu->port + PTR);
182 sol = inl(emu->port + DATA);
183 sol |= 1 << (voicenum - 32);
185 outl(SOLEL << 16, emu->port + PTR);
186 sol = inl(emu->port + DATA);
187 sol |= 1 << voicenum;
189 outl(sol, emu->port + DATA);
190 spin_unlock_irqrestore(&emu->emu_lock, flags);
193 void snd_emu10k1_voice_clear_loop_stop(emu10k1_t *emu, unsigned int voicenum)
198 spin_lock_irqsave(&emu->emu_lock, flags);
199 /* voice interrupt */
200 if (voicenum >= 32) {
201 outl(SOLEH << 16, emu->port + PTR);
202 sol = inl(emu->port + DATA);
203 sol &= ~(1 << (voicenum - 32));
205 outl(SOLEL << 16, emu->port + PTR);
206 sol = inl(emu->port + DATA);
207 sol &= ~(1 << voicenum);
209 outl(sol, emu->port + DATA);
210 spin_unlock_irqrestore(&emu->emu_lock, flags);
213 void snd_emu10k1_wait(emu10k1_t *emu, unsigned int wait)
215 volatile unsigned count;
216 unsigned int newtime = 0, curtime;
218 curtime = inl(emu->port + WC) >> 6;
221 while (count++ < 16384) {
222 newtime = inl(emu->port + WC) >> 6;
223 if (newtime != curtime)
232 unsigned short snd_emu10k1_ac97_read(ac97_t *ac97, unsigned short reg)
234 emu10k1_t *emu = ac97->private_data;
238 spin_lock_irqsave(&emu->emu_lock, flags);
239 outb(reg, emu->port + AC97ADDRESS);
240 val = inw(emu->port + AC97DATA);
241 spin_unlock_irqrestore(&emu->emu_lock, flags);
245 void snd_emu10k1_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short data)
247 emu10k1_t *emu = ac97->private_data;
250 spin_lock_irqsave(&emu->emu_lock, flags);
251 outb(reg, emu->port + AC97ADDRESS);
252 outw(data, emu->port + AC97DATA);
253 spin_unlock_irqrestore(&emu->emu_lock, flags);
257 * convert rate to pitch
260 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
262 static u32 logMagTable[128] = {
263 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
264 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
265 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
266 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
267 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
268 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
269 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
270 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
271 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
272 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
273 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
274 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
275 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
276 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
277 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
278 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
280 static char logSlopeTable[128] = {
281 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
282 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
283 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
284 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
285 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
286 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
287 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
288 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
289 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
290 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
291 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
292 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
293 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
294 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
295 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
296 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
301 return 0; /* Bail out if no leading "1" */
302 rate *= 11185; /* Scale 48000 to 0x20002380 */
303 for (i = 31; i > 0; i--) {
304 if (rate & 0x80000000) { /* Detect leading "1" */
305 return (((unsigned int) (i - 15) << 20) +
306 logMagTable[0x7f & (rate >> 24)] +
307 (0x7f & (rate >> 17)) *
308 logSlopeTable[0x7f & (rate >> 24)]);
313 return 0; /* Should never reach this point */