diff options
Diffstat (limited to 'sound/pci/emu10k1/io.c')
| -rw-r--r-- | sound/pci/emu10k1/io.c | 70 |
1 files changed, 49 insertions, 21 deletions
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 6702c15fefa..706b4f0c680 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -25,11 +25,11 @@ * */ -#include <sound/driver.h> #include <linux/time.h> #include <sound/core.h> #include <sound/emu10k1.h> #include <linux/delay.h> +#include <linux/export.h> #include "p17v.h" unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) @@ -71,6 +71,8 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i unsigned long flags; unsigned int mask; + if (snd_BUG_ON(!emu)) + return; mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); @@ -135,15 +137,23 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, unsigned int reset, set; unsigned int reg, tmp; int n, result; + int err = 0; + + /* This function is not re-entrant, so protect against it. */ + spin_lock(&emu->spi_lock); if (emu->card_capabilities->ca0108_chip) reg = 0x3c; /* PTR20, reg 0x3c */ else { /* For other chip types the SPI register * is currently unknown. */ - return 1; + err = 1; + goto spi_write_exit; + } + if (data > 0xffff) { + /* Only 16bit values allowed */ + err = 1; + goto spi_write_exit; } - if (data > 0xffff) /* Only 16bit values allowed */ - return 1; tmp = snd_emu10k1_ptr20_read(emu, reg, 0); reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ @@ -161,11 +171,17 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, break; } } - if (result) /* Timed out */ - return 1; + if (result) { + /* Timed out */ + err = 1; + goto spi_write_exit; + } snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ - return 0; + err = 0; +spi_write_exit: + spin_unlock(&emu->spi_lock); + return err; } /* The ADC does not support i2c read, so only write is implemented */ @@ -177,15 +193,17 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, int timeout = 0; int status; int retry; + int err = 0; + if ((reg > 0x7f) || (value > 0x1ff)) { - snd_printk(KERN_ERR "i2c_write: invalid values.\n"); + dev_err(emu->card->dev, "i2c_write: invalid values.\n"); return -EINVAL; } + /* This function is not re-entrant, so protect against it. */ + spin_lock(&emu->i2c_lock); + tmp = reg << 25 | value << 16; - // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); - /* Not sure what this I2C channel controls. */ - /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */ /* This controls the I2C connected to the WM8775 ADC Codec */ snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); @@ -193,23 +211,22 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, for (retry = 0; retry < 10; retry++) { /* Send the data to i2c */ - //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0); - //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); tmp = 0; tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); /* Wait till the transaction ends */ while (1) { - udelay(10); + mdelay(1); status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); - // snd_printk("I2C:status=0x%x\n", status); timeout++; if ((status & I2C_A_ADC_START) == 0) break; if (timeout > 1000) { - snd_printk("emu10k1:I2C:timeout status=0x%x\n", status); + dev_warn(emu->card->dev, + "emu10k1:I2C:timeout status=0x%x\n", + status); break; } } @@ -219,20 +236,27 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, } if (retry == 10) { - snd_printk(KERN_ERR "Writing to ADC failed!\n"); - return -EINVAL; + dev_err(emu->card->dev, "Writing to ADC failed!\n"); + dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n", + status, reg, value); + /* dump_stack(); */ + err = -EINVAL; } - return 0; + spin_unlock(&emu->i2c_lock); + return err; } int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) { + unsigned long flags; + if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ - if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ + if (value > 0x3f) /* 0 to 0x3f are values */ return 1; + spin_lock_irqsave(&emu->emu_lock, flags); outl(reg, emu->port + A_IOCFG); udelay(10); outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ @@ -240,20 +264,24 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) outl(value, emu->port + A_IOCFG); udelay(10); outl(value | 0x80 , emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ + spin_unlock_irqrestore(&emu->emu_lock, flags); return 0; } int snd_emu1010_fpga_read(struct snd_emu10k1 * emu, u32 reg, u32 *value) { + unsigned long flags; if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ + spin_lock_irqsave(&emu->emu_lock, flags); outl(reg, emu->port + A_IOCFG); udelay(10); outl(reg | 0x80, emu->port + A_IOCFG); /* High bit clocks the value into the fpga. */ udelay(10); *value = ((inl(emu->port + A_IOCFG) >> 8) & 0x7f); + spin_unlock_irqrestore(&emu->emu_lock, flags); return 0; } @@ -460,7 +488,7 @@ void snd_emu10k1_wait(struct snd_emu10k1 *emu, unsigned int wait) if (newtime != curtime) break; } - if (count >= 16384) + if (count > 16384) break; curtime = newtime; } |
