xref: /linux/sound/pci/emu10k1/io.c (revision 2f804aca48322f02a8f44cca540663845ee80fb1)
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 
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 
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 
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 + PTR2);
99 	val = inl(emu->port + DATA2);
100 	spin_unlock_irqrestore(&emu->emu_lock, flags);
101 	return val;
102 }
103 
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 + PTR2);
116 	outl(data, emu->port + DATA2);
117 	spin_unlock_irqrestore(&emu->emu_lock, flags);
118 }
119 
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 = P17V_SPI;
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 */
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 
236 void snd_emu1010_fpga_write(struct snd_emu10k1 *emu, u32 reg, u32 value)
237 {
238 	unsigned long flags;
239 
240 	if (snd_BUG_ON(reg > 0x3f))
241 		return;
242 	reg += 0x40; /* 0x40 upwards are registers. */
243 	if (snd_BUG_ON(value > 0x3f)) /* 0 to 0x3f are values */
244 		return;
245 	spin_lock_irqsave(&emu->emu_lock, flags);
246 	outw(reg, emu->port + A_GPIO);
247 	udelay(10);
248 	outw(reg | 0x80, emu->port + A_GPIO);  /* High bit clocks the value into the fpga. */
249 	udelay(10);
250 	outw(value, emu->port + A_GPIO);
251 	udelay(10);
252 	outw(value | 0x80 , emu->port + A_GPIO);  /* High bit clocks the value into the fpga. */
253 	spin_unlock_irqrestore(&emu->emu_lock, flags);
254 }
255 
256 void snd_emu1010_fpga_read(struct snd_emu10k1 *emu, u32 reg, u32 *value)
257 {
258 	// The higest input pin is used as the designated interrupt trigger,
259 	// so it needs to be masked out.
260 	u32 mask = emu->card_capabilities->ca0108_chip ? 0x1f : 0x7f;
261 	unsigned long flags;
262 	if (snd_BUG_ON(reg > 0x3f))
263 		return;
264 	reg += 0x40; /* 0x40 upwards are registers. */
265 	spin_lock_irqsave(&emu->emu_lock, flags);
266 	outw(reg, emu->port + A_GPIO);
267 	udelay(10);
268 	outw(reg | 0x80, emu->port + A_GPIO);  /* High bit clocks the value into the fpga. */
269 	udelay(10);
270 	*value = ((inw(emu->port + A_GPIO) >> 8) & mask);
271 	spin_unlock_irqrestore(&emu->emu_lock, flags);
272 }
273 
274 /* Each Destination has one and only one Source,
275  * but one Source can feed any number of Destinations simultaneously.
276  */
277 void snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 *emu, u32 dst, u32 src)
278 {
279 	if (snd_BUG_ON(dst & ~0x71f))
280 		return;
281 	if (snd_BUG_ON(src & ~0x71f))
282 		return;
283 	snd_emu1010_fpga_write(emu, EMU_HANA_DESTHI, dst >> 8);
284 	snd_emu1010_fpga_write(emu, EMU_HANA_DESTLO, dst & 0x1f);
285 	snd_emu1010_fpga_write(emu, EMU_HANA_SRCHI, src >> 8);
286 	snd_emu1010_fpga_write(emu, EMU_HANA_SRCLO, src & 0x1f);
287 }
288 
289 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
290 {
291 	unsigned long flags;
292 	unsigned int enable;
293 
294 	spin_lock_irqsave(&emu->emu_lock, flags);
295 	enable = inl(emu->port + INTE) | intrenb;
296 	outl(enable, emu->port + INTE);
297 	spin_unlock_irqrestore(&emu->emu_lock, flags);
298 }
299 
300 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
301 {
302 	unsigned long flags;
303 	unsigned int enable;
304 
305 	spin_lock_irqsave(&emu->emu_lock, flags);
306 	enable = inl(emu->port + INTE) & ~intrenb;
307 	outl(enable, emu->port + INTE);
308 	spin_unlock_irqrestore(&emu->emu_lock, flags);
309 }
310 
311 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
312 {
313 	unsigned long flags;
314 	unsigned int val;
315 
316 	spin_lock_irqsave(&emu->emu_lock, flags);
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 
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 	if (voicenum >= 32) {
337 		outl(CLIEH << 16, emu->port + PTR);
338 		val = inl(emu->port + DATA);
339 		val &= ~(1 << (voicenum - 32));
340 	} else {
341 		outl(CLIEL << 16, emu->port + PTR);
342 		val = inl(emu->port + DATA);
343 		val &= ~(1 << voicenum);
344 	}
345 	outl(val, emu->port + DATA);
346 	spin_unlock_irqrestore(&emu->emu_lock, flags);
347 }
348 
349 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
350 {
351 	unsigned long flags;
352 
353 	spin_lock_irqsave(&emu->emu_lock, flags);
354 	if (voicenum >= 32) {
355 		outl(CLIPH << 16, emu->port + PTR);
356 		voicenum = 1 << (voicenum - 32);
357 	} else {
358 		outl(CLIPL << 16, emu->port + PTR);
359 		voicenum = 1 << voicenum;
360 	}
361 	outl(voicenum, emu->port + DATA);
362 	spin_unlock_irqrestore(&emu->emu_lock, flags);
363 }
364 
365 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
366 {
367 	unsigned long flags;
368 	unsigned int val;
369 
370 	spin_lock_irqsave(&emu->emu_lock, flags);
371 	if (voicenum >= 32) {
372 		outl(HLIEH << 16, emu->port + PTR);
373 		val = inl(emu->port + DATA);
374 		val |= 1 << (voicenum - 32);
375 	} else {
376 		outl(HLIEL << 16, emu->port + PTR);
377 		val = inl(emu->port + DATA);
378 		val |= 1 << voicenum;
379 	}
380 	outl(val, emu->port + DATA);
381 	spin_unlock_irqrestore(&emu->emu_lock, flags);
382 }
383 
384 void snd_emu10k1_voice_half_loop_intr_disable(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 	if (voicenum >= 32) {
391 		outl(HLIEH << 16, emu->port + PTR);
392 		val = inl(emu->port + DATA);
393 		val &= ~(1 << (voicenum - 32));
394 	} else {
395 		outl(HLIEL << 16, emu->port + PTR);
396 		val = inl(emu->port + DATA);
397 		val &= ~(1 << voicenum);
398 	}
399 	outl(val, emu->port + DATA);
400 	spin_unlock_irqrestore(&emu->emu_lock, flags);
401 }
402 
403 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
404 {
405 	unsigned long flags;
406 
407 	spin_lock_irqsave(&emu->emu_lock, flags);
408 	if (voicenum >= 32) {
409 		outl(HLIPH << 16, emu->port + PTR);
410 		voicenum = 1 << (voicenum - 32);
411 	} else {
412 		outl(HLIPL << 16, emu->port + PTR);
413 		voicenum = 1 << voicenum;
414 	}
415 	outl(voicenum, emu->port + DATA);
416 	spin_unlock_irqrestore(&emu->emu_lock, flags);
417 }
418 
419 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
420 {
421 	unsigned long flags;
422 	unsigned int sol;
423 
424 	spin_lock_irqsave(&emu->emu_lock, flags);
425 	if (voicenum >= 32) {
426 		outl(SOLEH << 16, emu->port + PTR);
427 		sol = inl(emu->port + DATA);
428 		sol |= 1 << (voicenum - 32);
429 	} else {
430 		outl(SOLEL << 16, emu->port + PTR);
431 		sol = inl(emu->port + DATA);
432 		sol |= 1 << voicenum;
433 	}
434 	outl(sol, emu->port + DATA);
435 	spin_unlock_irqrestore(&emu->emu_lock, flags);
436 }
437 
438 void snd_emu10k1_voice_clear_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 	if (voicenum >= 32) {
445 		outl(SOLEH << 16, emu->port + PTR);
446 		sol = inl(emu->port + DATA);
447 		sol &= ~(1 << (voicenum - 32));
448 	} else {
449 		outl(SOLEL << 16, emu->port + PTR);
450 		sol = inl(emu->port + DATA);
451 		sol &= ~(1 << voicenum);
452 	}
453 	outl(sol, emu->port + DATA);
454 	spin_unlock_irqrestore(&emu->emu_lock, flags);
455 }
456 
457 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
458 {
459 	volatile unsigned count;
460 	unsigned int newtime = 0, curtime;
461 
462 	curtime = inl(emu->port + WC) >> 6;
463 	while (wait-- > 0) {
464 		count = 0;
465 		while (count++ < 16384) {
466 			newtime = inl(emu->port + WC) >> 6;
467 			if (newtime != curtime)
468 				break;
469 		}
470 		if (count > 16384)
471 			break;
472 		curtime = newtime;
473 	}
474 }
475 
476 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
477 {
478 	struct snd_emu10k1 *emu = ac97->private_data;
479 	unsigned long flags;
480 	unsigned short val;
481 
482 	spin_lock_irqsave(&emu->emu_lock, flags);
483 	outb(reg, emu->port + AC97ADDRESS);
484 	val = inw(emu->port + AC97DATA);
485 	spin_unlock_irqrestore(&emu->emu_lock, flags);
486 	return val;
487 }
488 
489 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
490 {
491 	struct snd_emu10k1 *emu = ac97->private_data;
492 	unsigned long flags;
493 
494 	spin_lock_irqsave(&emu->emu_lock, flags);
495 	outb(reg, emu->port + AC97ADDRESS);
496 	outw(data, emu->port + AC97DATA);
497 	spin_unlock_irqrestore(&emu->emu_lock, flags);
498 }
499 
500 /*
501  *  convert rate to pitch
502  */
503 
504 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
505 {
506 	static const u32 logMagTable[128] = {
507 		0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
508 		0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
509 		0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
510 		0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
511 		0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
512 		0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
513 		0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
514 		0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
515 		0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
516 		0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
517 		0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
518 		0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
519 		0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
520 		0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
521 		0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
522 		0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
523 	};
524 	static const char logSlopeTable[128] = {
525 		0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
526 		0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
527 		0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
528 		0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
529 		0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
530 		0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
531 		0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
532 		0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
533 		0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
534 		0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
535 		0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
536 		0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
537 		0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
538 		0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
539 		0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
540 		0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
541 	};
542 	int i;
543 
544 	if (rate == 0)
545 		return 0;	/* Bail out if no leading "1" */
546 	rate *= 11185;		/* Scale 48000 to 0x20002380 */
547 	for (i = 31; i > 0; i--) {
548 		if (rate & 0x80000000) {	/* Detect leading "1" */
549 			return (((unsigned int) (i - 15) << 20) +
550 			       logMagTable[0x7f & (rate >> 24)] +
551 					(0x7f & (rate >> 17)) *
552 					logSlopeTable[0x7f & (rate >> 24)]);
553 		}
554 		rate <<= 1;
555 	}
556 
557 	return 0;		/* Should never reach this point */
558 }
559 
560