• 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 (!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