Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa
[linux-2.6] / 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 "p17v.h"
33
34 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
35 {
36         unsigned long flags;
37         unsigned int regptr, val;
38         unsigned int mask;
39
40         mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
41         regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
42
43         if (reg & 0xff000000) {
44                 unsigned char size, offset;
45                 
46                 size = (reg >> 24) & 0x3f;
47                 offset = (reg >> 16) & 0x1f;
48                 mask = ((1 << size) - 1) << offset;
49                 
50                 spin_lock_irqsave(&emu->emu_lock, flags);
51                 outl(regptr, emu->port + PTR);
52                 val = inl(emu->port + DATA);
53                 spin_unlock_irqrestore(&emu->emu_lock, flags);
54                 
55                 return (val & mask) >> offset;
56         } else {
57                 spin_lock_irqsave(&emu->emu_lock, flags);
58                 outl(regptr, emu->port + PTR);
59                 val = inl(emu->port + DATA);
60                 spin_unlock_irqrestore(&emu->emu_lock, flags);
61                 return val;
62         }
63 }
64
65 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
66
67 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
68 {
69         unsigned int regptr;
70         unsigned long flags;
71         unsigned int mask;
72
73         if (!emu) {
74                 snd_printk(KERN_ERR "ptr_write: emu is null!\n");
75                 dump_stack();
76                 return;
77         }
78         mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
79         regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
80
81         if (reg & 0xff000000) {
82                 unsigned char size, offset;
83
84                 size = (reg >> 24) & 0x3f;
85                 offset = (reg >> 16) & 0x1f;
86                 mask = ((1 << size) - 1) << offset;
87                 data = (data << offset) & mask;
88
89                 spin_lock_irqsave(&emu->emu_lock, flags);
90                 outl(regptr, emu->port + PTR);
91                 data |= inl(emu->port + DATA) & ~mask;
92                 outl(data, emu->port + DATA);
93                 spin_unlock_irqrestore(&emu->emu_lock, flags);          
94         } else {
95                 spin_lock_irqsave(&emu->emu_lock, flags);
96                 outl(regptr, emu->port + PTR);
97                 outl(data, emu->port + DATA);
98                 spin_unlock_irqrestore(&emu->emu_lock, flags);
99         }
100 }
101
102 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
103
104 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, 
105                                           unsigned int reg, 
106                                           unsigned int chn)
107 {
108         unsigned long flags;
109         unsigned int regptr, val;
110   
111         regptr = (reg << 16) | chn;
112
113         spin_lock_irqsave(&emu->emu_lock, flags);
114         outl(regptr, emu->port + 0x20 + PTR);
115         val = inl(emu->port + 0x20 + DATA);
116         spin_unlock_irqrestore(&emu->emu_lock, flags);
117         return val;
118 }
119
120 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, 
121                                    unsigned int reg, 
122                                    unsigned int chn, 
123                                    unsigned int data)
124 {
125         unsigned int regptr;
126         unsigned long flags;
127
128         regptr = (reg << 16) | chn;
129
130         spin_lock_irqsave(&emu->emu_lock, flags);
131         outl(regptr, emu->port + 0x20 + PTR);
132         outl(data, emu->port + 0x20 + DATA);
133         spin_unlock_irqrestore(&emu->emu_lock, flags);
134 }
135
136 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
137                                    unsigned int data)
138 {
139         unsigned int reset, set;
140         unsigned int reg, tmp;
141         int n, result;
142         int err = 0;
143
144         /* This function is not re-entrant, so protect against it. */
145         spin_lock(&emu->spi_lock);
146         if (emu->card_capabilities->ca0108_chip)
147                 reg = 0x3c; /* PTR20, reg 0x3c */
148         else {
149                 /* For other chip types the SPI register
150                  * is currently unknown. */
151                 err = 1;
152                 goto spi_write_exit;
153         }
154         if (data > 0xffff) {
155                 /* Only 16bit values allowed */
156                 err = 1;
157                 goto spi_write_exit;
158         }
159
160         tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
161         reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
162         set = reset | 0x10000; /* Set xxx1xxxx */
163         snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
164         tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
165         snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
166         result = 1;
167         /* Wait for status bit to return to 0 */
168         for (n = 0; n < 100; n++) {
169                 udelay(10);
170                 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
171                 if (!(tmp & 0x10000)) {
172                         result = 0;
173                         break;
174                 }
175         }
176         if (result) {
177                 /* Timed out */
178                 err = 1;
179                 goto spi_write_exit;
180         }
181         snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
182         tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
183         err = 0;
184 spi_write_exit:
185         spin_unlock(&emu->spi_lock);
186         return err;
187 }
188
189 /* The ADC does not support i2c read, so only write is implemented */
190 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
191                                 u32 reg,
192                                 u32 value)
193 {
194         u32 tmp;
195         int timeout = 0;
196         int status;
197         int retry;
198         int err = 0;
199
200         if ((reg > 0x7f) || (value > 0x1ff)) {
201                 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
202                 return -EINVAL;
203         }
204
205         /* This function is not re-entrant, so protect against it. */
206         spin_lock(&emu->i2c_lock);
207
208         tmp = reg << 25 | value << 16;
209
210         /* This controls the I2C connected to the WM8775 ADC Codec */
211         snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
212         tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
213
214         for (retry = 0; retry < 10; retry++) {
215                 /* Send the data to i2c */
216                 tmp = 0;
217                 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
218                 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
219
220                 /* Wait till the transaction ends */
221                 while (1) {
222                         mdelay(1);
223                         status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
224                         timeout++;
225                         if ((status & I2C_A_ADC_START) == 0)
226                                 break;
227
228                         if (timeout > 1000) {
229                                 snd_printk("emu10k1:I2C:timeout status=0x%x\n", 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                 snd_printk(KERN_ERR "Writing to ADC failed!\n");
240                 snd_printk(KERN_ERR "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 < 0 || 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