linux/sound/pci/emu10k1/io.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   4 *                   Creative Labs, Inc.
   5 *  Routines for control of EMU10K1 chips
   6 *
   7 *  BUGS:
   8 *    --
   9 *
  10 *  TODO:
  11 *    --
  12 */
  13
  14#include <linux/time.h>
  15#include <sound/core.h>
  16#include <sound/emu10k1.h>
  17#include <linux/delay.h>
  18#include <linux/export.h>
  19#include "p17v.h"
  20
  21unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn)
  22{
  23        unsigned long flags;
  24        unsigned int regptr, val;
  25        unsigned int mask;
  26
  27        mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
  28        regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
  29
  30        if (reg & 0xff000000) {
  31                unsigned char size, offset;
  32                
  33                size = (reg >> 24) & 0x3f;
  34                offset = (reg >> 16) & 0x1f;
  35                mask = ((1 << size) - 1) << offset;
  36                
  37                spin_lock_irqsave(&emu->emu_lock, flags);
  38                outl(regptr, emu->port + PTR);
  39                val = inl(emu->port + DATA);
  40                spin_unlock_irqrestore(&emu->emu_lock, flags);
  41                
  42                return (val & mask) >> offset;
  43        } else {
  44                spin_lock_irqsave(&emu->emu_lock, flags);
  45                outl(regptr, emu->port + PTR);
  46                val = inl(emu->port + DATA);
  47                spin_unlock_irqrestore(&emu->emu_lock, flags);
  48                return val;
  49        }
  50}
  51
  52EXPORT_SYMBOL(snd_emu10k1_ptr_read);
  53
  54void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned int chn, unsigned int data)
  55{
  56        unsigned int regptr;
  57        unsigned long flags;
  58        unsigned int mask;
  59
  60        if (snd_BUG_ON(!emu))
  61                return;
  62        mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
  63        regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
  64
  65        if (reg & 0xff000000) {
  66                unsigned char size, offset;
  67
  68                size = (reg >> 24) & 0x3f;
  69                offset = (reg >> 16) & 0x1f;
  70                mask = ((1 << size) - 1) << offset;
  71                data = (data << offset) & mask;
  72
  73                spin_lock_irqsave(&emu->emu_lock, flags);
  74                outl(regptr, emu->port + PTR);
  75                data |= inl(emu->port + DATA) & ~mask;
  76                outl(data, emu->port + DATA);
  77                spin_unlock_irqrestore(&emu->emu_lock, flags);          
  78        } else {
  79                spin_lock_irqsave(&emu->emu_lock, flags);
  80                outl(regptr, emu->port + PTR);
  81                outl(data, emu->port + DATA);
  82                spin_unlock_irqrestore(&emu->emu_lock, flags);
  83        }
  84}
  85
  86EXPORT_SYMBOL(snd_emu10k1_ptr_write);
  87
  88unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, 
  89                                          unsigned int reg, 
  90                                          unsigned int chn)
  91{
  92        unsigned long flags;
  93        unsigned int regptr, val;
  94  
  95        regptr = (reg << 16) | chn;
  96
  97        spin_lock_irqsave(&emu->emu_lock, flags);
  98        outl(regptr, emu->port + 0x20 + PTR);
  99        val = inl(emu->port + 0x20 + DATA);
 100        spin_unlock_irqrestore(&emu->emu_lock, flags);
 101        return val;
 102}
 103
 104void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, 
 105                                   unsigned int reg, 
 106                                   unsigned int chn, 
 107                                   unsigned int data)
 108{
 109        unsigned int regptr;
 110        unsigned long flags;
 111
 112        regptr = (reg << 16) | chn;
 113
 114        spin_lock_irqsave(&emu->emu_lock, flags);
 115        outl(regptr, emu->port + 0x20 + PTR);
 116        outl(data, emu->port + 0x20 + DATA);
 117        spin_unlock_irqrestore(&emu->emu_lock, flags);
 118}
 119
 120int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
 121                                   unsigned int data)
 122{
 123        unsigned int reset, set;
 124        unsigned int reg, tmp;
 125        int n, result;
 126        int err = 0;
 127
 128        /* This function is not re-entrant, so protect against it. */
 129        spin_lock(&emu->spi_lock);
 130        if (emu->card_capabilities->ca0108_chip)
 131                reg = 0x3c; /* PTR20, reg 0x3c */
 132        else {
 133                /* For other chip types the SPI register
 134                 * is currently unknown. */
 135                err = 1;
 136                goto spi_write_exit;
 137        }
 138        if (data > 0xffff) {
 139                /* Only 16bit values allowed */
 140                err = 1;
 141                goto spi_write_exit;
 142        }
 143
 144        tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
 145        reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
 146        set = reset | 0x10000; /* Set xxx1xxxx */
 147        snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
 148        tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
 149        snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
 150        result = 1;
 151        /* Wait for status bit to return to 0 */
 152        for (n = 0; n < 100; n++) {
 153                udelay(10);
 154                tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
 155                if (!(tmp & 0x10000)) {
 156                        result = 0;
 157                        break;
 158                }
 159        }
 160        if (result) {
 161                /* Timed out */
 162                err = 1;
 163                goto spi_write_exit;
 164        }
 165        snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
 166        tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
 167        err = 0;
 168spi_write_exit:
 169        spin_unlock(&emu->spi_lock);
 170        return err;
 171}
 172
 173/* The ADC does not support i2c read, so only write is implemented */
 174int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
 175                                u32 reg,
 176                                u32 value)
 177{
 178        u32 tmp;
 179        int timeout = 0;
 180        int status;
 181        int retry;
 182        int err = 0;
 183
 184        if ((reg > 0x7f) || (value > 0x1ff)) {
 185                dev_err(emu->card->dev, "i2c_write: invalid values.\n");
 186                return -EINVAL;
 187        }
 188
 189        /* This function is not re-entrant, so protect against it. */
 190        spin_lock(&emu->i2c_lock);
 191
 192        tmp = reg << 25 | value << 16;
 193
 194        /* This controls the I2C connected to the WM8775 ADC Codec */
 195        snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
 196        tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
 197
 198        for (retry = 0; retry < 10; retry++) {
 199                /* Send the data to i2c */
 200                tmp = 0;
 201                tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
 202                snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
 203
 204                /* Wait till the transaction ends */
 205                while (1) {
 206                        mdelay(1);
 207                        status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
 208                        timeout++;
 209                        if ((status & I2C_A_ADC_START) == 0)
 210                                break;
 211
 212                        if (timeout > 1000) {
 213                                dev_warn(emu->card->dev,
 214                                           "emu10k1:I2C:timeout status=0x%x\n",
 215                                           status);
 216                                break;
 217                        }
 218                }
 219                //Read back and see if the transaction is successful
 220                if ((status & I2C_A_ADC_ABORT) == 0)
 221                        break;
 222        }
 223
 224        if (retry == 10) {
 225                dev_err(emu->card->dev, "Writing to ADC failed!\n");
 226                dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n",
 227                        status, reg, value);
 228                /* dump_stack(); */
 229                err = -EINVAL;
 230        }
 231    
 232        spin_unlock(&emu->i2c_lock);
 233        return err;
 234}
 235
 236int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
 237{
 238        unsigned long flags;
 239
 240        if (reg > 0x3f)
 241                return 1;
 242        reg += 0x40; /* 0x40 upwards are registers. */
 243        if (value > 0x3f) /* 0 to 0x3f are values */
 244                return 1;
 245        spin_lock_irqsave(&emu->emu_lock, flags);
 246        outl(reg, emu->port + A_IOCFG);
 247        udelay(10);
 248        outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
 249        udelay(10);
 250        outl(value, emu->port + A_IOCFG);
 251        udelay(10);
 252        outl(value | 0x80 , emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
 253        spin_unlock_irqrestore(&emu->emu_lock, flags);
 254
 255        return 0;
 256}
 257
 258int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value)
 259{
 260        unsigned long flags;
 261        if (reg > 0x3f)
 262                return 1;
 263        reg += 0x40; /* 0x40 upwards are registers. */
 264        spin_lock_irqsave(&emu->emu_lock, flags);
 265        outl(reg, emu->port + A_IOCFG);
 266        udelay(10);
 267        outl(reg | 0x80, emu->port + A_IOCFG);  /* High bit clocks the value into the fpga. */
 268        udelay(10);
 269        *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f);
 270        spin_unlock_irqrestore(&emu->emu_lock, flags);
 271
 272        return 0;
 273}
 274
 275/* Each Destination has one and only one Source,
 276 * but one Source can feed any number of Destinations simultaneously.
 277 */
 278int snd_emu1010_fpga_link_dst_src_write(struct snd_emu10k1 * emu, u32 dst, u32 src)
 279{
 280        snd_emu1010_fpga_write(emu, 0x00, ((dst >> 8) & 0x3f) );
 281        snd_emu1010_fpga_write(emu, 0x01, (dst & 0x3f) );
 282        snd_emu1010_fpga_write(emu, 0x02, ((src >> 8) & 0x3f) );
 283        snd_emu1010_fpga_write(emu, 0x03, (src & 0x3f) );
 284
 285        return 0;
 286}
 287
 288void snd_emu10k1_intr_enable(struct snd_emu10k1 *emu, unsigned int intrenb)
 289{
 290        unsigned long flags;
 291        unsigned int enable;
 292
 293        spin_lock_irqsave(&emu->emu_lock, flags);
 294        enable = inl(emu->port + INTE) | intrenb;
 295        outl(enable, emu->port + INTE);
 296        spin_unlock_irqrestore(&emu->emu_lock, flags);
 297}
 298
 299void snd_emu10k1_intr_disable(struct snd_emu10k1 *emu, unsigned int intrenb)
 300{
 301        unsigned long flags;
 302        unsigned int enable;
 303
 304        spin_lock_irqsave(&emu->emu_lock, flags);
 305        enable = inl(emu->port + INTE) & ~intrenb;
 306        outl(enable, emu->port + INTE);
 307        spin_unlock_irqrestore(&emu->emu_lock, flags);
 308}
 309
 310void snd_emu10k1_voice_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
 311{
 312        unsigned long flags;
 313        unsigned int val;
 314
 315        spin_lock_irqsave(&emu->emu_lock, flags);
 316        /* voice interrupt */
 317        if (voicenum >= 32) {
 318                outl(CLIEH << 16, emu->port + PTR);
 319                val = inl(emu->port + DATA);
 320                val |= 1 << (voicenum - 32);
 321        } else {
 322                outl(CLIEL << 16, emu->port + PTR);
 323                val = inl(emu->port + DATA);
 324                val |= 1 << voicenum;
 325        }
 326        outl(val, emu->port + DATA);
 327        spin_unlock_irqrestore(&emu->emu_lock, flags);
 328}
 329
 330void snd_emu10k1_voice_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
 331{
 332        unsigned long flags;
 333        unsigned int val;
 334
 335        spin_lock_irqsave(&emu->emu_lock, flags);
 336        /* voice interrupt */
 337        if (voicenum >= 32) {
 338                outl(CLIEH << 16, emu->port + PTR);
 339                val = inl(emu->port + DATA);
 340                val &= ~(1 << (voicenum - 32));
 341        } else {
 342                outl(CLIEL << 16, emu->port + PTR);
 343                val = inl(emu->port + DATA);
 344                val &= ~(1 << voicenum);
 345        }
 346        outl(val, emu->port + DATA);
 347        spin_unlock_irqrestore(&emu->emu_lock, flags);
 348}
 349
 350void snd_emu10k1_voice_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
 351{
 352        unsigned long flags;
 353
 354        spin_lock_irqsave(&emu->emu_lock, flags);
 355        /* voice interrupt */
 356        if (voicenum >= 32) {
 357                outl(CLIPH << 16, emu->port + PTR);
 358                voicenum = 1 << (voicenum - 32);
 359        } else {
 360                outl(CLIPL << 16, emu->port + PTR);
 361                voicenum = 1 << voicenum;
 362        }
 363        outl(voicenum, emu->port + DATA);
 364        spin_unlock_irqrestore(&emu->emu_lock, flags);
 365}
 366
 367void snd_emu10k1_voice_half_loop_intr_enable(struct snd_emu10k1 *emu, unsigned int voicenum)
 368{
 369        unsigned long flags;
 370        unsigned int val;
 371
 372        spin_lock_irqsave(&emu->emu_lock, flags);
 373        /* voice interrupt */
 374        if (voicenum >= 32) {
 375                outl(HLIEH << 16, emu->port + PTR);
 376                val = inl(emu->port + DATA);
 377                val |= 1 << (voicenum - 32);
 378        } else {
 379                outl(HLIEL << 16, emu->port + PTR);
 380                val = inl(emu->port + DATA);
 381                val |= 1 << voicenum;
 382        }
 383        outl(val, emu->port + DATA);
 384        spin_unlock_irqrestore(&emu->emu_lock, flags);
 385}
 386
 387void snd_emu10k1_voice_half_loop_intr_disable(struct snd_emu10k1 *emu, unsigned int voicenum)
 388{
 389        unsigned long flags;
 390        unsigned int val;
 391
 392        spin_lock_irqsave(&emu->emu_lock, flags);
 393        /* voice interrupt */
 394        if (voicenum >= 32) {
 395                outl(HLIEH << 16, emu->port + PTR);
 396                val = inl(emu->port + DATA);
 397                val &= ~(1 << (voicenum - 32));
 398        } else {
 399                outl(HLIEL << 16, emu->port + PTR);
 400                val = inl(emu->port + DATA);
 401                val &= ~(1 << voicenum);
 402        }
 403        outl(val, emu->port + DATA);
 404        spin_unlock_irqrestore(&emu->emu_lock, flags);
 405}
 406
 407void snd_emu10k1_voice_half_loop_intr_ack(struct snd_emu10k1 *emu, unsigned int voicenum)
 408{
 409        unsigned long flags;
 410
 411        spin_lock_irqsave(&emu->emu_lock, flags);
 412        /* voice interrupt */
 413        if (voicenum >= 32) {
 414                outl(HLIPH << 16, emu->port + PTR);
 415                voicenum = 1 << (voicenum - 32);
 416        } else {
 417                outl(HLIPL << 16, emu->port + PTR);
 418                voicenum = 1 << voicenum;
 419        }
 420        outl(voicenum, emu->port + DATA);
 421        spin_unlock_irqrestore(&emu->emu_lock, flags);
 422}
 423
 424void snd_emu10k1_voice_set_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
 425{
 426        unsigned long flags;
 427        unsigned int sol;
 428
 429        spin_lock_irqsave(&emu->emu_lock, flags);
 430        /* voice interrupt */
 431        if (voicenum >= 32) {
 432                outl(SOLEH << 16, emu->port + PTR);
 433                sol = inl(emu->port + DATA);
 434                sol |= 1 << (voicenum - 32);
 435        } else {
 436                outl(SOLEL << 16, emu->port + PTR);
 437                sol = inl(emu->port + DATA);
 438                sol |= 1 << voicenum;
 439        }
 440        outl(sol, emu->port + DATA);
 441        spin_unlock_irqrestore(&emu->emu_lock, flags);
 442}
 443
 444void snd_emu10k1_voice_clear_loop_stop(struct snd_emu10k1 *emu, unsigned int voicenum)
 445{
 446        unsigned long flags;
 447        unsigned int sol;
 448
 449        spin_lock_irqsave(&emu->emu_lock, flags);
 450        /* voice interrupt */
 451        if (voicenum >= 32) {
 452                outl(SOLEH << 16, emu->port + PTR);
 453                sol = inl(emu->port + DATA);
 454                sol &= ~(1 << (voicenum - 32));
 455        } else {
 456                outl(SOLEL << 16, emu->port + PTR);
 457                sol = inl(emu->port + DATA);
 458                sol &= ~(1 << voicenum);
 459        }
 460        outl(sol, emu->port + DATA);
 461        spin_unlock_irqrestore(&emu->emu_lock, flags);
 462}
 463
 464void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait)
 465{
 466        volatile unsigned count;
 467        unsigned int newtime = 0, curtime;
 468
 469        curtime = inl(emu->port + WC) >> 6;
 470        while (wait-- > 0) {
 471                count = 0;
 472                while (count++ < 16384) {
 473                        newtime = inl(emu->port + WC) >> 6;
 474                        if (newtime != curtime)
 475                                break;
 476                }
 477                if (count > 16384)
 478                        break;
 479                curtime = newtime;
 480        }
 481}
 482
 483unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
 484{
 485        struct snd_emu10k1 *emu = ac97->private_data;
 486        unsigned long flags;
 487        unsigned short val;
 488
 489        spin_lock_irqsave(&emu->emu_lock, flags);
 490        outb(reg, emu->port + AC97ADDRESS);
 491        val = inw(emu->port + AC97DATA);
 492        spin_unlock_irqrestore(&emu->emu_lock, flags);
 493        return val;
 494}
 495
 496void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data)
 497{
 498        struct snd_emu10k1 *emu = ac97->private_data;
 499        unsigned long flags;
 500
 501        spin_lock_irqsave(&emu->emu_lock, flags);
 502        outb(reg, emu->port + AC97ADDRESS);
 503        outw(data, emu->port + AC97DATA);
 504        spin_unlock_irqrestore(&emu->emu_lock, flags);
 505}
 506
 507/*
 508 *  convert rate to pitch
 509 */
 510
 511unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate)
 512{
 513        static u32 logMagTable[128] = {
 514                0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
 515                0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
 516                0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
 517                0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
 518                0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
 519                0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
 520                0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
 521                0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
 522                0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
 523                0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
 524                0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
 525                0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
 526                0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
 527                0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
 528                0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
 529                0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
 530        };
 531        static char logSlopeTable[128] = {
 532                0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
 533                0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
 534                0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
 535                0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
 536                0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
 537                0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
 538                0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
 539                0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
 540                0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
 541                0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
 542                0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
 543                0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
 544                0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
 545                0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
 546                0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
 547                0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
 548        };
 549        int i;
 550
 551        if (rate == 0)
 552                return 0;       /* Bail out if no leading "1" */
 553        rate *= 11185;          /* Scale 48000 to 0x20002380 */
 554        for (i = 31; i > 0; i--) {
 555                if (rate & 0x80000000) {        /* Detect leading "1" */
 556                        return (((unsigned int) (i - 15) << 20) +
 557                               logMagTable[0x7f & (rate >> 24)] +
 558                                        (0x7f & (rate >> 17)) *
 559                                        logSlopeTable[0x7f & (rate >> 24)]);
 560                }
 561                rate <<= 1;
 562        }
 563
 564        return 0;               /* Should never reach this point */
 565}
 566
 567