[PATCH] w1: Added default generic read/write operations.
[linux-2.6/verdex.git] / sound / pci / emu10k1 / io.c
blobef5304df8c1184a25c5955f94d6c9132e9ddea51
1 /*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Creative Labs, Inc.
4 * Routines for control of EMU10K1 chips
6 * BUGS:
7 * --
9 * TODO:
10 * --
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>
32 #include <linux/delay.h>
34 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
36 unsigned long flags;
37 unsigned int regptr, val;
38 unsigned int mask;
40 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
41 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
43 if (reg & 0xff000000) {
44 unsigned char size, offset;
46 size = (reg >> 24) & 0x3f;
47 offset = (reg >> 16) & 0x1f;
48 mask = ((1 << size) - 1) << offset;
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);
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;
65 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
67 unsigned int regptr;
68 unsigned long flags;
69 unsigned int mask;
71 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
72 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
74 if (reg & 0xff000000) {
75 unsigned char size, offset;
77 size = (reg >> 24) & 0x3f;
78 offset = (reg >> 16) & 0x1f;
79 mask = ((1 << size) - 1) << offset;
80 data = (data << offset) & mask;
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);
95 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
96 unsigned int reg,
97 unsigned int chn)
99 unsigned long flags;
100 unsigned int regptr, val;
102 regptr = (reg << 16) | chn;
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;
111 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
112 unsigned int reg,
113 unsigned int chn,
114 unsigned int data)
116 unsigned int regptr;
117 unsigned long flags;
119 regptr = (reg << 16) | chn;
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);
127 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
128 unsigned int data)
130 unsigned int reset, set;
131 unsigned int reg, tmp;
132 int n, result;
133 if (emu->card_capabilities->ca0108_chip)
134 reg = 0x3c; /* PTR20, reg 0x3c */
135 else {
136 /* For other chip types the SPI register
137 * is currently unknown. */
138 return 1;
140 if (data > 0xffff) /* Only 16bit values allowed */
141 return 1;
143 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
144 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
145 set = reset | 0x10000; /* Set xxx1xxxx */
146 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
147 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
148 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
149 result = 1;
150 /* Wait for status bit to return to 0 */
151 for (n = 0; n < 100; n++) {
152 udelay(10);
153 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
154 if (!(tmp & 0x10000)) {
155 result = 0;
156 break;
159 if (result) /* Timed out */
160 return 1;
161 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
162 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
163 return 0;
166 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
168 unsigned long flags;
169 unsigned int enable;
171 spin_lock_irqsave(&emu->emu_lock, flags);
172 enable = inl(emu->port + INTE) | intrenb;
173 outl(enable, emu->port + INTE);
174 spin_unlock_irqrestore(&emu->emu_lock, flags);
177 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
179 unsigned long flags;
180 unsigned int enable;
182 spin_lock_irqsave(&emu->emu_lock, flags);
183 enable = inl(emu->port + INTE) & ~intrenb;
184 outl(enable, emu->port + INTE);
185 spin_unlock_irqrestore(&emu->emu_lock, flags);
188 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
190 unsigned long flags;
191 unsigned int val;
193 spin_lock_irqsave(&emu->emu_lock, flags);
194 /* voice interrupt */
195 if (voicenum >= 32) {
196 outl(CLIEH << 16, emu->port + PTR);
197 val = inl(emu->port + DATA);
198 val |= 1 << (voicenum - 32);
199 } else {
200 outl(CLIEL << 16, emu->port + PTR);
201 val = inl(emu->port + DATA);
202 val |= 1 << voicenum;
204 outl(val, emu->port + DATA);
205 spin_unlock_irqrestore(&emu->emu_lock, flags);
208 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
210 unsigned long flags;
211 unsigned int val;
213 spin_lock_irqsave(&emu->emu_lock, flags);
214 /* voice interrupt */
215 if (voicenum >= 32) {
216 outl(CLIEH << 16, emu->port + PTR);
217 val = inl(emu->port + DATA);
218 val &= ~(1 << (voicenum - 32));
219 } else {
220 outl(CLIEL << 16, emu->port + PTR);
221 val = inl(emu->port + DATA);
222 val &= ~(1 << voicenum);
224 outl(val, emu->port + DATA);
225 spin_unlock_irqrestore(&emu->emu_lock, flags);
228 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
230 unsigned long flags;
232 spin_lock_irqsave(&emu->emu_lock, flags);
233 /* voice interrupt */
234 if (voicenum >= 32) {
235 outl(CLIPH << 16, emu->port + PTR);
236 voicenum = 1 << (voicenum - 32);
237 } else {
238 outl(CLIPL << 16, emu->port + PTR);
239 voicenum = 1 << voicenum;
241 outl(voicenum, emu->port + DATA);
242 spin_unlock_irqrestore(&emu->emu_lock, flags);
245 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
247 unsigned long flags;
248 unsigned int val;
250 spin_lock_irqsave(&emu->emu_lock, flags);
251 /* voice interrupt */
252 if (voicenum >= 32) {
253 outl(HLIEH << 16, emu->port + PTR);
254 val = inl(emu->port + DATA);
255 val |= 1 << (voicenum - 32);
256 } else {
257 outl(HLIEL << 16, emu->port + PTR);
258 val = inl(emu->port + DATA);
259 val |= 1 << voicenum;
261 outl(val, emu->port + DATA);
262 spin_unlock_irqrestore(&emu->emu_lock, flags);
265 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
267 unsigned long flags;
268 unsigned int val;
270 spin_lock_irqsave(&emu->emu_lock, flags);
271 /* voice interrupt */
272 if (voicenum >= 32) {
273 outl(HLIEH << 16, emu->port + PTR);
274 val = inl(emu->port + DATA);
275 val &= ~(1 << (voicenum - 32));
276 } else {
277 outl(HLIEL << 16, emu->port + PTR);
278 val = inl(emu->port + DATA);
279 val &= ~(1 << voicenum);
281 outl(val, emu->port + DATA);
282 spin_unlock_irqrestore(&emu->emu_lock, flags);
285 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
287 unsigned long flags;
289 spin_lock_irqsave(&emu->emu_lock, flags);
290 /* voice interrupt */
291 if (voicenum >= 32) {
292 outl(HLIPH << 16, emu->port + PTR);
293 voicenum = 1 << (voicenum - 32);
294 } else {
295 outl(HLIPL << 16, emu->port + PTR);
296 voicenum = 1 << voicenum;
298 outl(voicenum, emu->port + DATA);
299 spin_unlock_irqrestore(&emu->emu_lock, flags);
302 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
304 unsigned long flags;
305 unsigned int sol;
307 spin_lock_irqsave(&emu->emu_lock, flags);
308 /* voice interrupt */
309 if (voicenum >= 32) {
310 outl(SOLEH << 16, emu->port + PTR);
311 sol = inl(emu->port + DATA);
312 sol |= 1 << (voicenum - 32);
313 } else {
314 outl(SOLEL << 16, emu->port + PTR);
315 sol = inl(emu->port + DATA);
316 sol |= 1 << voicenum;
318 outl(sol, emu->port + DATA);
319 spin_unlock_irqrestore(&emu->emu_lock, flags);
322 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
324 unsigned long flags;
325 unsigned int sol;
327 spin_lock_irqsave(&emu->emu_lock, flags);
328 /* voice interrupt */
329 if (voicenum >= 32) {
330 outl(SOLEH << 16, emu->port + PTR);
331 sol = inl(emu->port + DATA);
332 sol &= ~(1 << (voicenum - 32));
333 } else {
334 outl(SOLEL << 16, emu->port + PTR);
335 sol = inl(emu->port + DATA);
336 sol &= ~(1 << voicenum);
338 outl(sol, emu->port + DATA);
339 spin_unlock_irqrestore(&emu->emu_lock, flags);
342 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
344 volatile unsigned count;
345 unsigned int newtime = 0, curtime;
347 curtime = inl(emu->port + WC) >> 6;
348 while (wait-- > 0) {
349 count = 0;
350 while (count++ < 16384) {
351 newtime = inl(emu->port + WC) >> 6;
352 if (newtime != curtime)
353 break;
355 if (count >= 16384)
356 break;
357 curtime = newtime;
361 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
363 struct snd_emu10k1 *emu = ac97->private_data;
364 unsigned long flags;
365 unsigned short val;
367 spin_lock_irqsave(&emu->emu_lock, flags);
368 outb(reg, emu->port + AC97ADDRESS);
369 val = inw(emu->port + AC97DATA);
370 spin_unlock_irqrestore(&emu->emu_lock, flags);
371 return val;
374 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
376 struct snd_emu10k1 *emu = ac97->private_data;
377 unsigned long flags;
379 spin_lock_irqsave(&emu->emu_lock, flags);
380 outb(reg, emu->port + AC97ADDRESS);
381 outw(data, emu->port + AC97DATA);
382 spin_unlock_irqrestore(&emu->emu_lock, flags);
386 * convert rate to pitch
389 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
391 static u32 logMagTable[128] = {
392 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
393 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
394 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
395 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
396 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
397 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
398 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
399 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
400 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
401 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
402 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
403 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
404 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
405 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
406 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
407 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
409 static char logSlopeTable[128] = {
410 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
411 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
412 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
413 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
414 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
415 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
416 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
417 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
418 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
419 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
420 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
421 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
422 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
423 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
424 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
425 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
427 int i;
429 if (rate == 0)
430 return 0; /* Bail out if no leading "1" */
431 rate *= 11185; /* Scale 48000 to 0x20002380 */
432 for (i = 31; i > 0; i--) {
433 if (rate & 0x80000000) { /* Detect leading "1" */
434 return (((unsigned int) (i - 15) << 20) +
435 logMagTable[0x7f & (rate >> 24)] +
436 (0x7f & (rate >> 17)) *
437 logSlopeTable[0x7f & (rate >> 24)]);
439 rate <<= 1;
442 return 0; /* Should never reach this point */