diff options
author | James Courtier-Dutton <James@superbug.co.uk> | 2007-11-10 12:55:14 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:30:24 -0500 |
commit | c94fa4c9168e51a8dab8e72cb9f0d89673fc8d8c (patch) | |
tree | 08169553a3b69a284b322941131f406661e499e8 /sound/pci/emu10k1/io.c | |
parent | 3839e4f136d6da3dc85d237aa9569ee94bfea763 (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.c | 52 |
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; |
184 | spi_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 | ||
228 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) | 250 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) |