]> git.karo-electronics.de Git - mv-sheeva.git/blob - sound/pci/emu10k1/io.c
Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mv-sheeva.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 "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(KERN_WARNING
230                                            "emu10k1:I2C:timeout status=0x%x\n",
231                                            status);
232                                 break;
233                         }
234                 }
235                 //Read back and see if the transaction is successful
236                 if ((status & I2C_A_ADC_ABORT) == 0)
237                         break;
238         }
239
240         if (retry == 10) {
241                 snd_printk(KERN_ERR "Writing to ADC failed!\n");
242                 snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
243                         status, reg, value);
244                 /* dump_stack(); */
245                 err = -EINVAL;
246         }
247     
248         spin_unlock(&emu->i2c_lock);
249         return err;
250 }
251
252 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
253 {
254         unsigned long flags;
255
256         if (reg > 0x3f)
257                 return 1;
258         reg += 0x40; /* 0x40 upwards are registers. */
259         if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */
260                 return 1;
261         spin_lock_irqsave(&emu->emu_lock, flags);
262         outl(reg, emu->port + A_IOCFG);
263         udelay(10);
264         outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
265         udelay(10);
266         outl(value, emu->port + A_IOCFG);
267         udelay(10);
268         outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
269         spin_unlock_irqrestore(&emu->emu_lock, flags);
270
271         return 0;
272 }
273
274 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
275 {
276         unsigned long flags;
277         if (reg > 0x3f)
278                 return 1;
279         reg += 0x40; /* 0x40 upwards are registers. */
280         spin_lock_irqsave(&emu->emu_lock, flags);
281         outl(reg, emu->port + A_IOCFG);
282         udelay(10);
283         outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
284         udelay(10);
285         *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
286         spin_unlock_irqrestore(&emu->emu_lock, flags);
287
288         return 0;
289 }
290
291 /* Each Destination has one and only one Source,
292  * but one Source can feed any number of Destinations simultaneously.
293  */
294 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
295 {
296         snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
297         snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
298         snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
299         snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
300
301         return 0;
302 }
303
304 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
305 {
306         unsigned long flags;
307         unsigned int enable;
308
309         spin_lock_irqsave(&emu->emu_lock, flags);
310         enable = inl(emu->port + INTE) | intrenb;
311         outl(enable, emu->port + INTE);
312         spin_unlock_irqrestore(&emu->emu_lock, flags);
313 }
314
315 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
316 {
317         unsigned long flags;
318         unsigned int enable;
319
320         spin_lock_irqsave(&emu->emu_lock, flags);
321         enable = inl(emu->port + INTE) & ~intrenb;
322         outl(enable, emu->port + INTE);
323         spin_unlock_irqrestore(&emu->emu_lock, flags);
324 }
325
326 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
327 {
328         unsigned long flags;
329         unsigned int val;
330
331         spin_lock_irqsave(&emu->emu_lock, flags);
332         /* voice interrupt */
333         if (voicenum >= 32) {
334                 outl(CLIEH << 16, emu->port + PTR);
335                 val = inl(emu->port + DATA);
336                 val |= 1 << (voicenum - 32);
337         } else {
338                 outl(CLIEL << 16, emu->port + PTR);
339                 val = inl(emu->port + DATA);
340                 val |= 1 << voicenum;
341         }
342         outl(val, emu->port + DATA);
343         spin_unlock_irqrestore(&emu->emu_lock, flags);
344 }
345
346 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
347 {
348         unsigned long flags;
349         unsigned int val;
350
351         spin_lock_irqsave(&emu->emu_lock, flags);
352         /* voice interrupt */
353         if (voicenum >= 32) {
354                 outl(CLIEH << 16, emu->port + PTR);
355                 val = inl(emu->port + DATA);
356                 val &= ~(1 << (voicenum - 32));
357         } else {
358                 outl(CLIEL << 16, emu->port + PTR);
359                 val = inl(emu->port + DATA);
360                 val &= ~(1 << voicenum);
361         }
362         outl(val, emu->port + DATA);
363         spin_unlock_irqrestore(&emu->emu_lock, flags);
364 }
365
366 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
367 {
368         unsigned long flags;
369
370         spin_lock_irqsave(&emu->emu_lock, flags);
371         /* voice interrupt */
372         if (voicenum >= 32) {
373                 outl(CLIPH << 16, emu->port + PTR);
374                 voicenum = 1 << (voicenum - 32);
375         } else {
376                 outl(CLIPL << 16, emu->port + PTR);
377                 voicenum = 1 << voicenum;
378         }
379         outl(voicenum, emu->port + DATA);
380         spin_unlock_irqrestore(&emu->emu_lock, flags);
381 }
382
383 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
384 {
385         unsigned long flags;
386         unsigned int val;
387
388         spin_lock_irqsave(&emu->emu_lock, flags);
389         /* voice interrupt */
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_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
404 {
405         unsigned long flags;
406         unsigned int val;
407
408         spin_lock_irqsave(&emu->emu_lock, flags);
409         /* voice interrupt */
410         if (voicenum >= 32) {
411                 outl(HLIEH << 16, emu->port + PTR);
412                 val = inl(emu->port + DATA);
413                 val &= ~(1 << (voicenum - 32));
414         } else {
415                 outl(HLIEL << 16, emu->port + PTR);
416                 val = inl(emu->port + DATA);
417                 val &= ~(1 << voicenum);
418         }
419         outl(val, emu->port + DATA);
420         spin_unlock_irqrestore(&emu->emu_lock, flags);
421 }
422
423 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
424 {
425         unsigned long flags;
426
427         spin_lock_irqsave(&emu->emu_lock, flags);
428         /* voice interrupt */
429         if (voicenum >= 32) {
430                 outl(HLIPH << 16, emu->port + PTR);
431                 voicenum = 1 << (voicenum - 32);
432         } else {
433                 outl(HLIPL << 16, emu->port + PTR);
434                 voicenum = 1 << voicenum;
435         }
436         outl(voicenum, emu->port + DATA);
437         spin_unlock_irqrestore(&emu->emu_lock, flags);
438 }
439
440 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
441 {
442         unsigned long flags;
443         unsigned int sol;
444
445         spin_lock_irqsave(&emu->emu_lock, flags);
446         /* voice interrupt */
447         if (voicenum >= 32) {
448                 outl(SOLEH << 16, emu->port + PTR);
449                 sol = inl(emu->port + DATA);
450                 sol |= 1 << (voicenum - 32);
451         } else {
452                 outl(SOLEL << 16, emu->port + PTR);
453                 sol = inl(emu->port + DATA);
454                 sol |= 1 << voicenum;
455         }
456         outl(sol, emu->port + DATA);
457         spin_unlock_irqrestore(&emu->emu_lock, flags);
458 }
459
460 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
461 {
462         unsigned long flags;
463         unsigned int sol;
464
465         spin_lock_irqsave(&emu->emu_lock, flags);
466         /* voice interrupt */
467         if (voicenum >= 32) {
468                 outl(SOLEH << 16, emu->port + PTR);
469                 sol = inl(emu->port + DATA);
470                 sol &= ~(1 << (voicenum - 32));
471         } else {
472                 outl(SOLEL << 16, emu->port + PTR);
473                 sol = inl(emu->port + DATA);
474                 sol &= ~(1 << voicenum);
475         }
476         outl(sol, emu->port + DATA);
477         spin_unlock_irqrestore(&emu->emu_lock, flags);
478 }
479
480 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
481 {
482         volatile unsigned count;
483         unsigned int newtime = 0, curtime;
484
485         curtime = inl(emu->port + WC) >> 6;
486         while (wait-- > 0) {
487                 count = 0;
488                 while (count++ < 16384) {
489                         newtime = inl(emu->port + WC) >> 6;
490                         if (newtime != curtime)
491                                 break;
492                 }
493                 if (count > 16384)
494                         break;
495                 curtime = newtime;
496         }
497 }
498
499 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
500 {
501         struct snd_emu10k1 *emu = ac97->private_data;
502         unsigned long flags;
503         unsigned short val;
504
505         spin_lock_irqsave(&emu->emu_lock, flags);
506         outb(reg, emu->port + AC97ADDRESS);
507         val = inw(emu->port + AC97DATA);
508         spin_unlock_irqrestore(&emu->emu_lock, flags);
509         return val;
510 }
511
512 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
513 {
514         struct snd_emu10k1 *emu = ac97->private_data;
515         unsigned long flags;
516
517         spin_lock_irqsave(&emu->emu_lock, flags);
518         outb(reg, emu->port + AC97ADDRESS);
519         outw(data, emu->port + AC97DATA);
520         spin_unlock_irqrestore(&emu->emu_lock, flags);
521 }
522
523 /*
524  *  convert rate to pitch
525  */
526
527 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
528 {
529         static u32 logMagTable[128] = {
530                 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
531                 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
532                 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
533                 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
534                 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
535                 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
536                 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
537                 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
538                 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
539                 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
540                 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
541                 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
542                 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
543                 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
544                 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
545                 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
546         };
547         static char logSlopeTable[128] = {
548                 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
549                 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
550                 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
551                 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
552                 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
553                 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
554                 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
555                 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
556                 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
557                 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
558                 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
559                 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
560                 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
561                 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
562                 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
563                 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
564         };
565         int i;
566
567         if (rate == 0)
568                 return 0;       /* Bail out if no leading "1" */
569         rate *= 11185;          /* Scale 48000 to 0x20002380 */
570         for (i = 31; i > 0; i--) {
571                 if (rate & 0x80000000) {        /* Detect leading "1" */
572                         return (((unsigned int) (i - 15) << 20) +
573                                logMagTable[0x7f & (rate >> 24)] +
574                                         (0x7f & (rate >> 17)) *
575                                         logSlopeTable[0x7f & (rate >> 24)]);
576                 }
577                 rate <<= 1;
578         }
579
580         return 0;               /* Should never reach this point */
581 }
582