1 /*
2 * Copyright (c) by Jaroslav Kysela <perex@perex.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 <linux/time.h>
29 #include <sound/core.h>
30 #include <sound/emu10k1.h>
31 #include <linux/delay.h>
32 #include <linux/export.h>
33 #include "p17v.h"
34
snd_emu10k1_ptr_read(struct snd_emu10k1 * emu,unsigned int reg,unsigned int chn)35 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
36 {
37 unsigned long flags;
38 unsigned int regptr, val;
39 unsigned int mask;
40
41 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
42 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
43
44 if (reg & 0xff000000) {
45 unsigned char size, offset;
46
47 size = (reg >> 24) & 0x3f;
48 offset = (reg >> 16) & 0x1f;
49 mask = ((1 << size) - 1) << offset;
50
51 spin_lock_irqsave(&emu->emu_lock, flags);
52 outl(regptr, emu->port + PTR);
53 val = inl(emu->port + DATA);
54 spin_unlock_irqrestore(&emu->emu_lock, flags);
55
56 return (val & mask) >> offset;
57 } else {
58 spin_lock_irqsave(&emu->emu_lock, flags);
59 outl(regptr, emu->port + PTR);
60 val = inl(emu->port + DATA);
61 spin_unlock_irqrestore(&emu->emu_lock, flags);
62 return val;
63 }
64 }
65
66 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
67
snd_emu10k1_ptr_write(struct snd_emu10k1 * emu,unsigned int reg,unsigned int chn,unsigned int data)68 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
69 {
70 unsigned int regptr;
71 unsigned long flags;
72 unsigned int mask;
73
74 if (!emu) {
75 snd_printk(KERN_ERR "ptr_write: emu is null!\n");
76 dump_stack();
77 return;
78 }
79 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
80 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
81
82 if (reg & 0xff000000) {
83 unsigned char size, offset;
84
85 size = (reg >> 24) & 0x3f;
86 offset = (reg >> 16) & 0x1f;
87 mask = ((1 << size) - 1) << offset;
88 data = (data << offset) & mask;
89
90 spin_lock_irqsave(&emu->emu_lock, flags);
91 outl(regptr, emu->port + PTR);
92 data |= inl(emu->port + DATA) & ~mask;
93 outl(data, emu->port + DATA);
94 spin_unlock_irqrestore(&emu->emu_lock, flags);
95 } else {
96 spin_lock_irqsave(&emu->emu_lock, flags);
97 outl(regptr, emu->port + PTR);
98 outl(data, emu->port + DATA);
99 spin_unlock_irqrestore(&emu->emu_lock, flags);
100 }
101 }
102
103 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
104
snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,unsigned int reg,unsigned int chn)105 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu,
106 unsigned int reg,
107 unsigned int chn)
108 {
109 unsigned long flags;
110 unsigned int regptr, val;
111
112 regptr = (reg << 16) | chn;
113
114 spin_lock_irqsave(&emu->emu_lock, flags);
115 outl(regptr, emu->port + 0x20 + PTR);
116 val = inl(emu->port + 0x20 + DATA);
117 spin_unlock_irqrestore(&emu->emu_lock, flags);
118 return val;
119 }
120
snd_emu10k1_ptr20_write(struct snd_emu10k1 * emu,unsigned int reg,unsigned int chn,unsigned int data)121 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu,
122 unsigned int reg,
123 unsigned int chn,
124 unsigned int data)
125 {
126 unsigned int regptr;
127 unsigned long flags;
128
129 regptr = (reg << 16) | chn;
130
131 spin_lock_irqsave(&emu->emu_lock, flags);
132 outl(regptr, emu->port + 0x20 + PTR);
133 outl(data, emu->port + 0x20 + DATA);
134 spin_unlock_irqrestore(&emu->emu_lock, flags);
135 }
136
snd_emu10k1_spi_write(struct snd_emu10k1 * emu,unsigned int data)137 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
138 unsigned int data)
139 {
140 unsigned int reset, set;
141 unsigned int reg, tmp;
142 int n, result;
143 int err = 0;
144
145 /* This function is not re-entrant, so protect against it. */
146 spin_lock(&emu->spi_lock);
147 if (emu->card_capabilities->ca0108_chip)
148 reg = 0x3c; /* PTR20, reg 0x3c */
149 else {
150 /* For other chip types the SPI register
151 * is currently unknown. */
152 err = 1;
153 goto spi_write_exit;
154 }
155 if (data > 0xffff) {
156 /* Only 16bit values allowed */
157 err = 1;
158 goto spi_write_exit;
159 }
160
161 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
162 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
163 set = reset | 0x10000; /* Set xxx1xxxx */
164 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
165 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
166 snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
167 result = 1;
168 /* Wait for status bit to return to 0 */
169 for (n = 0; n < 100; n++) {
170 udelay(10);
171 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
172 if (!(tmp & 0x10000)) {
173 result = 0;
174 break;
175 }
176 }
177 if (result) {
178 /* Timed out */
179 err = 1;
180 goto spi_write_exit;
181 }
182 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
183 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
184 err = 0;
185 spi_write_exit:
186 spin_unlock(&emu->spi_lock);
187 return err;
188 }
189
190 /* The ADC does not support i2c read, so only write is implemented */
snd_emu10k1_i2c_write(struct snd_emu10k1 * emu,u32 reg,u32 value)191 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
192 u32 reg,
193 u32 value)
194 {
195 u32 tmp;
196 int timeout = 0;
197 int status;
198 int retry;
199 int err = 0;
200
201 if ((reg > 0x7f) || (value > 0x1ff)) {
202 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
203 return -EINVAL;
204 }
205
206 /* This function is not re-entrant, so protect against it. */
207 spin_lock(&emu->i2c_lock);
208
209 tmp = reg << 25 | value << 16;
210
211 /* This controls the I2C connected to the WM8775 ADC Codec */
212 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
213 tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
214
215 for (retry = 0; retry < 10; retry++) {
216 /* Send the data to i2c */
217 tmp = 0;
218 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
219 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
220
221 /* Wait till the transaction ends */
222 while (1) {
223 mdelay(1);
224 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
225 timeout++;
226 if ((status & I2C_A_ADC_START) == 0)
227 break;
228
229 if (timeout > 1000) {
230 snd_printk(KERN_WARNING
231 "emu10k1:I2C:timeout status=0x%x\n",
232 status);
233 break;
234 }
235 }
236 //Read back and see if the transaction is successful
237 if ((status & I2C_A_ADC_ABORT) == 0)
238 break;
239 }
240
241 if (retry == 10) {
242 snd_printk(KERN_ERR "Writing to ADC failed!\n");
243 snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
244 status, reg, value);
245 /* dump_stack(); */
246 err = -EINVAL;
247 }
248
249 spin_unlock(&emu->i2c_lock);
250 return err;
251 }
252
snd_emu1010_fpga_write(struct snd_emu10k1 * emu,u32 reg,u32 value)253 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
254 {
255 unsigned long flags;
256
257 if (reg > 0x3f)
258 return 1;
259 reg += 0x40; /* 0x40 upwards are registers. */
260 if (value > 0x3f) /* 0 to 0x3f are values */
261 return 1;
262 spin_lock_irqsave(&emu->emu_lock, flags);
263 outl(reg, emu->port + A_IOCFG);
264 udelay(10);
265 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
266 udelay(10);
267 outl(value, emu->port + A_IOCFG);
268 udelay(10);
269 outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
270 spin_unlock_irqrestore(&emu->emu_lock, flags);
271
272 return 0;
273 }
274
snd_emu1010_fpga_read(struct snd_emu10k1 * emu,u32 reg,u32 * value)275 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
276 {
277 unsigned long flags;
278 if (reg > 0x3f)
279 return 1;
280 reg += 0x40; /* 0x40 upwards are registers. */
281 spin_lock_irqsave(&emu->emu_lock, flags);
282 outl(reg, emu->port + A_IOCFG);
283 udelay(10);
284 outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */
285 udelay(10);
286 *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
287 spin_unlock_irqrestore(&emu->emu_lock, flags);
288
289 return 0;
290 }
291
292 /* Each Destination has one and only one Source,
293 * but one Source can feed any number of Destinations simultaneously.
294 */
snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu,u32 dst,u32 src)295 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
296 {
297 snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
298 snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
299 snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
300 snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
301
302 return 0;
303 }
304
snd_emu10k1_intr_enable(struct snd_emu10k1 * emu,unsigned int intrenb)305 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
306 {
307 unsigned long flags;
308 unsigned int enable;
309
310 spin_lock_irqsave(&emu->emu_lock, flags);
311 enable = inl(emu->port + INTE) | intrenb;
312 outl(enable, emu->port + INTE);
313 spin_unlock_irqrestore(&emu->emu_lock, flags);
314 }
315
snd_emu10k1_intr_disable(struct snd_emu10k1 * emu,unsigned int intrenb)316 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
317 {
318 unsigned long flags;
319 unsigned int enable;
320
321 spin_lock_irqsave(&emu->emu_lock, flags);
322 enable = inl(emu->port + INTE) & ~intrenb;
323 outl(enable, emu->port + INTE);
324 spin_unlock_irqrestore(&emu->emu_lock, flags);
325 }
326
snd_emu10k1_voice_intr_enable(struct snd_emu10k1 * emu,unsigned int voicenum)327 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
328 {
329 unsigned long flags;
330 unsigned int val;
331
332 spin_lock_irqsave(&emu->emu_lock, flags);
333 /* voice interrupt */
334 if (voicenum >= 32) {
335 outl(CLIEH << 16, emu->port + PTR);
336 val = inl(emu->port + DATA);
337 val |= 1 << (voicenum - 32);
338 } else {
339 outl(CLIEL << 16, emu->port + PTR);
340 val = inl(emu->port + DATA);
341 val |= 1 << voicenum;
342 }
343 outl(val, emu->port + DATA);
344 spin_unlock_irqrestore(&emu->emu_lock, flags);
345 }
346
snd_emu10k1_voice_intr_disable(struct snd_emu10k1 * emu,unsigned int voicenum)347 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
348 {
349 unsigned long flags;
350 unsigned int val;
351
352 spin_lock_irqsave(&emu->emu_lock, flags);
353 /* voice interrupt */
354 if (voicenum >= 32) {
355 outl(CLIEH << 16, emu->port + PTR);
356 val = inl(emu->port + DATA);
357 val &= ~(1 << (voicenum - 32));
358 } else {
359 outl(CLIEL << 16, emu->port + PTR);
360 val = inl(emu->port + DATA);
361 val &= ~(1 << voicenum);
362 }
363 outl(val, emu->port + DATA);
364 spin_unlock_irqrestore(&emu->emu_lock, flags);
365 }
366
snd_emu10k1_voice_intr_ack(struct snd_emu10k1 * emu,unsigned int voicenum)367 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
368 {
369 unsigned long flags;
370
371 spin_lock_irqsave(&emu->emu_lock, flags);
372 /* voice interrupt */
373 if (voicenum >= 32) {
374 outl(CLIPH << 16, emu->port + PTR);
375 voicenum = 1 << (voicenum - 32);
376 } else {
377 outl(CLIPL << 16, emu->port + PTR);
378 voicenum = 1 << voicenum;
379 }
380 outl(voicenum, emu->port + DATA);
381 spin_unlock_irqrestore(&emu->emu_lock, flags);
382 }
383
snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 * emu,unsigned int voicenum)384 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
385 {
386 unsigned long flags;
387 unsigned int val;
388
389 spin_lock_irqsave(&emu->emu_lock, flags);
390 /* voice interrupt */
391 if (voicenum >= 32) {
392 outl(HLIEH << 16, emu->port + PTR);
393 val = inl(emu->port + DATA);
394 val |= 1 << (voicenum - 32);
395 } else {
396 outl(HLIEL << 16, emu->port + PTR);
397 val = inl(emu->port + DATA);
398 val |= 1 << voicenum;
399 }
400 outl(val, emu->port + DATA);
401 spin_unlock_irqrestore(&emu->emu_lock, flags);
402 }
403
snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 * emu,unsigned int voicenum)404 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
405 {
406 unsigned long flags;
407 unsigned int val;
408
409 spin_lock_irqsave(&emu->emu_lock, flags);
410 /* voice interrupt */
411 if (voicenum >= 32) {
412 outl(HLIEH << 16, emu->port + PTR);
413 val = inl(emu->port + DATA);
414 val &= ~(1 << (voicenum - 32));
415 } else {
416 outl(HLIEL << 16, emu->port + PTR);
417 val = inl(emu->port + DATA);
418 val &= ~(1 << voicenum);
419 }
420 outl(val, emu->port + DATA);
421 spin_unlock_irqrestore(&emu->emu_lock, flags);
422 }
423
snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 * emu,unsigned int voicenum)424 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
425 {
426 unsigned long flags;
427
428 spin_lock_irqsave(&emu->emu_lock, flags);
429 /* voice interrupt */
430 if (voicenum >= 32) {
431 outl(HLIPH << 16, emu->port + PTR);
432 voicenum = 1 << (voicenum - 32);
433 } else {
434 outl(HLIPL << 16, emu->port + PTR);
435 voicenum = 1 << voicenum;
436 }
437 outl(voicenum, emu->port + DATA);
438 spin_unlock_irqrestore(&emu->emu_lock, flags);
439 }
440
snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 * emu,unsigned int voicenum)441 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
442 {
443 unsigned long flags;
444 unsigned int sol;
445
446 spin_lock_irqsave(&emu->emu_lock, flags);
447 /* voice interrupt */
448 if (voicenum >= 32) {
449 outl(SOLEH << 16, emu->port + PTR);
450 sol = inl(emu->port + DATA);
451 sol |= 1 << (voicenum - 32);
452 } else {
453 outl(SOLEL << 16, emu->port + PTR);
454 sol = inl(emu->port + DATA);
455 sol |= 1 << voicenum;
456 }
457 outl(sol, emu->port + DATA);
458 spin_unlock_irqrestore(&emu->emu_lock, flags);
459 }
460
snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 * emu,unsigned int voicenum)461 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
462 {
463 unsigned long flags;
464 unsigned int sol;
465
466 spin_lock_irqsave(&emu->emu_lock, flags);
467 /* voice interrupt */
468 if (voicenum >= 32) {
469 outl(SOLEH << 16, emu->port + PTR);
470 sol = inl(emu->port + DATA);
471 sol &= ~(1 << (voicenum - 32));
472 } else {
473 outl(SOLEL << 16, emu->port + PTR);
474 sol = inl(emu->port + DATA);
475 sol &= ~(1 << voicenum);
476 }
477 outl(sol, emu->port + DATA);
478 spin_unlock_irqrestore(&emu->emu_lock, flags);
479 }
480
snd_emu10k1_wait(struct snd_emu10k1 * emu,unsigned int wait)481 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
482 {
483 volatile unsigned count;
484 unsigned int newtime = 0, curtime;
485
486 curtime = inl(emu->port + WC) >> 6;
487 while (wait-- > 0) {
488 count = 0;
489 while (count++ < 16384) {
490 newtime = inl(emu->port + WC) >> 6;
491 if (newtime != curtime)
492 break;
493 }
494 if (count > 16384)
495 break;
496 curtime = newtime;
497 }
498 }
499
snd_emu10k1_ac97_read(struct snd_ac97 * ac97,unsigned short reg)500 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
501 {
502 struct snd_emu10k1 *emu = ac97->private_data;
503 unsigned long flags;
504 unsigned short val;
505
506 spin_lock_irqsave(&emu->emu_lock, flags);
507 outb(reg, emu->port + AC97ADDRESS);
508 val = inw(emu->port + AC97DATA);
509 spin_unlock_irqrestore(&emu->emu_lock, flags);
510 return val;
511 }
512
snd_emu10k1_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short data)513 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
514 {
515 struct snd_emu10k1 *emu = ac97->private_data;
516 unsigned long flags;
517
518 spin_lock_irqsave(&emu->emu_lock, flags);
519 outb(reg, emu->port + AC97ADDRESS);
520 outw(data, emu->port + AC97DATA);
521 spin_unlock_irqrestore(&emu->emu_lock, flags);
522 }
523
524 /*
525 * convert rate to pitch
526 */
527
snd_emu10k1_rate_to_pitch(unsigned int rate)528 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
529 {
530 static u32 logMagTable[128] = {
531 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
532 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
533 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
534 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
535 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
536 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
537 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
538 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
539 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
540 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
541 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
542 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
543 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
544 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
545 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
546 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
547 };
548 static char logSlopeTable[128] = {
549 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
550 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
551 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
552 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
553 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
554 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
555 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
556 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
557 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
558 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
559 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
560 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
561 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
562 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
563 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
564 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
565 };
566 int i;
567
568 if (rate == 0)
569 return 0; /* Bail out if no leading "1" */
570 rate *= 11185; /* Scale 48000 to 0x20002380 */
571 for (i = 31; i > 0; i--) {
572 if (rate & 0x80000000) { /* Detect leading "1" */
573 return (((unsigned int) (i - 15) << 20) +
574 logMagTable[0x7f & (rate >> 24)] +
575 (0x7f & (rate >> 17)) *
576 logSlopeTable[0x7f & (rate >> 24)]);
577 }
578 rate <<= 1;
579 }
580
581 return 0; /* Should never reach this point */
582 }
583
584