diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-11-12 10:42:44 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-02-02 11:22:31 -0500 |
commit | e683ec4697c74c7d04ff8e90ec625ac34e25a7d8 (patch) | |
tree | 982e73c3f194843130c68bf86316a0502dcab24e /sound/pci | |
parent | 18e352e4a73465349711a9324767e1b2453383e2 (diff) |
ALSA: ice1724 - Dynamic MIDI TX irq control
MIDI_TX IRQ seems always pending when any bytes on FIFO is available.
Thus, it's better to enable MPU_TX only when any bytres are really
stored in the substream, and disables immediately when the queue
becomes empty.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/ice1712/ice1724.c | 43 |
1 files changed, 27 insertions, 16 deletions
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index bb8d8c766b9d..eb7872dec5ae 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -241,6 +241,8 @@ get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream) | |||
241 | struct snd_rawmidi_substream, list); | 241 | struct snd_rawmidi_substream, list); |
242 | } | 242 | } |
243 | 243 | ||
244 | static void enable_midi_irq(struct snd_ice1712 *ice, u8 flag, int enable); | ||
245 | |||
244 | static void vt1724_midi_write(struct snd_ice1712 *ice) | 246 | static void vt1724_midi_write(struct snd_ice1712 *ice) |
245 | { | 247 | { |
246 | struct snd_rawmidi_substream *s; | 248 | struct snd_rawmidi_substream *s; |
@@ -254,6 +256,11 @@ static void vt1724_midi_write(struct snd_ice1712 *ice) | |||
254 | for (i = 0; i < count; ++i) | 256 | for (i = 0; i < count; ++i) |
255 | outb(buffer[i], ICEREG1724(ice, MPU_DATA)); | 257 | outb(buffer[i], ICEREG1724(ice, MPU_DATA)); |
256 | } | 258 | } |
259 | /* mask irq when all bytes have been transmitted. | ||
260 | * enabled again in output_trigger when the new data comes in. | ||
261 | */ | ||
262 | enable_midi_irq(ice, VT1724_IRQ_MPU_TX, | ||
263 | !snd_rawmidi_transmit_empty(s)); | ||
257 | } | 264 | } |
258 | 265 | ||
259 | static void vt1724_midi_read(struct snd_ice1712 *ice) | 266 | static void vt1724_midi_read(struct snd_ice1712 *ice) |
@@ -272,31 +279,34 @@ static void vt1724_midi_read(struct snd_ice1712 *ice) | |||
272 | } | 279 | } |
273 | } | 280 | } |
274 | 281 | ||
275 | static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, | 282 | /* call with ice->reg_lock */ |
276 | u8 flag, int enable) | 283 | static void enable_midi_irq(struct snd_ice1712 *ice, u8 flag, int enable) |
277 | { | 284 | { |
278 | struct snd_ice1712 *ice = substream->rmidi->private_data; | 285 | u8 mask = inb(ICEREG1724(ice, IRQMASK)); |
279 | u8 mask; | ||
280 | |||
281 | spin_lock_irq(&ice->reg_lock); | ||
282 | mask = inb(ICEREG1724(ice, IRQMASK)); | ||
283 | if (enable) | 286 | if (enable) |
284 | mask &= ~flag; | 287 | mask &= ~flag; |
285 | else | 288 | else |
286 | mask |= flag; | 289 | mask |= flag; |
287 | outb(mask, ICEREG1724(ice, IRQMASK)); | 290 | outb(mask, ICEREG1724(ice, IRQMASK)); |
291 | } | ||
292 | |||
293 | static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, | ||
294 | u8 flag, int enable) | ||
295 | { | ||
296 | struct snd_ice1712 *ice = substream->rmidi->private_data; | ||
297 | |||
298 | spin_lock_irq(&ice->reg_lock); | ||
299 | enable_midi_irq(ice, flag, enable); | ||
288 | spin_unlock_irq(&ice->reg_lock); | 300 | spin_unlock_irq(&ice->reg_lock); |
289 | } | 301 | } |
290 | 302 | ||
291 | static int vt1724_midi_output_open(struct snd_rawmidi_substream *s) | 303 | static int vt1724_midi_output_open(struct snd_rawmidi_substream *s) |
292 | { | 304 | { |
293 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1); | ||
294 | return 0; | 305 | return 0; |
295 | } | 306 | } |
296 | 307 | ||
297 | static int vt1724_midi_output_close(struct snd_rawmidi_substream *s) | 308 | static int vt1724_midi_output_close(struct snd_rawmidi_substream *s) |
298 | { | 309 | { |
299 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0); | ||
300 | return 0; | 310 | return 0; |
301 | } | 311 | } |
302 | 312 | ||
@@ -311,6 +321,7 @@ static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) | |||
311 | vt1724_midi_write(ice); | 321 | vt1724_midi_write(ice); |
312 | } else { | 322 | } else { |
313 | ice->midi_output = 0; | 323 | ice->midi_output = 0; |
324 | enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); | ||
314 | } | 325 | } |
315 | spin_unlock_irqrestore(&ice->reg_lock, flags); | 326 | spin_unlock_irqrestore(&ice->reg_lock, flags); |
316 | } | 327 | } |
@@ -320,6 +331,7 @@ static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) | |||
320 | struct snd_ice1712 *ice = s->rmidi->private_data; | 331 | struct snd_ice1712 *ice = s->rmidi->private_data; |
321 | unsigned long timeout; | 332 | unsigned long timeout; |
322 | 333 | ||
334 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0); | ||
323 | /* 32 bytes should be transmitted in less than about 12 ms */ | 335 | /* 32 bytes should be transmitted in less than about 12 ms */ |
324 | timeout = jiffies + msecs_to_jiffies(15); | 336 | timeout = jiffies + msecs_to_jiffies(15); |
325 | do { | 337 | do { |
@@ -389,24 +401,24 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
389 | status &= status_mask; | 401 | status &= status_mask; |
390 | if (status == 0) | 402 | if (status == 0) |
391 | break; | 403 | break; |
404 | spin_lock(&ice->reg_lock); | ||
392 | if (++timeout > 10) { | 405 | if (++timeout > 10) { |
393 | status = inb(ICEREG1724(ice, IRQSTAT)); | 406 | status = inb(ICEREG1724(ice, IRQSTAT)); |
394 | printk(KERN_ERR "ice1724: Too long irq loop, " | 407 | printk(KERN_ERR "ice1724: Too long irq loop, " |
395 | "status = 0x%x\n", status); | 408 | "status = 0x%x\n", status); |
396 | if (status & VT1724_IRQ_MPU_TX) { | 409 | if (status & VT1724_IRQ_MPU_TX) { |
397 | printk(KERN_ERR "ice1724: Disabling MPU_TX\n"); | 410 | printk(KERN_ERR "ice1724: Disabling MPU_TX\n"); |
398 | outb(inb(ICEREG1724(ice, IRQMASK)) | | 411 | enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); |
399 | VT1724_IRQ_MPU_TX, | ||
400 | ICEREG1724(ice, IRQMASK)); | ||
401 | } | 412 | } |
413 | spin_unlock(&ice->reg_lock); | ||
402 | break; | 414 | break; |
403 | } | 415 | } |
404 | handled = 1; | 416 | handled = 1; |
405 | if (status & VT1724_IRQ_MPU_TX) { | 417 | if (status & VT1724_IRQ_MPU_TX) { |
406 | spin_lock(&ice->reg_lock); | ||
407 | if (ice->midi_output) | 418 | if (ice->midi_output) |
408 | vt1724_midi_write(ice); | 419 | vt1724_midi_write(ice); |
409 | spin_unlock(&ice->reg_lock); | 420 | else |
421 | enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); | ||
410 | /* Due to mysterical reasons, MPU_TX is always | 422 | /* Due to mysterical reasons, MPU_TX is always |
411 | * generated (and can't be cleared) when a PCM | 423 | * generated (and can't be cleared) when a PCM |
412 | * playback is going. So let's ignore at the | 424 | * playback is going. So let's ignore at the |
@@ -415,15 +427,14 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
415 | status_mask &= ~VT1724_IRQ_MPU_TX; | 427 | status_mask &= ~VT1724_IRQ_MPU_TX; |
416 | } | 428 | } |
417 | if (status & VT1724_IRQ_MPU_RX) { | 429 | if (status & VT1724_IRQ_MPU_RX) { |
418 | spin_lock(&ice->reg_lock); | ||
419 | if (ice->midi_input) | 430 | if (ice->midi_input) |
420 | vt1724_midi_read(ice); | 431 | vt1724_midi_read(ice); |
421 | else | 432 | else |
422 | vt1724_midi_clear_rx(ice); | 433 | vt1724_midi_clear_rx(ice); |
423 | spin_unlock(&ice->reg_lock); | ||
424 | } | 434 | } |
425 | /* ack MPU irq */ | 435 | /* ack MPU irq */ |
426 | outb(status, ICEREG1724(ice, IRQSTAT)); | 436 | outb(status, ICEREG1724(ice, IRQSTAT)); |
437 | spin_unlock(&ice->reg_lock); | ||
427 | if (status & VT1724_IRQ_MTPCM) { | 438 | if (status & VT1724_IRQ_MTPCM) { |
428 | /* | 439 | /* |
429 | * Multi-track PCM | 440 | * Multi-track PCM |