aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ice1712/ice1724.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-04-23 11:47:28 -0400
committerTakashi Iwai <tiwai@suse.de>2008-04-24 06:38:25 -0400
commit3a841d519f91463361bbbe7addc24a0c1b2e9f99 (patch)
treec2044e30d0898659898be8b1e011337d2b623035 /sound/pci/ice1712/ice1724.c
parentb415ed45f4db9f8365daac84cf2518642a174dc0 (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/ice1712/ice1724.c')
-rw-r--r--sound/pci/ice1712/ice1724.c95
1 files changed, 81 insertions, 14 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 */
228static 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
239static 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