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 "p17v.h"
  33
  34unsigned 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
  65EXPORT_SYMBOL(snd_emu10k1_ptr_read);
  66
  67void 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
 102EXPORT_SYMBOL(snd_emu10k1_ptr_write);
 103
 104unsigned 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
 120void 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
 136int 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;
 184spi_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 */
 190int 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
 252int 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
 274int 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 */
 294int 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
 304void 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
 315void 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
 326void 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
 346void 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
 366void 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
 383void 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
 403void 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
 423void 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
 440void 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
 460void 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
 480void 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
 499unsigned 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
 512void 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
 527unsigned 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
 583