linux/sound/pci/emu10k1/io.c
<<
>>
Prefs
   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
  35unsigned 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
  66EXPORT_SYMBOL(snd_emu10k1_ptr_read);
  67
  68void 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 (snd_BUG_ON(!emu))
  75                return;
  76        mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
  77        regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
  78
  79        if (reg & 0xff000000) {
  80                unsigned char size, offset;
  81
  82                size = (reg >> 24) & 0x3f;
  83                offset = (reg >> 16) & 0x1f;
  84                mask = ((1 << size) - 1) << offset;
  85                data = (data << offset) & mask;
  86
  87                spin_lock_irqsave(&emu->emu_lock, flags);
  88                outl(regptr, emu->port + PTR);
  89                data |= inl(emu->port + DATA) & ~mask;
  90                outl(data, emu->port + DATA);
  91                spin_unlock_irqrestore(&emu->emu_lock, flags);          
  92        } else {
  93                spin_lock_irqsave(&emu->emu_lock, flags);
  94                outl(regptr, emu->port + PTR);
  95                outl(data, emu->port + DATA);
  96                spin_unlock_irqrestore(&emu->emu_lock, flags);
  97        }
  98}
  99
 100EXPORT_SYMBOL(snd_emu10k1_ptr_write);
 101
 102unsigned int snd_emu10k1_ptr20_read(struct snd_emu10k1 * emu, 
 103                                          unsigned int reg, 
 104                                          unsigned int chn)
 105{
 106        unsigned long flags;
 107        unsigned int regptr, val;
 108  
 109        regptr = (reg << 16) | chn;
 110
 111        spin_lock_irqsave(&emu->emu_lock, flags);
 112        outl(regptr, emu->port + 0x20 + PTR);
 113        val = inl(emu->port + 0x20 + DATA);
 114        spin_unlock_irqrestore(&emu->emu_lock, flags);
 115        return val;
 116}
 117
 118void snd_emu10k1_ptr20_write(struct snd_emu10k1 *emu, 
 119                                   unsigned int reg, 
 120                                   unsigned int chn, 
 121                                   unsigned int data)
 122{
 123        unsigned int regptr;
 124        unsigned long flags;
 125
 126        regptr = (reg << 16) | chn;
 127
 128        spin_lock_irqsave(&emu->emu_lock, flags);
 129        outl(regptr, emu->port + 0x20 + PTR);
 130        outl(data, emu->port + 0x20 + DATA);
 131        spin_unlock_irqrestore(&emu->emu_lock, flags);
 132}
 133
 134int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
 135                                   unsigned int data)
 136{
 137        unsigned int reset, set;
 138        unsigned int reg, tmp;
 139        int n, result;
 140        int err = 0;
 141
 142        /* This function is not re-entrant, so protect against it. */
 143        spin_lock(&emu->spi_lock);
 144        if (emu->card_capabilities->ca0108_chip)
 145                reg = 0x3c; /* PTR20, reg 0x3c */
 146        else {
 147                /* For other chip types the SPI register
 148                 * is currently unknown. */
 149                err = 1;
 150                goto spi_write_exit;
 151        }
 152        if (data > 0xffff) {
 153                /* Only 16bit values allowed */
 154                err = 1;
 155                goto spi_write_exit;
 156        }
 157
 158        tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
 159        reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
 160        set = reset | 0x10000; /* Set xxx1xxxx */
 161        snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
 162        tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* write post */
 163        snd_emu10k1_ptr20_write(emu, reg, 0, set | data);
 164        result = 1;
 165        /* Wait for status bit to return to 0 */
 166        for (n = 0; n < 100; n++) {
 167                udelay(10);
 168                tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
 169                if (!(tmp & 0x10000)) {
 170                        result = 0;
 171                        break;
 172                }
 173        }
 174        if (result) {
 175                /* Timed out */
 176                err = 1;
 177                goto spi_write_exit;
 178        }
 179        snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
 180        tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
 181        err = 0;
 182spi_write_exit:
 183        spin_unlock(&emu->spi_lock);
 184        return err;
 185}
 186
 187/* The ADC does not support i2c read, so only write is implemented */
 188int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
 189                                u32 reg,
 190                                u32 value)
 191{
 192        u32 tmp;
 193        int timeout = 0;
 194        int status;
 195        int retry;
 196        int err = 0;
 197
 198        if ((reg > 0x7f) || (value > 0x1ff)) {
 199                dev_err(emu->card->dev, "i2c_write: invalid values.\n");
 200                return -EINVAL;
 201        }
 202
 203        /* This function is not re-entrant, so protect against it. */
 204        spin_lock(&emu->i2c_lock);
 205
 206        tmp = reg << 25 | value << 16;
 207
 208        /* This controls the I2C connected to the WM8775 ADC Codec */
 209        snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
 210        tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */
 211
 212        for (retry = 0; retry < 10; retry++) {
 213                /* Send the data to i2c */
 214                tmp = 0;
 215                tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
 216                snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
 217
 218                /* Wait till the transaction ends */
 219                while (1) {
 220                        mdelay(1);
 221                        status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
 222                        timeout++;
 223                        if ((status & I2C_A_ADC_START) == 0)
 224                                break;
 225
 226                        if (timeout > 1000) {
 227                                dev_warn(emu->card->dev,
 228                                           "emu10k1:I2C:timeout status=0x%x\n",
 229                                           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                dev_err(emu->card->dev, "Writing to ADC failed!\n");
 240                dev_err(emu->card->dev, "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
 250int 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 > 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
 272int 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 */
 292int 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
 302void 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
 313void 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
 324void 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
 344void 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
 364void 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
 381void 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
 401void 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
 421void 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
 438void 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
 458void 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
 478void 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
 497unsigned 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
 510void 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
 525unsigned 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
 581