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("emu10k1:I2C:timeout status=0x%x\n", 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                snd_printk(KERN_ERR "Writing to ADC failed!\n");
 240                snd_printk(KERN_ERR "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 < 0 || 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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.