cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

io.c (15507B)


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