aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/emu10k1/io.c
diff options
context:
space:
mode:
authorJames Courtier-Dutton <James@superbug.co.uk>2007-11-10 12:55:14 -0500
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:30:24 -0500
commitc94fa4c9168e51a8dab8e72cb9f0d89673fc8d8c (patch)
tree08169553a3b69a284b322941131f406661e499e8 /sound/pci/emu10k1/io.c
parent3839e4f136d6da3dc85d237aa9569ee94bfea763 (diff)
[ALSA] emu10k1: General cleanup, add new locks, fix alsa bug#3501, kernel bug#9304.
Signed-off-by: James Courtier-Dutton <James@superbug.co.uk> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/emu10k1/io.c')
-rw-r--r--sound/pci/emu10k1/io.c52
1 files changed, 37 insertions, 15 deletions
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index a02638350a0a..b5a802bdeb7c 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -70,6 +70,11 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
70 unsigned long flags; 70 unsigned long flags;
71 unsigned int mask; 71 unsigned int mask;
72 72
73 if (!emu) {
74 snd_printk(KERN_ERR "ptr_write: emu is null!\n");
75 dump_stack();
76 return;
77 }
73 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; 78 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
74 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); 79 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
75 80
@@ -134,15 +139,23 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
134 unsigned int reset, set; 139 unsigned int reset, set;
135 unsigned int reg, tmp; 140 unsigned int reg, tmp;
136 int n, result; 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);
137 if (emu->card_capabilities->ca0108_chip) 146 if (emu->card_capabilities->ca0108_chip)
138 reg = 0x3c; /* PTR20, reg 0x3c */ 147 reg = 0x3c; /* PTR20, reg 0x3c */
139 else { 148 else {
140 /* For other chip types the SPI register 149 /* For other chip types the SPI register
141 * is currently unknown. */ 150 * is currently unknown. */
142 return 1; 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;
143 } 158 }
144 if (data > 0xffff) /* Only 16bit values allowed */
145 return 1;
146 159
147 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); 160 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
148 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ 161 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
@@ -160,11 +173,17 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
160 break; 173 break;
161 } 174 }
162 } 175 }
163 if (result) /* Timed out */ 176 if (result) {
164 return 1; 177 /* Timed out */
178 err = 1;
179 goto spi_write_exit;
180 }
165 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); 181 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
166 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ 182 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
167 return 0; 183 err = 0;
184spi_write_exit:
185 spin_unlock(&emu->spi_lock);
186 return err;
168} 187}
169 188
170/* The ADC does not support i2c read, so only write is implemented */ 189/* The ADC does not support i2c read, so only write is implemented */
@@ -176,15 +195,17 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
176 int timeout = 0; 195 int timeout = 0;
177 int status; 196 int status;
178 int retry; 197 int retry;
198 int err = 0;
199
179 if ((reg > 0x7f) || (value > 0x1ff)) { 200 if ((reg > 0x7f) || (value > 0x1ff)) {
180 snd_printk(KERN_ERR "i2c_write: invalid values.\n"); 201 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
181 return -EINVAL; 202 return -EINVAL;
182 } 203 }
183 204
205 /* This function is not re-entrant, so protect against it. */
206 spin_lock(&emu->i2c_lock);
207
184 tmp = reg << 25 | value << 16; 208 tmp = reg << 25 | value << 16;
185 // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
186 /* Not sure what this I2C channel controls. */
187 /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
188 209
189 /* This controls the I2C connected to the WM8775 ADC Codec */ 210 /* This controls the I2C connected to the WM8775 ADC Codec */
190 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); 211 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
@@ -192,17 +213,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
192 213
193 for (retry = 0; retry < 10; retry++) { 214 for (retry = 0; retry < 10; retry++) {
194 /* Send the data to i2c */ 215 /* Send the data to i2c */
195 //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
196 //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
197 tmp = 0; 216 tmp = 0;
198 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); 217 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
199 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); 218 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
200 219
201 /* Wait till the transaction ends */ 220 /* Wait till the transaction ends */
202 while (1) { 221 while (1) {
203 udelay(10); 222 mdelay(1);
204 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); 223 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
205 // snd_printk("I2C:status=0x%x\n", status);
206 timeout++; 224 timeout++;
207 if ((status & I2C_A_ADC_START) == 0) 225 if ((status & I2C_A_ADC_START) == 0)
208 break; 226 break;
@@ -219,10 +237,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
219 237
220 if (retry == 10) { 238 if (retry == 10) {
221 snd_printk(KERN_ERR "Writing to ADC failed!\n"); 239 snd_printk(KERN_ERR "Writing to ADC failed!\n");
222 return -EINVAL; 240 snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
241 status, reg, value);
242 /* dump_stack(); */
243 err = -EINVAL;
223 } 244 }
224 245
225 return 0; 246 spin_unlock(&emu->i2c_lock);
247 return err;
226} 248}
227 249
228int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) 250int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)