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