sound: Add export.h for THIS_MODULE/EXPORT_SYMBOL where needed
[linux-2.6.git] / 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 (!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
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
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
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 */
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
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
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  */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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