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