diff options
Diffstat (limited to 'sound/pci/ice1712/ice1724.c')
-rw-r--r-- | sound/pci/ice1712/ice1724.c | 213 |
1 files changed, 167 insertions, 46 deletions
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 67350901772c..e596d777d9dd 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
33 | #include <sound/core.h> | 33 | #include <sound/core.h> |
34 | #include <sound/info.h> | 34 | #include <sound/info.h> |
35 | #include <sound/mpu401.h> | 35 | #include <sound/rawmidi.h> |
36 | #include <sound/initval.h> | 36 | #include <sound/initval.h> |
37 | 37 | ||
38 | #include <sound/asoundef.h> | 38 | #include <sound/asoundef.h> |
@@ -223,30 +223,153 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice) | |||
223 | } | 223 | } |
224 | 224 | ||
225 | /* | 225 | /* |
226 | * MPU401 accessor | 226 | * MIDI |
227 | */ | 227 | */ |
228 | static unsigned char snd_vt1724_mpu401_read(struct snd_mpu401 *mpu, | 228 | |
229 | unsigned long addr) | 229 | static void vt1724_midi_clear_rx(struct snd_ice1712 *ice) |
230 | { | ||
231 | unsigned int count; | ||
232 | |||
233 | for (count = inb(ICEREG1724(ice, MPU_RXFIFO)); count > 0; --count) | ||
234 | inb(ICEREG1724(ice, MPU_DATA)); | ||
235 | } | ||
236 | |||
237 | static inline struct snd_rawmidi_substream * | ||
238 | get_rawmidi_substream(struct snd_ice1712 *ice, unsigned int stream) | ||
230 | { | 239 | { |
231 | /* fix status bits to the standard position */ | 240 | return list_first_entry(&ice->rmidi[0]->streams[stream].substreams, |
232 | /* only RX_EMPTY and TX_FULL are checked */ | 241 | struct snd_rawmidi_substream, list); |
233 | if (addr == MPU401C(mpu)) | 242 | } |
234 | return (inb(addr) & 0x0c) << 4; | 243 | |
244 | static void vt1724_midi_write(struct snd_ice1712 *ice) | ||
245 | { | ||
246 | struct snd_rawmidi_substream *s; | ||
247 | int count, i; | ||
248 | u8 buffer[32]; | ||
249 | |||
250 | s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_OUTPUT); | ||
251 | count = 31 - inb(ICEREG1724(ice, MPU_TXFIFO)); | ||
252 | if (count > 0) { | ||
253 | count = snd_rawmidi_transmit(s, buffer, count); | ||
254 | for (i = 0; i < count; ++i) | ||
255 | outb(buffer[i], ICEREG1724(ice, MPU_DATA)); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | static void vt1724_midi_read(struct snd_ice1712 *ice) | ||
260 | { | ||
261 | struct snd_rawmidi_substream *s; | ||
262 | int count, i; | ||
263 | u8 buffer[32]; | ||
264 | |||
265 | s = get_rawmidi_substream(ice, SNDRV_RAWMIDI_STREAM_INPUT); | ||
266 | count = inb(ICEREG1724(ice, MPU_RXFIFO)); | ||
267 | if (count > 0) { | ||
268 | count = min(count, 32); | ||
269 | for (i = 0; i < count; ++i) | ||
270 | buffer[i] = inb(ICEREG1724(ice, MPU_DATA)); | ||
271 | snd_rawmidi_receive(s, buffer, count); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | static void vt1724_enable_midi_irq(struct snd_rawmidi_substream *substream, | ||
276 | u8 flag, int enable) | ||
277 | { | ||
278 | struct snd_ice1712 *ice = substream->rmidi->private_data; | ||
279 | u8 mask; | ||
280 | |||
281 | spin_lock_irq(&ice->reg_lock); | ||
282 | mask = inb(ICEREG1724(ice, IRQMASK)); | ||
283 | if (enable) | ||
284 | mask &= ~flag; | ||
235 | else | 285 | else |
236 | return inb(addr); | 286 | mask |= flag; |
287 | outb(mask, ICEREG1724(ice, IRQMASK)); | ||
288 | spin_unlock_irq(&ice->reg_lock); | ||
237 | } | 289 | } |
238 | 290 | ||
239 | static void snd_vt1724_mpu401_write(struct snd_mpu401 *mpu, | 291 | static int vt1724_midi_output_open(struct snd_rawmidi_substream *s) |
240 | unsigned char data, unsigned long addr) | ||
241 | { | 292 | { |
242 | if (addr == MPU401C(mpu)) { | 293 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 1); |
243 | if (data == MPU401_ENTER_UART) | 294 | return 0; |
244 | outb(0x01, addr); | 295 | } |
245 | /* what else? */ | 296 | |
246 | } else | 297 | static int vt1724_midi_output_close(struct snd_rawmidi_substream *s) |
247 | outb(data, addr); | 298 | { |
299 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_TX, 0); | ||
300 | return 0; | ||
248 | } | 301 | } |
249 | 302 | ||
303 | static void vt1724_midi_output_trigger(struct snd_rawmidi_substream *s, int up) | ||
304 | { | ||
305 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
306 | unsigned long flags; | ||
307 | |||
308 | spin_lock_irqsave(&ice->reg_lock, flags); | ||
309 | if (up) { | ||
310 | ice->midi_output = 1; | ||
311 | vt1724_midi_write(ice); | ||
312 | } else { | ||
313 | ice->midi_output = 0; | ||
314 | } | ||
315 | spin_unlock_irqrestore(&ice->reg_lock, flags); | ||
316 | } | ||
317 | |||
318 | static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s) | ||
319 | { | ||
320 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
321 | unsigned long timeout; | ||
322 | |||
323 | /* 32 bytes should be transmitted in less than about 12 ms */ | ||
324 | timeout = jiffies + msecs_to_jiffies(15); | ||
325 | do { | ||
326 | if (inb(ICEREG1724(ice, MPU_CTRL)) & VT1724_MPU_TX_EMPTY) | ||
327 | break; | ||
328 | schedule_timeout_uninterruptible(1); | ||
329 | } while (time_after(timeout, jiffies)); | ||
330 | } | ||
331 | |||
332 | static struct snd_rawmidi_ops vt1724_midi_output_ops = { | ||
333 | .open = vt1724_midi_output_open, | ||
334 | .close = vt1724_midi_output_close, | ||
335 | .trigger = vt1724_midi_output_trigger, | ||
336 | .drain = vt1724_midi_output_drain, | ||
337 | }; | ||
338 | |||
339 | static int vt1724_midi_input_open(struct snd_rawmidi_substream *s) | ||
340 | { | ||
341 | vt1724_midi_clear_rx(s->rmidi->private_data); | ||
342 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 1); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int vt1724_midi_input_close(struct snd_rawmidi_substream *s) | ||
347 | { | ||
348 | vt1724_enable_midi_irq(s, VT1724_IRQ_MPU_RX, 0); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up) | ||
353 | { | ||
354 | struct snd_ice1712 *ice = s->rmidi->private_data; | ||
355 | unsigned long flags; | ||
356 | |||
357 | spin_lock_irqsave(&ice->reg_lock, flags); | ||
358 | if (up) { | ||
359 | ice->midi_input = 1; | ||
360 | vt1724_midi_read(ice); | ||
361 | } else { | ||
362 | ice->midi_input = 0; | ||
363 | } | ||
364 | spin_unlock_irqrestore(&ice->reg_lock, flags); | ||
365 | } | ||
366 | |||
367 | static struct snd_rawmidi_ops vt1724_midi_input_ops = { | ||
368 | .open = vt1724_midi_input_open, | ||
369 | .close = vt1724_midi_input_close, | ||
370 | .trigger = vt1724_midi_input_trigger, | ||
371 | }; | ||
372 | |||
250 | 373 | ||
251 | /* | 374 | /* |
252 | * Interrupt handler | 375 | * Interrupt handler |
@@ -278,13 +401,10 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
278 | #endif | 401 | #endif |
279 | handled = 1; | 402 | handled = 1; |
280 | if (status & VT1724_IRQ_MPU_TX) { | 403 | if (status & VT1724_IRQ_MPU_TX) { |
281 | if (ice->rmidi[0]) | 404 | spin_lock(&ice->reg_lock); |
282 | snd_mpu401_uart_interrupt_tx(irq, | 405 | if (ice->midi_output) |
283 | ice->rmidi[0]->private_data); | 406 | vt1724_midi_write(ice); |
284 | else /* disable TX to be sure */ | 407 | spin_unlock(&ice->reg_lock); |
285 | outb(inb(ICEREG1724(ice, IRQMASK)) | | ||
286 | VT1724_IRQ_MPU_TX, | ||
287 | ICEREG1724(ice, IRQMASK)); | ||
288 | /* Due to mysterical reasons, MPU_TX is always | 408 | /* Due to mysterical reasons, MPU_TX is always |
289 | * generated (and can't be cleared) when a PCM | 409 | * generated (and can't be cleared) when a PCM |
290 | * playback is going. So let's ignore at the | 410 | * playback is going. So let's ignore at the |
@@ -293,13 +413,12 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) | |||
293 | status_mask &= ~VT1724_IRQ_MPU_TX; | 413 | status_mask &= ~VT1724_IRQ_MPU_TX; |
294 | } | 414 | } |
295 | if (status & VT1724_IRQ_MPU_RX) { | 415 | if (status & VT1724_IRQ_MPU_RX) { |
296 | if (ice->rmidi[0]) | 416 | spin_lock(&ice->reg_lock); |
297 | snd_mpu401_uart_interrupt(irq, | 417 | if (ice->midi_input) |
298 | ice->rmidi[0]->private_data); | 418 | vt1724_midi_read(ice); |
299 | else /* disable RX to be sure */ | 419 | else |
300 | outb(inb(ICEREG1724(ice, IRQMASK)) | | 420 | vt1724_midi_clear_rx(ice); |
301 | VT1724_IRQ_MPU_RX, | 421 | spin_unlock(&ice->reg_lock); |
302 | ICEREG1724(ice, IRQMASK)); | ||
303 | } | 422 | } |
304 | /* ack MPU irq */ | 423 | /* ack MPU irq */ |
305 | outb(status, ICEREG1724(ice, IRQSTAT)); | 424 | outb(status, ICEREG1724(ice, IRQSTAT)); |
@@ -2425,28 +2544,30 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, | |||
2425 | 2544 | ||
2426 | if (! c->no_mpu401) { | 2545 | if (! c->no_mpu401) { |
2427 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { | 2546 | if (ice->eeprom.data[ICE_EEP2_SYSCONF] & VT1724_CFG_MPU401) { |
2428 | struct snd_mpu401 *mpu; | 2547 | struct snd_rawmidi *rmidi; |
2429 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712, | 2548 | |
2430 | ICEREG1724(ice, MPU_CTRL), | 2549 | err = snd_rawmidi_new(card, "MIDI", 0, 1, 1, &rmidi); |
2431 | (MPU401_INFO_INTEGRATED | | 2550 | if (err < 0) { |
2432 | MPU401_INFO_NO_ACK | | ||
2433 | MPU401_INFO_TX_IRQ), | ||
2434 | ice->irq, 0, | ||
2435 | &ice->rmidi[0])) < 0) { | ||
2436 | snd_card_free(card); | 2551 | snd_card_free(card); |
2437 | return err; | 2552 | return err; |
2438 | } | 2553 | } |
2439 | mpu = ice->rmidi[0]->private_data; | 2554 | ice->rmidi[0] = rmidi; |
2440 | mpu->read = snd_vt1724_mpu401_read; | 2555 | rmidi->private_data = ice; |
2441 | mpu->write = snd_vt1724_mpu401_write; | 2556 | strcpy(rmidi->name, "ICE1724 MIDI"); |
2442 | /* unmask MPU RX/TX irqs */ | 2557 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | |
2443 | outb(inb(ICEREG1724(ice, IRQMASK)) & | 2558 | SNDRV_RAWMIDI_INFO_INPUT | |
2444 | ~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX), | 2559 | SNDRV_RAWMIDI_INFO_DUPLEX; |
2445 | ICEREG1724(ice, IRQMASK)); | 2560 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, |
2561 | &vt1724_midi_output_ops); | ||
2562 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
2563 | &vt1724_midi_input_ops); | ||
2564 | |||
2446 | /* set watermarks */ | 2565 | /* set watermarks */ |
2447 | outb(VT1724_MPU_RX_FIFO | 0x1, | 2566 | outb(VT1724_MPU_RX_FIFO | 0x1, |
2448 | ICEREG1724(ice, MPU_FIFO_WM)); | 2567 | ICEREG1724(ice, MPU_FIFO_WM)); |
2449 | outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); | 2568 | outb(0x1, ICEREG1724(ice, MPU_FIFO_WM)); |
2569 | /* set UART mode */ | ||
2570 | outb(VT1724_MPU_UART, ICEREG1724(ice, MPU_CTRL)); | ||
2450 | } | 2571 | } |
2451 | } | 2572 | } |
2452 | 2573 | ||