Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0004  *                   Creative Labs, Inc.
0005  *  Routines for control of EMU10K1 chips
0006  *
0007  *  BUGS:
0008  *    --
0009  *
0010  *  TODO:
0011  *    --
0012  */
0013 
0014 #include <linux/time.h>
0015 #include <sound/core.h>
0016 #include <sound/emu10k1.h>
0017 #include <linux/delay.h>
0018 #include <linux/export.h>
0019 #include "p17v.h"
0020 
0021 unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
0022 {
0023     unsigned long flags;
0024     unsigned int regptr, val;
0025     unsigned int mask;
0026 
0027     mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
0028     regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
0029 
0030     if (reg & 0xff000000) {
0031         unsigned char size, offset;
0032         
0033         size = (reg >> 24) & 0x3f;
0034         offset = (reg >> 16) & 0x1f;
0035         mask = ((1 << size) - 1) << offset;
0036         
0037         spin_lock_irqsave(&emu->emu_lock, flags);
0038         outl(regptr, emu->port + PTR);
0039         val = inl(emu->port + DATA);
0040         spin_unlock_irqrestore(&emu->emu_lock, flags);
0041         
0042         return (val & mask) >> offset;
0043     } else {
0044         spin_lock_irqsave(&emu->emu_lock, flags);
0045         outl(regptr, emu->port + PTR);
0046         val = inl(emu->port + DATA);
0047         spin_unlock_irqrestore(&emu->emu_lock, flags);
0048         return val;
0049     }
0050 }
0051 
0052 EXPORT_SYMBOL(snd_emu10k1_ptr_read);
0053 
0054 void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
0055 {
0056     unsigned int regptr;
0057     unsigned long flags;
0058     unsigned int mask;
0059 
0060     if (snd_BUG_ON(!emu))
0061         return;
0062     mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
0063     regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
0064 
0065     if (reg & 0xff000000) {
0066         unsigned char size, offset;
0067 
0068         size = (reg >> 24) & 0x3f;
0069         offset = (reg >> 16) & 0x1f;
0070         mask = ((1 << size) - 1) << offset;
0071         data = (data << offset) & mask;
0072 
0073         spin_lock_irqsave(&emu->emu_lock, flags);
0074         outl(regptr, emu->port + PTR);
0075         data |= inl(emu->port + DATA) & ~mask;
0076         outl(data, emu->port + DATA);
0077         spin_unlock_irqrestore(&emu->emu_lock, flags);      
0078     } else {
0079         spin_lock_irqsave(&emu->emu_lock, flags);
0080         outl(regptr, emu->port + PTR);
0081         outl(data, emu->port + DATA);
0082         spin_unlock_irqrestore(&emu->emu_lock, flags);
0083     }
0084 }
0085 
0086 EXPORT_SYMBOL(snd_emu10k1_ptr_write);
0087 
0088 unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, 
0089                       unsigned int reg, 
0090                       unsigned int chn)
0091 {
0092     unsigned long flags;
0093     unsigned int regptr, val;
0094   
0095     regptr = (reg << 16) | chn;
0096 
0097     spin_lock_irqsave(&emu->emu_lock, flags);
0098     outl(regptr, emu->port + 0x20 + PTR);
0099     val = inl(emu->port + 0x20 + DATA);
0100     spin_unlock_irqrestore(&emu->emu_lock, flags);
0101     return val;
0102 }
0103 
0104 void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, 
0105                    unsigned int reg, 
0106                    unsigned int chn, 
0107                    unsigned int data)
0108 {
0109     unsigned int regptr;
0110     unsigned long flags;
0111 
0112     regptr = (reg << 16) | chn;
0113 
0114     spin_lock_irqsave(&emu->emu_lock, flags);
0115     outl(regptr, emu->port + 0x20 + PTR);
0116     outl(data, emu->port + 0x20 + DATA);
0117     spin_unlock_irqrestore(&emu->emu_lock, flags);
0118 }
0119 
0120 int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
0121                    unsigned int data)
0122 {
0123     unsigned int reset, set;
0124     unsigned int reg, tmp;
0125     int n, result;
0126     int err = 0;
0127 
0128     /* This function is not re-entrant, so protect against it. */
0129     spin_lock(&emu->spi_lock);
0130     if (emu->card_capabilities->ca0108_chip)
0131         reg = 0x3c; /* PTR20, reg 0x3c */
0132     else {
0133         /* For other chip types the SPI register
0134          * is currently unknown. */
0135         err = 1;
0136         goto spi_write_exit;
0137     }
0138     if (data > 0xffff) {
0139         /* Only 16bit values allowed */
0140         err = 1;
0141         goto spi_write_exit;
0142     }
0143 
0144     tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
0145     reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
0146     set = reset | 0x10000; /* Set xxx1xxxx */
0147     snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
0148     tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
0149     snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
0150     result = 1;
0151     /* Wait for status bit to return to 0 */
0152     for (n = 0; n < 100; n++) {
0153         udelay(10);
0154         tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
0155         if (!(tmp & 0x10000)) {
0156             result = 0;
0157             break;
0158         }
0159     }
0160     if (result) {
0161         /* Timed out */
0162         err = 1;
0163         goto spi_write_exit;
0164     }
0165     snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
0166     tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
0167     err = 0;
0168 spi_write_exit:
0169     spin_unlock(&emu->spi_lock);
0170     return err;
0171 }
0172 
0173 /* The ADC does not support i2c read, so only write is implemented */
0174 int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
0175                 u32 reg,
0176                 u32 value)
0177 {
0178     u32 tmp;
0179     int timeout = 0;
0180     int status;
0181     int retry;
0182     int err = 0;
0183 
0184     if ((reg > 0x7f) || (value > 0x1ff)) {
0185         dev_err(emu->card->dev, "i2c_write: invalid values.\n");
0186         return -EINVAL;
0187     }
0188 
0189     /* This function is not re-entrant, so protect against it. */
0190     spin_lock(&emu->i2c_lock);
0191 
0192     tmp = reg << 25 | value << 16;
0193 
0194     /* This controls the I2C connected to the WM8775 ADC Codec */
0195     snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
0196     tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
0197 
0198     for (retry = 0; retry < 10; retry++) {
0199         /* Send the data to i2c */
0200         tmp = 0;
0201         tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
0202         snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
0203 
0204         /* Wait till the transaction ends */
0205         while (1) {
0206             mdelay(1);
0207             status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
0208             timeout++;
0209             if ((status & I2C_A_ADC_START) == 0)
0210                 break;
0211 
0212             if (timeout > 1000) {
0213                 dev_warn(emu->card->dev,
0214                        "emu10k1:I2C:timeout status=0x%x\n",
0215                        status);
0216                 break;
0217             }
0218         }
0219         //Read back and see if the transaction is successful
0220         if ((status & I2C_A_ADC_ABORT) == 0)
0221             break;
0222     }
0223 
0224     if (retry == 10) {
0225         dev_err(emu->card->dev, "Writing to ADC failed!\n");
0226         dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n",
0227             status, reg, value);
0228         /* dump_stack(); */
0229         err = -EINVAL;
0230     }
0231     
0232     spin_unlock(&emu->i2c_lock);
0233     return err;
0234 }
0235 
0236 int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
0237 {
0238     unsigned long flags;
0239 
0240     if (reg > 0x3f)
0241         return 1;
0242     reg += 0x40; /* 0x40 upwards are registers. */
0243     if (value > 0x3f) /* 0 to 0x3f are values */
0244         return 1;
0245     spin_lock_irqsave(&emu->emu_lock, flags);
0246     outl(reg, emu->port + A_IOCFG);
0247     udelay(10);
0248     outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
0249     udelay(10);
0250     outl(value, emu->port + A_IOCFG);
0251     udelay(10);
0252     outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
0253     spin_unlock_irqrestore(&emu->emu_lock, flags);
0254 
0255     return 0;
0256 }
0257 
0258 int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
0259 {
0260     unsigned long flags;
0261     if (reg > 0x3f)
0262         return 1;
0263     reg += 0x40; /* 0x40 upwards are registers. */
0264     spin_lock_irqsave(&emu->emu_lock, flags);
0265     outl(reg, emu->port + A_IOCFG);
0266     udelay(10);
0267     outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
0268     udelay(10);
0269     *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
0270     spin_unlock_irqrestore(&emu->emu_lock, flags);
0271 
0272     return 0;
0273 }
0274 
0275 /* Each Destination has one and only one Source,
0276  * but one Source can feed any number of Destinations simultaneously.
0277  */
0278 int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
0279 {
0280     snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
0281     snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
0282     snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
0283     snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
0284 
0285     return 0;
0286 }
0287 
0288 void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
0289 {
0290     unsigned long flags;
0291     unsigned int enable;
0292 
0293     spin_lock_irqsave(&emu->emu_lock, flags);
0294     enable = inl(emu->port + INTE) | intrenb;
0295     outl(enable, emu->port + INTE);
0296     spin_unlock_irqrestore(&emu->emu_lock, flags);
0297 }
0298 
0299 void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
0300 {
0301     unsigned long flags;
0302     unsigned int enable;
0303 
0304     spin_lock_irqsave(&emu->emu_lock, flags);
0305     enable = inl(emu->port + INTE) & ~intrenb;
0306     outl(enable, emu->port + INTE);
0307     spin_unlock_irqrestore(&emu->emu_lock, flags);
0308 }
0309 
0310 void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
0311 {
0312     unsigned long flags;
0313     unsigned int val;
0314 
0315     spin_lock_irqsave(&emu->emu_lock, flags);
0316     /* voice interrupt */
0317     if (voicenum >= 32) {
0318         outl(CLIEH << 16, emu->port + PTR);
0319         val = inl(emu->port + DATA);
0320         val |= 1 << (voicenum - 32);
0321     } else {
0322         outl(CLIEL << 16, emu->port + PTR);
0323         val = inl(emu->port + DATA);
0324         val |= 1 << voicenum;
0325     }
0326     outl(val, emu->port + DATA);
0327     spin_unlock_irqrestore(&emu->emu_lock, flags);
0328 }
0329 
0330 void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
0331 {
0332     unsigned long flags;
0333     unsigned int val;
0334 
0335     spin_lock_irqsave(&emu->emu_lock, flags);
0336     /* voice interrupt */
0337     if (voicenum >= 32) {
0338         outl(CLIEH << 16, emu->port + PTR);
0339         val = inl(emu->port + DATA);
0340         val &= ~(1 << (voicenum - 32));
0341     } else {
0342         outl(CLIEL << 16, emu->port + PTR);
0343         val = inl(emu->port + DATA);
0344         val &= ~(1 << voicenum);
0345     }
0346     outl(val, emu->port + DATA);
0347     spin_unlock_irqrestore(&emu->emu_lock, flags);
0348 }
0349 
0350 void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
0351 {
0352     unsigned long flags;
0353 
0354     spin_lock_irqsave(&emu->emu_lock, flags);
0355     /* voice interrupt */
0356     if (voicenum >= 32) {
0357         outl(CLIPH << 16, emu->port + PTR);
0358         voicenum = 1 << (voicenum - 32);
0359     } else {
0360         outl(CLIPL << 16, emu->port + PTR);
0361         voicenum = 1 << voicenum;
0362     }
0363     outl(voicenum, emu->port + DATA);
0364     spin_unlock_irqrestore(&emu->emu_lock, flags);
0365 }
0366 
0367 void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
0368 {
0369     unsigned long flags;
0370     unsigned int val;
0371 
0372     spin_lock_irqsave(&emu->emu_lock, flags);
0373     /* voice interrupt */
0374     if (voicenum >= 32) {
0375         outl(HLIEH << 16, emu->port + PTR);
0376         val = inl(emu->port + DATA);
0377         val |= 1 << (voicenum - 32);
0378     } else {
0379         outl(HLIEL << 16, emu->port + PTR);
0380         val = inl(emu->port + DATA);
0381         val |= 1 << voicenum;
0382     }
0383     outl(val, emu->port + DATA);
0384     spin_unlock_irqrestore(&emu->emu_lock, flags);
0385 }
0386 
0387 void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
0388 {
0389     unsigned long flags;
0390     unsigned int val;
0391 
0392     spin_lock_irqsave(&emu->emu_lock, flags);
0393     /* voice interrupt */
0394     if (voicenum >= 32) {
0395         outl(HLIEH << 16, emu->port + PTR);
0396         val = inl(emu->port + DATA);
0397         val &= ~(1 << (voicenum - 32));
0398     } else {
0399         outl(HLIEL << 16, emu->port + PTR);
0400         val = inl(emu->port + DATA);
0401         val &= ~(1 << voicenum);
0402     }
0403     outl(val, emu->port + DATA);
0404     spin_unlock_irqrestore(&emu->emu_lock, flags);
0405 }
0406 
0407 void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
0408 {
0409     unsigned long flags;
0410 
0411     spin_lock_irqsave(&emu->emu_lock, flags);
0412     /* voice interrupt */
0413     if (voicenum >= 32) {
0414         outl(HLIPH << 16, emu->port + PTR);
0415         voicenum = 1 << (voicenum - 32);
0416     } else {
0417         outl(HLIPL << 16, emu->port + PTR);
0418         voicenum = 1 << voicenum;
0419     }
0420     outl(voicenum, emu->port + DATA);
0421     spin_unlock_irqrestore(&emu->emu_lock, flags);
0422 }
0423 
0424 void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
0425 {
0426     unsigned long flags;
0427     unsigned int sol;
0428 
0429     spin_lock_irqsave(&emu->emu_lock, flags);
0430     /* voice interrupt */
0431     if (voicenum >= 32) {
0432         outl(SOLEH << 16, emu->port + PTR);
0433         sol = inl(emu->port + DATA);
0434         sol |= 1 << (voicenum - 32);
0435     } else {
0436         outl(SOLEL << 16, emu->port + PTR);
0437         sol = inl(emu->port + DATA);
0438         sol |= 1 << voicenum;
0439     }
0440     outl(sol, emu->port + DATA);
0441     spin_unlock_irqrestore(&emu->emu_lock, flags);
0442 }
0443 
0444 void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
0445 {
0446     unsigned long flags;
0447     unsigned int sol;
0448 
0449     spin_lock_irqsave(&emu->emu_lock, flags);
0450     /* voice interrupt */
0451     if (voicenum >= 32) {
0452         outl(SOLEH << 16, emu->port + PTR);
0453         sol = inl(emu->port + DATA);
0454         sol &= ~(1 << (voicenum - 32));
0455     } else {
0456         outl(SOLEL << 16, emu->port + PTR);
0457         sol = inl(emu->port + DATA);
0458         sol &= ~(1 << voicenum);
0459     }
0460     outl(sol, emu->port + DATA);
0461     spin_unlock_irqrestore(&emu->emu_lock, flags);
0462 }
0463 
0464 void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
0465 {
0466     volatile unsigned count;
0467     unsigned int newtime = 0, curtime;
0468 
0469     curtime = inl(emu->port + WC) >> 6;
0470     while (wait-- > 0) {
0471         count = 0;
0472         while (count++ < 16384) {
0473             newtime = inl(emu->port + WC) >> 6;
0474             if (newtime != curtime)
0475                 break;
0476         }
0477         if (count > 16384)
0478             break;
0479         curtime = newtime;
0480     }
0481 }
0482 
0483 unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
0484 {
0485     struct snd_emu10k1 *emu = ac97->private_data;
0486     unsigned long flags;
0487     unsigned short val;
0488 
0489     spin_lock_irqsave(&emu->emu_lock, flags);
0490     outb(reg, emu->port + AC97ADDRESS);
0491     val = inw(emu->port + AC97DATA);
0492     spin_unlock_irqrestore(&emu->emu_lock, flags);
0493     return val;
0494 }
0495 
0496 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
0497 {
0498     struct snd_emu10k1 *emu = ac97->private_data;
0499     unsigned long flags;
0500 
0501     spin_lock_irqsave(&emu->emu_lock, flags);
0502     outb(reg, emu->port + AC97ADDRESS);
0503     outw(data, emu->port + AC97DATA);
0504     spin_unlock_irqrestore(&emu->emu_lock, flags);
0505 }
0506 
0507 /*
0508  *  convert rate to pitch
0509  */
0510 
0511 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
0512 {
0513     static const u32 logMagTable[128] = {
0514         0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
0515         0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
0516         0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
0517         0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
0518         0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
0519         0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
0520         0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
0521         0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
0522         0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
0523         0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
0524         0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
0525         0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
0526         0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
0527         0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
0528         0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
0529         0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
0530     };
0531     static const char logSlopeTable[128] = {
0532         0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
0533         0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
0534         0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
0535         0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
0536         0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
0537         0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
0538         0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
0539         0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
0540         0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
0541         0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
0542         0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
0543         0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
0544         0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
0545         0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
0546         0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
0547         0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
0548     };
0549     int i;
0550 
0551     if (rate == 0)
0552         return 0;   /* Bail out if no leading "1" */
0553     rate *= 11185;      /* Scale 48000 to 0x20002380 */
0554     for (i = 31; i > 0; i--) {
0555         if (rate & 0x80000000) {    /* Detect leading "1" */
0556             return (((unsigned int) (i - 15) << 20) +
0557                    logMagTable[0x7f & (rate >> 24)] +
0558                     (0x7f & (rate >> 17)) *
0559                     logSlopeTable[0x7f & (rate >> 24)]);
0560         }
0561         rate <<= 1;
0562     }
0563 
0564     return 0;       /* Should never reach this point */
0565 }
0566