diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-04-23 11:47:28 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-04-24 06:38:25 -0400 |
commit | 3a841d519f91463361bbbe7addc24a0c1b2e9f99 (patch) | |
tree | c2044e30d0898659898be8b1e011337d2b623035 /sound/pci | |
parent | b415ed45f4db9f8365daac84cf2518642a174dc0 (diff) |
[ALSA] ice1724 - Fix IRQ lock-up with MPU access
The sound boards with VT1724 and compatible chips may lock up when
MPU401 is accessed together with the PCM streaming.
This patch fixes the problem.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/ice1712/ice1724.c | 95 | ||||
-rw-r--r-- | sound/pci/ice1712/prodigy192.c | 4 |
2 files changed, 81 insertions, 18 deletions
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 13ea94f317cb..4490422fb930 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -223,6 +223,32 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice) | |||
223 | } | 223 | } |
224 | 224 | ||
225 | /* | 225 | /* |
226 | * MPU401 accessor | ||
227 | */ | ||
228 | static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu, | ||
229 | unsigned long addr) | ||
230 | { | ||
231 | /* fix status bits to the standard position */ | ||
232 | /* only RX_EMPTY and TX_FULL are checked */ | ||
233 | if (addr == MPU401C(mpu)) | ||
234 | return (inb(addr) & 0x0c) << 4; | ||
235 | else | ||
236 | return inb(addr); | ||
237 | } | ||
238 | |||
239 | static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu, | ||
240 | unsigned char data, unsigned long addr) | ||
241 | { | ||
242 | if (addr == MPU401C(mpu)) { | ||
243 | if (data == MPU401_ENTER_UART) | ||
244 | outb(0x01, addr); | ||
245 | /* what else? */ | ||
246 | } else | ||
247 | outb(data, addr); | ||
248 | } | ||
249 | |||
250 | |||
251 | /* | ||
226 | * Interrupt handler | 252 | * Interrupt handler |
227 | */ | 253 | */ |
228 | 254 | ||
@@ -230,24 +256,53 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
230 | { | 256 | { |
231 | struct snd_ice1712 *ice = dev_id; | 257 | struct snd_ice1712 *ice = dev_id; |
232 | unsigned char status; | 258 | unsigned char status; |
259 | unsigned char status_mask = | ||
260 | VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM; | ||
233 | int handled = 0; | 261 | int handled = 0; |
262 | #ifdef CONFIG_SND_DEBUG | ||
263 | int timeout = 0; | ||
264 | #endif | ||
234 | 265 | ||
235 | while (1) { | 266 | while (1) { |
236 | status = inb(ICEREG1724(ice, IRQSTAT)); | 267 | status = inb(ICEREG1724(ice, IRQSTAT)); |
268 | status &= status_mask; | ||
237 | if (status == 0) | 269 | if (status == 0) |
238 | break; | 270 | break; |
239 | 271 | #ifdef CONFIG_SND_DEBUG | |
272 | if (++timeout > 10) { | ||
273 | printk(KERN_ERR | ||
274 | "ice1724: Too long irq loop, status = 0x%x\n", | ||
275 | status); | ||
276 | break; | ||
277 | } | ||
278 | #endif | ||
240 | handled = 1; | 279 | handled = 1; |
241 | /* these should probably be separated at some point, | 280 | if (status & VT1724_IRQ_MPU_TX) { |
242 | * but as we don't currently have MPU support on the board | ||
243 | * I will leave it | ||
244 | */ | ||
245 | if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) { | ||
246 | if (ice->rmidi[0]) | 281 | if (ice->rmidi[0]) |
247 | snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data); | 282 | snd_mpu401_uart_interrupt_tx(irq, |
248 | outb(status & (VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX), ICEREG1724(ice, IRQSTAT)); | 283 | ice->rmidi[0]->private_data); |
249 | status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX); | 284 | else /* disable TX to be sure */ |
285 | outb(inb(ICEREG1724(ice, IRQMASK)) | | ||
286 | VT1724_IRQ_MPU_TX, | ||
287 | ICEREG1724(ice, IRQMASK)); | ||
288 | /* Due to mysterical reasons, MPU_TX is always | ||
289 | * generated (and can't be cleared) when a PCM | ||
290 | * playback is going. So let's ignore at the | ||
291 | * next loop. | ||
292 | */ | ||
293 | status_mask &= ~VT1724_IRQ_MPU_TX; | ||
294 | } | ||
295 | if (status & VT1724_IRQ_MPU_RX) { | ||
296 | if (ice->rmidi[0]) | ||
297 | snd_mpu401_uart_interrupt(irq, | ||
298 | ice->rmidi[0]->private_data); | ||
299 | else /* disable RX to be sure */ | ||
300 | outb(inb(ICEREG1724(ice, IRQMASK)) | | ||
301 | VT1724_IRQ_MPU_RX, | ||
302 | ICEREG1724(ice, IRQMASK)); | ||
250 | } | 303 | } |
304 | /* ack MPU irq */ | ||
305 | outb(status, ICEREG1724(ice, IRQSTAT)); | ||
251 | if (status & VT1724_IRQ_MTPCM) { | 306 | if (status & VT1724_IRQ_MTPCM) { |
252 | /* | 307 | /* |
253 | * Multi-track PCM | 308 | * Multi-track PCM |
@@ -2236,10 +2291,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card, | |||
2236 | } | 2291 | } |
2237 | 2292 | ||
2238 | /* unmask used interrupts */ | 2293 | /* unmask used interrupts */ |
2239 | if (! (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401)) | 2294 | mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX; |
2240 | mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX; | ||
2241 | else | ||
2242 | mask = 0; | ||
2243 | outb(mask, ICEREG1724(ice, IRQMASK)); | 2295 | outb(mask, ICEREG1724(ice, IRQMASK)); |
2244 | /* don't handle FIFO overrun/underruns (just yet), | 2296 | /* don't handle FIFO overrun/underruns (just yet), |
2245 | * since they cause machine lockups | 2297 | * since they cause machine lockups |
@@ -2373,14 +2425,29 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, | |||
2373 | 2425 | ||
2374 | if (! c->no_mpu401) { | 2426 | if (! c->no_mpu401) { |
2375 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { | 2427 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { |
2428 | struct snd_mpu401 *mpu; | ||
2376 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, | 2429 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, |
2377 | ICEREG1724(ice, MPU_CTRL), | 2430 | ICEREG1724(ice, MPU_CTRL), |
2378 | MPU401_INFO_INTEGRATED, | 2431 | (MPU401_INFO_INTEGRATED | |
2432 | MPU401_INFO_TX_IRQ), | ||
2379 | ice->irq, 0, | 2433 | ice->irq, 0, |
2380 | &ice->rmidi[0])) < 0) { | 2434 | &ice->rmidi[0])) < 0) { |
2381 | snd_card_free(card); | 2435 | snd_card_free(card); |
2382 | return err; | 2436 | return err; |
2383 | } | 2437 | } |
2438 | mpu = ice->rmidi[0]->private_data; | ||
2439 | mpu->read = snd_vt1724_mpu401_read; | ||
2440 | mpu->write = snd_vt1724_mpu401_write; | ||
2441 | /* unmask MPU RX/TX irqs */ | ||
2442 | outb(inb(ICEREG1724(ice, IRQMASK)) & | ||
2443 | ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX), | ||
2444 | ICEREG1724(ice, IRQMASK)); | ||
2445 | #if 0 /* for testing */ | ||
2446 | /* set watermarks */ | ||
2447 | outb(VT1724_MPU_RX_FIFO | 0x1, | ||
2448 | ICEREG1724(ice, MPU_FIFO_WM)); | ||
2449 | outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); | ||
2450 | #endif | ||
2384 | } | 2451 | } |
2385 | } | 2452 | } |
2386 | 2453 | ||
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 25ceb67a9c16..48d3679292a7 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -812,10 +812,6 @@ struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { | |||
812 | .build_controls = prodigy192_add_controls, | 812 | .build_controls = prodigy192_add_controls, |
813 | .eeprom_size = sizeof(prodigy71_eeprom), | 813 | .eeprom_size = sizeof(prodigy71_eeprom), |
814 | .eeprom_data = prodigy71_eeprom, | 814 | .eeprom_data = prodigy71_eeprom, |
815 | /* the current MPU401 code loops infinitely | ||
816 | * when opening midi device | ||
817 | */ | ||
818 | .no_mpu401 = 1, | ||
819 | }, | 815 | }, |
820 | { } /* terminator */ | 816 | { } /* terminator */ |
821 | }; | 817 | }; |