diff options
Diffstat (limited to 'sound/pci/ice1712/ice1724.c')
-rw-r--r-- | sound/pci/ice1712/ice1724.c | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index bb8d8c766b9d..128510e77a78 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 |
@@ -745,7 +756,14 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream) | |||
745 | 756 | ||
746 | spin_unlock_irq(&ice->reg_lock); | 757 | spin_unlock_irq(&ice->reg_lock); |
747 | 758 | ||
748 | /* printk("pro prepare: ch = %d, addr = 0x%x, buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream)); */ | 759 | /* |
760 | printk(KERN_DEBUG "pro prepare: ch = %d, addr = 0x%x, " | ||
761 | "buffer = 0x%x, period = 0x%x\n", | ||
762 | substream->runtime->channels, | ||
763 | (unsigned int)substream->runtime->dma_addr, | ||
764 | snd_pcm_lib_buffer_bytes(substream), | ||
765 | snd_pcm_lib_period_bytes(substream)); | ||
766 | */ | ||
749 | return 0; | 767 | return 0; |
750 | } | 768 | } |
751 | 769 | ||
@@ -2122,7 +2140,9 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, | |||
2122 | wait_i2c_busy(ice); | 2140 | wait_i2c_busy(ice); |
2123 | val = inb(ICEREG1724(ice, I2C_DATA)); | 2141 | val = inb(ICEREG1724(ice, I2C_DATA)); |
2124 | mutex_unlock(&ice->i2c_mutex); | 2142 | mutex_unlock(&ice->i2c_mutex); |
2125 | /* printk("i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); */ | 2143 | /* |
2144 | printk(KERN_DEBUG "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); | ||
2145 | */ | ||
2126 | return val; | 2146 | return val; |
2127 | } | 2147 | } |
2128 | 2148 | ||
@@ -2131,7 +2151,9 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice, | |||
2131 | { | 2151 | { |
2132 | mutex_lock(&ice->i2c_mutex); | 2152 | mutex_lock(&ice->i2c_mutex); |
2133 | wait_i2c_busy(ice); | 2153 | wait_i2c_busy(ice); |
2134 | /* printk("i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); */ | 2154 | /* |
2155 | printk(KERN_DEBUG "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); | ||
2156 | */ | ||
2135 | outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); | 2157 | outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); |
2136 | outb(data, ICEREG1724(ice, I2C_DATA)); | 2158 | outb(data, ICEREG1724(ice, I2C_DATA)); |
2137 | outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); | 2159 | outb(dev | VT1724_I2C_WRITE, ICEREG1724(ice, I2C_DEV_ADDR)); |
@@ -2456,9 +2478,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, | |||
2456 | return -ENOENT; | 2478 | return -ENOENT; |
2457 | } | 2479 | } |
2458 | 2480 | ||
2459 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | 2481 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); |
2460 | if (card == NULL) | 2482 | if (err < 0) |
2461 | return -ENOMEM; | 2483 | return err; |
2462 | 2484 | ||
2463 | strcpy(card->driver, "ICE1724"); | 2485 | strcpy(card->driver, "ICE1724"); |
2464 | strcpy(card->shortname, "ICEnsemble ICE1724"); | 2486 | strcpy(card->shortname, "ICEnsemble ICE1724"); |