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