USB: unusual_dev entry for Sony P990i
[linux-2.6/verdex.git] / sound / pci / emu10k1 / io.c
blob029e7856c43beaa7d171a22696d95410119b7b43
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 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
67 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
69 unsigned int regptr;
70 unsigned long flags;
71 unsigned int mask;
73 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
74 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
76 if (reg & 0xff000000) {
77 unsigned char size, offset;
79 size = (reg >> 24) & 0x3f;
80 offset = (reg >> 16) & 0x1f;
81 mask = ((1 << size) - 1) << offset;
82 data = (data << offset) & mask;
84 spin_lock_irqsave(&emu->emu_lock, flags);
85 outl(regptr, emu->port + PTR);
86 data |= inl(emu->port + DATA) & ~mask;
87 outl(data, emu->port + DATA);
88 spin_unlock_irqrestore(&emu->emu_lock, flags);
89 } else {
90 spin_lock_irqsave(&emu->emu_lock, flags);
91 outl(regptr, emu->port + PTR);
92 outl(data, emu->port + DATA);
93 spin_unlock_irqrestore(&emu->emu_lock, flags);
97 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
99 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
100 unsigned int reg,
101 unsigned int chn)
103 unsigned long flags;
104 unsigned int regptr, val;
106 regptr = (reg << 16) | chn;
108 spin_lock_irqsave(&emu->emu_lock, flags);
109 outl(regptr, emu->port + 0x20 + PTR);
110 val = inl(emu->port + 0x20 + DATA);
111 spin_unlock_irqrestore(&emu->emu_lock, flags);
112 return val;
115 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
116 unsigned int reg,
117 unsigned int chn,
118 unsigned int data)
120 unsigned int regptr;
121 unsigned long flags;
123 regptr = (reg << 16) | chn;
125 spin_lock_irqsave(&emu->emu_lock, flags);
126 outl(regptr, emu->port + 0x20 + PTR);
127 outl(data, emu->port + 0x20 + DATA);
128 spin_unlock_irqrestore(&emu->emu_lock, flags);
131 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
132 unsigned int data)
134 unsigned int reset, set;
135 unsigned int reg, tmp;
136 int n, result;
137 if (emu->card_capabilities->ca0108_chip)
138 reg = 0x3c; /* PTR20, reg 0x3c */
139 else {
140 /* For other chip types the SPI register
141 * is currently unknown. */
142 return 1;
144 if (data > 0xffff) /* Only 16bit values allowed */
145 return 1;
147 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
148 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
149 set = reset | 0x10000; /* Set xxx1xxxx */
150 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
151 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
152 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
153 result = 1;
154 /* Wait for status bit to return to 0 */
155 for (n = 0; n < 100; n++) {
156 udelay(10);
157 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
158 if (!(tmp & 0x10000)) {
159 result = 0;
160 break;
163 if (result) /* Timed out */
164 return 1;
165 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
166 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
167 return 0;
170 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
172 unsigned long flags;
173 unsigned int enable;
175 spin_lock_irqsave(&emu->emu_lock, flags);
176 enable = inl(emu->port + INTE) | intrenb;
177 outl(enable, emu->port + INTE);
178 spin_unlock_irqrestore(&emu->emu_lock, flags);
181 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
183 unsigned long flags;
184 unsigned int enable;
186 spin_lock_irqsave(&emu->emu_lock, flags);
187 enable = inl(emu->port + INTE) & ~intrenb;
188 outl(enable, emu->port + INTE);
189 spin_unlock_irqrestore(&emu->emu_lock, flags);
192 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
194 unsigned long flags;
195 unsigned int val;
197 spin_lock_irqsave(&emu->emu_lock, flags);
198 /* voice interrupt */
199 if (voicenum >= 32) {
200 outl(CLIEH << 16, emu->port + PTR);
201 val = inl(emu->port + DATA);
202 val |= 1 << (voicenum - 32);
203 } else {
204 outl(CLIEL << 16, emu->port + PTR);
205 val = inl(emu->port + DATA);
206 val |= 1 << voicenum;
208 outl(val, emu->port + DATA);
209 spin_unlock_irqrestore(&emu->emu_lock, flags);
212 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
214 unsigned long flags;
215 unsigned int val;
217 spin_lock_irqsave(&emu->emu_lock, flags);
218 /* voice interrupt */
219 if (voicenum >= 32) {
220 outl(CLIEH << 16, emu->port + PTR);
221 val = inl(emu->port + DATA);
222 val &= ~(1 << (voicenum - 32));
223 } else {
224 outl(CLIEL << 16, emu->port + PTR);
225 val = inl(emu->port + DATA);
226 val &= ~(1 << voicenum);
228 outl(val, emu->port + DATA);
229 spin_unlock_irqrestore(&emu->emu_lock, flags);
232 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
234 unsigned long flags;
236 spin_lock_irqsave(&emu->emu_lock, flags);
237 /* voice interrupt */
238 if (voicenum >= 32) {
239 outl(CLIPH << 16, emu->port + PTR);
240 voicenum = 1 << (voicenum - 32);
241 } else {
242 outl(CLIPL << 16, emu->port + PTR);
243 voicenum = 1 << voicenum;
245 outl(voicenum, emu->port + DATA);
246 spin_unlock_irqrestore(&emu->emu_lock, flags);
249 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
251 unsigned long flags;
252 unsigned int val;
254 spin_lock_irqsave(&emu->emu_lock, flags);
255 /* voice interrupt */
256 if (voicenum >= 32) {
257 outl(HLIEH << 16, emu->port + PTR);
258 val = inl(emu->port + DATA);
259 val |= 1 << (voicenum - 32);
260 } else {
261 outl(HLIEL << 16, emu->port + PTR);
262 val = inl(emu->port + DATA);
263 val |= 1 << voicenum;
265 outl(val, emu->port + DATA);
266 spin_unlock_irqrestore(&emu->emu_lock, flags);
269 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
271 unsigned long flags;
272 unsigned int val;
274 spin_lock_irqsave(&emu->emu_lock, flags);
275 /* voice interrupt */
276 if (voicenum >= 32) {
277 outl(HLIEH << 16, emu->port + PTR);
278 val = inl(emu->port + DATA);
279 val &= ~(1 << (voicenum - 32));
280 } else {
281 outl(HLIEL << 16, emu->port + PTR);
282 val = inl(emu->port + DATA);
283 val &= ~(1 << voicenum);
285 outl(val, emu->port + DATA);
286 spin_unlock_irqrestore(&emu->emu_lock, flags);
289 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
291 unsigned long flags;
293 spin_lock_irqsave(&emu->emu_lock, flags);
294 /* voice interrupt */
295 if (voicenum >= 32) {
296 outl(HLIPH << 16, emu->port + PTR);
297 voicenum = 1 << (voicenum - 32);
298 } else {
299 outl(HLIPL << 16, emu->port + PTR);
300 voicenum = 1 << voicenum;
302 outl(voicenum, emu->port + DATA);
303 spin_unlock_irqrestore(&emu->emu_lock, flags);
306 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
308 unsigned long flags;
309 unsigned int sol;
311 spin_lock_irqsave(&emu->emu_lock, flags);
312 /* voice interrupt */
313 if (voicenum >= 32) {
314 outl(SOLEH << 16, emu->port + PTR);
315 sol = inl(emu->port + DATA);
316 sol |= 1 << (voicenum - 32);
317 } else {
318 outl(SOLEL << 16, emu->port + PTR);
319 sol = inl(emu->port + DATA);
320 sol |= 1 << voicenum;
322 outl(sol, emu->port + DATA);
323 spin_unlock_irqrestore(&emu->emu_lock, flags);
326 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
328 unsigned long flags;
329 unsigned int sol;
331 spin_lock_irqsave(&emu->emu_lock, flags);
332 /* voice interrupt */
333 if (voicenum >= 32) {
334 outl(SOLEH << 16, emu->port + PTR);
335 sol = inl(emu->port + DATA);
336 sol &= ~(1 << (voicenum - 32));
337 } else {
338 outl(SOLEL << 16, emu->port + PTR);
339 sol = inl(emu->port + DATA);
340 sol &= ~(1 << voicenum);
342 outl(sol, emu->port + DATA);
343 spin_unlock_irqrestore(&emu->emu_lock, flags);
346 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
348 volatile unsigned count;
349 unsigned int newtime = 0, curtime;
351 curtime = inl(emu->port + WC) >> 6;
352 while (wait-- > 0) {
353 count = 0;
354 while (count++ < 16384) {
355 newtime = inl(emu->port + WC) >> 6;
356 if (newtime != curtime)
357 break;
359 if (count >= 16384)
360 break;
361 curtime = newtime;
365 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
367 struct snd_emu10k1 *emu = ac97->private_data;
368 unsigned long flags;
369 unsigned short val;
371 spin_lock_irqsave(&emu->emu_lock, flags);
372 outb(reg, emu->port + AC97ADDRESS);
373 val = inw(emu->port + AC97DATA);
374 spin_unlock_irqrestore(&emu->emu_lock, flags);
375 return val;
378 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
380 struct snd_emu10k1 *emu = ac97->private_data;
381 unsigned long flags;
383 spin_lock_irqsave(&emu->emu_lock, flags);
384 outb(reg, emu->port + AC97ADDRESS);
385 outw(data, emu->port + AC97DATA);
386 spin_unlock_irqrestore(&emu->emu_lock, flags);
390 * convert rate to pitch
393 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
395 static u32 logMagTable[128] = {
396 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
397 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
398 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
399 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
400 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
401 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
402 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
403 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
404 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
405 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
406 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
407 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
408 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
409 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
410 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
411 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
413 static char logSlopeTable[128] = {
414 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
415 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
416 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
417 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
418 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
419 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
420 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
421 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
422 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
423 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
424 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
425 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
426 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
427 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
428 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
429 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
431 int i;
433 if (rate == 0)
434 return 0; /* Bail out if no leading "1" */
435 rate *= 11185; /* Scale 48000 to 0x20002380 */
436 for (i = 31; i > 0; i--) {
437 if (rate & 0x80000000) { /* Detect leading "1" */
438 return (((unsigned int) (i - 15) << 20) +
439 logMagTable[0x7f & (rate >> 24)] +
440 (0x7f & (rate >> 17)) *
441 logSlopeTable[0x7f & (rate >> 24)]);
443 rate <<= 1;
446 return 0; /* Should never reach this point */