blob: 27ab7d1788a039136f24c9589b04f79a79e6e503 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
James Courtier-Dutton27fe8642005-12-21 15:06:08 +010032#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Takashi Iwaieb4698f2005-11-17 14:50:13 +010034unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035{
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
Takashi Iwai2dd31de2006-04-28 15:13:39 +020065EXPORT_SYMBOL(snd_emu10k1_ptr_read);
66
Takashi Iwaieb4698f2005-11-17 14:50:13 +010067void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068{
69 unsigned int regptr;
70 unsigned long flags;
71 unsigned int mask;
72
73 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
74 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
75
76 if (reg & 0xff000000) {
77 unsigned char size, offset;
78
79 size = (reg >> 24) & 0x3f;
80 offset = (reg >> 16) & 0x1f;
81 mask = ((1 << size) - 1) << offset;
82 data = (data << offset) & mask;
83
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);
94 }
95}
96
Takashi Iwai2dd31de2006-04-28 15:13:39 +020097EXPORT_SYMBOL(snd_emu10k1_ptr_write);
98
Takashi Iwaieb4698f2005-11-17 14:50:13 +010099unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 unsigned int reg,
101 unsigned int chn)
102{
103 unsigned long flags;
104 unsigned int regptr, val;
105
106 regptr = (reg << 16) | chn;
107
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;
113}
114
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100115void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 unsigned int reg,
117 unsigned int chn,
118 unsigned int data)
119{
120 unsigned int regptr;
121 unsigned long flags;
122
123 regptr = (reg << 16) | chn;
124
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);
129}
130
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100131int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
132 unsigned int data)
133{
134 unsigned int reset, set;
135 unsigned int reg, tmp;
136 int n, result;
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100137 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;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100143 }
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100144 if (data > 0xffff) /* Only 16bit values allowed */
145 return 1;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100146
147 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
James Courtier-Dutton28bcbdd2005-12-21 15:41:50 +0100148 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100149 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 */
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100155 for (n = 0; n < 100; n++) {
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100156 udelay(10);
157 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
158 if (!(tmp & 0x10000)) {
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100159 result = 0;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100160 break;
161 }
162 }
James Courtier-Duttonc6a02ca2005-12-21 15:56:01 +0100163 if (result) /* Timed out */
164 return 1;
James Courtier-Dutton27fe8642005-12-21 15:06:08 +0100165 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
166 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
167 return 0;
168}
169
James Courtier-Dutton9f4bd5d2006-10-01 10:48:04 +0100170int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value)
171{
172 if (reg < 0 || reg > 0x3f)
173 return 1;
174 reg += 0x40; /* 0x40 upwards are registers. */
175 if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
176 return 1;
177 outl(reg, emu->port + A_IOCFG);
178 udelay(10);
179 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
180 udelay(10);
181 outl(value, emu->port + A_IOCFG);
182 udelay(10);
183 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
184
185 return 0;
186}
187
188int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, int reg, int *value)
189{
190 if (reg < 0 || reg > 0x3f)
191 return 1;
192 reg += 0x40; /* 0x40 upwards are registers. */
193 outl(reg, emu->port + A_IOCFG);
194 udelay(10);
195 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
196 udelay(10);
197 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
198
199 return 0;
200}
201
202/* Each Destination has one and only one Source,
203 * but one Source can feed any number of Destinations simultaneously.
204 */
205int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, int dst, int src)
206{
207 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
208 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
209 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
210 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
211
212 return 0;
213}
214
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100215void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 unsigned long flags;
218 unsigned int enable;
219
220 spin_lock_irqsave(&emu->emu_lock, flags);
221 enable = inl(emu->port + INTE) | intrenb;
222 outl(enable, emu->port + INTE);
223 spin_unlock_irqrestore(&emu->emu_lock, flags);
224}
225
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100226void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 unsigned long flags;
229 unsigned int enable;
230
231 spin_lock_irqsave(&emu->emu_lock, flags);
232 enable = inl(emu->port + INTE) & ~intrenb;
233 outl(enable, emu->port + INTE);
234 spin_unlock_irqrestore(&emu->emu_lock, flags);
235}
236
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100237void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238{
239 unsigned long flags;
240 unsigned int val;
241
242 spin_lock_irqsave(&emu->emu_lock, flags);
243 /* voice interrupt */
244 if (voicenum >= 32) {
245 outl(CLIEH << 16, emu->port + PTR);
246 val = inl(emu->port + DATA);
247 val |= 1 << (voicenum - 32);
248 } else {
249 outl(CLIEL << 16, emu->port + PTR);
250 val = inl(emu->port + DATA);
251 val |= 1 << voicenum;
252 }
253 outl(val, emu->port + DATA);
254 spin_unlock_irqrestore(&emu->emu_lock, flags);
255}
256
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100257void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258{
259 unsigned long flags;
260 unsigned int val;
261
262 spin_lock_irqsave(&emu->emu_lock, flags);
263 /* voice interrupt */
264 if (voicenum >= 32) {
265 outl(CLIEH << 16, emu->port + PTR);
266 val = inl(emu->port + DATA);
267 val &= ~(1 << (voicenum - 32));
268 } else {
269 outl(CLIEL << 16, emu->port + PTR);
270 val = inl(emu->port + DATA);
271 val &= ~(1 << voicenum);
272 }
273 outl(val, emu->port + DATA);
274 spin_unlock_irqrestore(&emu->emu_lock, flags);
275}
276
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100277void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278{
279 unsigned long flags;
280
281 spin_lock_irqsave(&emu->emu_lock, flags);
282 /* voice interrupt */
283 if (voicenum >= 32) {
284 outl(CLIPH << 16, emu->port + PTR);
285 voicenum = 1 << (voicenum - 32);
286 } else {
287 outl(CLIPL << 16, emu->port + PTR);
288 voicenum = 1 << voicenum;
289 }
290 outl(voicenum, emu->port + DATA);
291 spin_unlock_irqrestore(&emu->emu_lock, flags);
292}
293
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100294void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295{
296 unsigned long flags;
297 unsigned int val;
298
299 spin_lock_irqsave(&emu->emu_lock, flags);
300 /* voice interrupt */
301 if (voicenum >= 32) {
302 outl(HLIEH << 16, emu->port + PTR);
303 val = inl(emu->port + DATA);
304 val |= 1 << (voicenum - 32);
305 } else {
306 outl(HLIEL << 16, emu->port + PTR);
307 val = inl(emu->port + DATA);
308 val |= 1 << voicenum;
309 }
310 outl(val, emu->port + DATA);
311 spin_unlock_irqrestore(&emu->emu_lock, flags);
312}
313
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100314void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
316 unsigned long flags;
317 unsigned int val;
318
319 spin_lock_irqsave(&emu->emu_lock, flags);
320 /* voice interrupt */
321 if (voicenum >= 32) {
322 outl(HLIEH << 16, emu->port + PTR);
323 val = inl(emu->port + DATA);
324 val &= ~(1 << (voicenum - 32));
325 } else {
326 outl(HLIEL << 16, emu->port + PTR);
327 val = inl(emu->port + DATA);
328 val &= ~(1 << voicenum);
329 }
330 outl(val, emu->port + DATA);
331 spin_unlock_irqrestore(&emu->emu_lock, flags);
332}
333
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100334void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336 unsigned long flags;
337
338 spin_lock_irqsave(&emu->emu_lock, flags);
339 /* voice interrupt */
340 if (voicenum >= 32) {
341 outl(HLIPH << 16, emu->port + PTR);
342 voicenum = 1 << (voicenum - 32);
343 } else {
344 outl(HLIPL << 16, emu->port + PTR);
345 voicenum = 1 << voicenum;
346 }
347 outl(voicenum, emu->port + DATA);
348 spin_unlock_irqrestore(&emu->emu_lock, flags);
349}
350
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100351void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
353 unsigned long flags;
354 unsigned int sol;
355
356 spin_lock_irqsave(&emu->emu_lock, flags);
357 /* voice interrupt */
358 if (voicenum >= 32) {
359 outl(SOLEH << 16, emu->port + PTR);
360 sol = inl(emu->port + DATA);
361 sol |= 1 << (voicenum - 32);
362 } else {
363 outl(SOLEL << 16, emu->port + PTR);
364 sol = inl(emu->port + DATA);
365 sol |= 1 << voicenum;
366 }
367 outl(sol, emu->port + DATA);
368 spin_unlock_irqrestore(&emu->emu_lock, flags);
369}
370
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100371void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372{
373 unsigned long flags;
374 unsigned int sol;
375
376 spin_lock_irqsave(&emu->emu_lock, flags);
377 /* voice interrupt */
378 if (voicenum >= 32) {
379 outl(SOLEH << 16, emu->port + PTR);
380 sol = inl(emu->port + DATA);
381 sol &= ~(1 << (voicenum - 32));
382 } else {
383 outl(SOLEL << 16, emu->port + PTR);
384 sol = inl(emu->port + DATA);
385 sol &= ~(1 << voicenum);
386 }
387 outl(sol, emu->port + DATA);
388 spin_unlock_irqrestore(&emu->emu_lock, flags);
389}
390
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100391void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
393 volatile unsigned count;
394 unsigned int newtime = 0, curtime;
395
396 curtime = inl(emu->port + WC) >> 6;
397 while (wait-- > 0) {
398 count = 0;
399 while (count++ < 16384) {
400 newtime = inl(emu->port + WC) >> 6;
401 if (newtime != curtime)
402 break;
403 }
404 if (count >= 16384)
405 break;
406 curtime = newtime;
407 }
408}
409
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100410unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100412 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 unsigned long flags;
414 unsigned short val;
415
416 spin_lock_irqsave(&emu->emu_lock, flags);
417 outb(reg, emu->port + AC97ADDRESS);
418 val = inw(emu->port + AC97DATA);
419 spin_unlock_irqrestore(&emu->emu_lock, flags);
420 return val;
421}
422
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100423void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424{
Takashi Iwaieb4698f2005-11-17 14:50:13 +0100425 struct snd_emu10k1 *emu = ac97->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 unsigned long flags;
427
428 spin_lock_irqsave(&emu->emu_lock, flags);
429 outb(reg, emu->port + AC97ADDRESS);
430 outw(data, emu->port + AC97DATA);
431 spin_unlock_irqrestore(&emu->emu_lock, flags);
432}
433
434/*
435 * convert rate to pitch
436 */
437
438unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
439{
440 static u32 logMagTable[128] = {
441 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
442 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
443 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
444 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
445 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
446 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
447 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
448 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
449 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
450 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
451 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
452 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
453 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
454 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
455 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
456 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
457 };
458 static char logSlopeTable[128] = {
459 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
460 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
461 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
462 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
463 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
464 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
465 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
466 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
467 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
468 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
469 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
470 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
471 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
472 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
473 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
474 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
475 };
476 int i;
477
478 if (rate == 0)
479 return 0; /* Bail out if no leading "1" */
480 rate *= 11185; /* Scale 48000 to 0x20002380 */
481 for (i = 31; i > 0; i--) {
482 if (rate & 0x80000000) { /* Detect leading "1" */
483 return (((unsigned int) (i - 15) << 20) +
484 logMagTable[0x7f & (rate >> 24)] +
485 (0x7f & (rate >> 17)) *
486 logSlopeTable[0x7f & (rate >> 24)]);
487 }
488 rate <<= 1;
489 }
490
491 return 0; /* Should never reach this point */
492}
493