Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / sound / pci / emu10k1 / io.c
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
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
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
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
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
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 */
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
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
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  */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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