source: GPL/alsa-kernel/pci/emu10k1/io.c@ 1

Last change on this file since 1 was 1, checked in by vladest, 20 years ago

initial import

File size: 12.5 KB
Line 
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#define __NO_VERSION__
29#include <sound/driver.h>
30#include <linux/time.h>
31#include <sound/core.h>
32#include <sound/emu10k1.h>
33
34unsigned int snd_emu10k1_ptr_read(emu10k1_t * emu, unsigned int reg, unsigned int chn)
35{
36 unsigned long flags;
37 unsigned int regptr, val;
38 unsigned int mask;
39
40 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
41 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
42
43 if (reg & 0xff000000) {
44 unsigned char size, offset;
45
46 size = (reg >> 24) & 0x3f;
47 offset = (reg >> 16) & 0x1f;
48 mask = ((1 << size) - 1) << offset;
49
50 spin_lock_irqsave(&emu->emu_lock, flags);
51 outl(regptr, emu->port + PTR);
52 val = inl(emu->port + DATA);
53 spin_unlock_irqrestore(&emu->emu_lock, flags);
54
55 return (val & mask) >> offset;
56 } else {
57 spin_lock_irqsave(&emu->emu_lock, flags);
58 outl(regptr, emu->port + PTR);
59 val = inl(emu->port + DATA);
60 spin_unlock_irqrestore(&emu->emu_lock, flags);
61 return val;
62 }
63}
64
65void snd_emu10k1_ptr_write(emu10k1_t *emu, unsigned int reg, unsigned int chn, unsigned int data)
66{
67 unsigned int regptr;
68 unsigned long flags;
69 unsigned int mask;
70
71 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
72 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
73
74 if (reg & 0xff000000) {
75 unsigned char size, offset;
76
77 size = (reg >> 24) & 0x3f;
78 offset = (reg >> 16) & 0x1f;
79 mask = ((1 << size) - 1) << offset;
80 data = (data << offset) & mask;
81
82 spin_lock_irqsave(&emu->emu_lock, flags);
83 outl(regptr, emu->port + PTR);
84 data |= inl(emu->port + DATA) & ~mask;
85 outl(data, emu->port + DATA);
86 spin_unlock_irqrestore(&emu->emu_lock, flags);
87 } else {
88 spin_lock_irqsave(&emu->emu_lock, flags);
89 outl(regptr, emu->port + PTR);
90 outl(data, emu->port + DATA);
91 spin_unlock_irqrestore(&emu->emu_lock, flags);
92 }
93}
94
95unsigned int snd_emu10k1_ptr20_read(emu10k1_t * emu,
96 unsigned int reg,
97 unsigned int chn)
98{
99 unsigned long flags;
100 unsigned int regptr, val;
101
102 regptr = (reg << 16) | chn;
103
104 spin_lock_irqsave(&emu->emu_lock, flags);
105 outl(regptr, emu->port + 0x20 + PTR);
106 val = inl(emu->port + 0x20 + DATA);
107 spin_unlock_irqrestore(&emu->emu_lock, flags);
108 return val;
109}
110
111void snd_emu10k1_ptr20_write(emu10k1_t *emu,
112 unsigned int reg,
113 unsigned int chn,
114 unsigned int data)
115{
116 unsigned int regptr;
117 unsigned long flags;
118
119 regptr = (reg << 16) | chn;
120
121 spin_lock_irqsave(&emu->emu_lock, flags);
122 outl(regptr, emu->port + 0x20 + PTR);
123 outl(data, emu->port + 0x20 + DATA);
124 spin_unlock_irqrestore(&emu->emu_lock, flags);
125}
126
127void snd_emu10k1_intr_enable(emu10k1_t *emu, unsigned int intrenb)
128{
129 unsigned long flags;
130 unsigned int enable;
131
132 spin_lock_irqsave(&emu->emu_lock, flags);
133 enable = inl(emu->port + INTE) | intrenb;
134 outl(enable, emu->port + INTE);
135 spin_unlock_irqrestore(&emu->emu_lock, flags);
136}
137
138void snd_emu10k1_intr_disable(emu10k1_t *emu, unsigned int intrenb)
139{
140 unsigned long flags;
141 unsigned int enable;
142
143 spin_lock_irqsave(&emu->emu_lock, flags);
144 enable = inl(emu->port + INTE) & ~intrenb;
145 outl(enable, emu->port + INTE);
146 spin_unlock_irqrestore(&emu->emu_lock, flags);
147}
148
149void snd_emu10k1_voice_intr_enable(emu10k1_t *emu, unsigned int voicenum)
150{
151 unsigned long flags;
152 unsigned int val;
153
154 spin_lock_irqsave(&emu->emu_lock, flags);
155 /* voice interrupt */
156 if (voicenum >= 32) {
157 outl(CLIEH << 16, emu->port + PTR);
158 val = inl(emu->port + DATA);
159 val |= 1 << (voicenum - 32);
160 } else {
161 outl(CLIEL << 16, emu->port + PTR);
162 val = inl(emu->port + DATA);
163 val |= 1 << voicenum;
164 }
165 outl(val, emu->port + DATA);
166 spin_unlock_irqrestore(&emu->emu_lock, flags);
167}
168
169void snd_emu10k1_voice_intr_disable(emu10k1_t *emu, unsigned int voicenum)
170{
171 unsigned long flags;
172 unsigned int val;
173
174 spin_lock_irqsave(&emu->emu_lock, flags);
175 /* voice interrupt */
176 if (voicenum >= 32) {
177 outl(CLIEH << 16, emu->port + PTR);
178 val = inl(emu->port + DATA);
179 val &= ~(1 << (voicenum - 32));
180 } else {
181 outl(CLIEL << 16, emu->port + PTR);
182 val = inl(emu->port + DATA);
183 val &= ~(1 << voicenum);
184 }
185 outl(val, emu->port + DATA);
186 spin_unlock_irqrestore(&emu->emu_lock, flags);
187}
188
189void snd_emu10k1_voice_intr_ack(emu10k1_t *emu, unsigned int voicenum)
190{
191 unsigned long flags;
192
193 spin_lock_irqsave(&emu->emu_lock, flags);
194 /* voice interrupt */
195 if (voicenum >= 32) {
196 outl(CLIPH << 16, emu->port + PTR);
197 voicenum = 1 << (voicenum - 32);
198 } else {
199 outl(CLIPL << 16, emu->port + PTR);
200 voicenum = 1 << voicenum;
201 }
202 outl(voicenum, emu->port + DATA);
203 spin_unlock_irqrestore(&emu->emu_lock, flags);
204}
205
206void snd_emu10k1_voice_half_loop_intr_enable(emu10k1_t *emu, unsigned int voicenum)
207{
208 unsigned long flags;
209 unsigned int val;
210
211 spin_lock_irqsave(&emu->emu_lock, flags);
212 /* voice interrupt */
213 if (voicenum >= 32) {
214 outl(HLIEH << 16, emu->port + PTR);
215 val = inl(emu->port + DATA);
216 val |= 1 << (voicenum - 32);
217 } else {
218 outl(HLIEL << 16, emu->port + PTR);
219 val = inl(emu->port + DATA);
220 val |= 1 << voicenum;
221 }
222 outl(val, emu->port + DATA);
223 spin_unlock_irqrestore(&emu->emu_lock, flags);
224}
225
226void snd_emu10k1_voice_half_loop_intr_disable(emu10k1_t *emu, unsigned int voicenum)
227{
228 unsigned long flags;
229 unsigned int val;
230
231 spin_lock_irqsave(&emu->emu_lock, flags);
232 /* voice interrupt */
233 if (voicenum >= 32) {
234 outl(HLIEH << 16, emu->port + PTR);
235 val = inl(emu->port + DATA);
236 val &= ~(1 << (voicenum - 32));
237 } else {
238 outl(HLIEL << 16, emu->port + PTR);
239 val = inl(emu->port + DATA);
240 val &= ~(1 << voicenum);
241 }
242 outl(val, emu->port + DATA);
243 spin_unlock_irqrestore(&emu->emu_lock, flags);
244}
245
246void snd_emu10k1_voice_half_loop_intr_ack(emu10k1_t *emu, unsigned int voicenum)
247{
248 unsigned long flags;
249
250 spin_lock_irqsave(&emu->emu_lock, flags);
251 /* voice interrupt */
252 if (voicenum >= 32) {
253 outl(HLIPH << 16, emu->port + PTR);
254 voicenum = 1 << (voicenum - 32);
255 } else {
256 outl(HLIPL << 16, emu->port + PTR);
257 voicenum = 1 << voicenum;
258 }
259 outl(voicenum, emu->port + DATA);
260 spin_unlock_irqrestore(&emu->emu_lock, flags);
261}
262
263void snd_emu10k1_voice_set_loop_stop(emu10k1_t *emu, unsigned int voicenum)
264{
265 unsigned long flags;
266 unsigned int sol;
267
268 spin_lock_irqsave(&emu->emu_lock, flags);
269 /* voice interrupt */
270 if (voicenum >= 32) {
271 outl(SOLEH << 16, emu->port + PTR);
272 sol = inl(emu->port + DATA);
273 sol |= 1 << (voicenum - 32);
274 } else {
275 outl(SOLEL << 16, emu->port + PTR);
276 sol = inl(emu->port + DATA);
277 sol |= 1 << voicenum;
278 }
279 outl(sol, emu->port + DATA);
280 spin_unlock_irqrestore(&emu->emu_lock, flags);
281}
282
283void snd_emu10k1_voice_clear_loop_stop(emu10k1_t *emu, unsigned int voicenum)
284{
285 unsigned long flags;
286 unsigned int sol;
287
288 spin_lock_irqsave(&emu->emu_lock, flags);
289 /* voice interrupt */
290 if (voicenum >= 32) {
291 outl(SOLEH << 16, emu->port + PTR);
292 sol = inl(emu->port + DATA);
293 sol &= ~(1 << (voicenum - 32));
294 } else {
295 outl(SOLEL << 16, emu->port + PTR);
296 sol = inl(emu->port + DATA);
297 sol &= ~(1 << voicenum);
298 }
299 outl(sol, emu->port + DATA);
300 spin_unlock_irqrestore(&emu->emu_lock, flags);
301}
302
303void snd_emu10k1_wait(emu10k1_t *emu, unsigned int wait)
304{
305 volatile unsigned count;
306 unsigned int newtime = 0, curtime;
307
308 curtime = inl(emu->port + WC) >> 6;
309 while (wait-- > 0) {
310 count = 0;
311 while (count++ < 16384) {
312 newtime = inl(emu->port + WC) >> 6;
313 if (newtime != curtime)
314 break;
315 }
316 if (count >= 16384)
317 break;
318 curtime = newtime;
319 }
320}
321
322unsigned short snd_emu10k1_ac97_read(ac97_t *ac97, unsigned short reg)
323{
324 emu10k1_t *emu = ac97->private_data;
325 unsigned long flags;
326 unsigned short val;
327
328 spin_lock_irqsave(&emu->emu_lock, flags);
329 outb(reg, emu->port + AC97ADDRESS);
330 val = inw(emu->port + AC97DATA);
331 spin_unlock_irqrestore(&emu->emu_lock, flags);
332 return val;
333}
334
335void snd_emu10k1_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short data)
336{
337 emu10k1_t *emu = ac97->private_data;
338 unsigned long flags;
339
340 spin_lock_irqsave(&emu->emu_lock, flags);
341 outb(reg, emu->port + AC97ADDRESS);
342 outw(data, emu->port + AC97DATA);
343 spin_unlock_irqrestore(&emu->emu_lock, flags);
344}
345
346/*
347 * convert rate to pitch
348 */
349
350unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
351{
352 static u32 logMagTable[128] = {
353 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
354 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
355 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
356 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
357 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
358 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
359 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
360 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
361 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
362 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
363 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
364 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
365 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
366 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
367 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
368 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
369 };
370 static char logSlopeTable[128] = {
371 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
372 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
373 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
374 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
375 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
376 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
377 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
378 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
379 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
380 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
381 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
382 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
383 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
384 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
385 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
386 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
387 };
388 int i;
389
390 if (rate == 0)
391 return 0; /* Bail out if no leading "1" */
392 rate *= 11185; /* Scale 48000 to 0x20002380 */
393 for (i = 31; i > 0; i--) {
394 if (rate & 0x80000000) { /* Detect leading "1" */
395 return (((unsigned int) (i - 15) << 20) +
396 logMagTable[0x7f & (rate >> 24)] +
397 (0x7f & (rate >> 17)) *
398 logSlopeTable[0x7f & (rate >> 24)]);
399 }
400 rate <<= 1;
401 }
402
403 return 0; /* Should never reach this point */
404}
405
406/*
407 * Returns an attenuation based upon a cumulative volume value
408 * Algorithm calculates 0x200 - 0x10 log2 (input)
409 */
410
411unsigned char snd_emu10k1_sum_vol_attn(unsigned int value)
412{
413 unsigned short count = 16, ans;
414
415 if (value == 0)
416 return 0xFF;
417
418 /* Find first SET bit. This is the integer part of the value */
419 while ((value & 0x10000) == 0) {
420 value <<= 1;
421 count--;
422 }
423
424 /* The REST of the data is the fractional part. */
425 ans = (unsigned short) (0x110 - ((count << 4) + ((value & 0x0FFFFL) >> 12)));
426 if (ans > 0xFF)
427 ans = 0xFF;
428
429 return (unsigned char) ans;
430}
Note: See TracBrowser for help on using the repository browser.