diff options
Diffstat (limited to 'sound/drivers')
-rw-r--r-- | sound/drivers/mpu401/mpu401_uart.c | 96 |
1 files changed, 68 insertions, 28 deletions
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index cd64d3eb9ec8..4bf07ca9b17d 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c | |||
@@ -95,17 +95,8 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu) | |||
95 | #endif | 95 | #endif |
96 | } | 96 | } |
97 | 97 | ||
98 | static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | 98 | static void uart_interrupt_tx(struct snd_mpu401 *mpu) |
99 | { | 99 | { |
100 | spin_lock(&mpu->input_lock); | ||
101 | if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) | ||
102 | snd_mpu401_uart_input_read(mpu); | ||
103 | else | ||
104 | snd_mpu401_uart_clear_rx(mpu); | ||
105 | spin_unlock(&mpu->input_lock); | ||
106 | /* ok. for better Tx performance try do some output when | ||
107 | * input is done | ||
108 | */ | ||
109 | if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && | 100 | if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && |
110 | test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { | 101 | test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { |
111 | spin_lock(&mpu->output_lock); | 102 | spin_lock(&mpu->output_lock); |
@@ -114,6 +105,22 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | |||
114 | } | 105 | } |
115 | } | 106 | } |
116 | 107 | ||
108 | static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu) | ||
109 | { | ||
110 | if (mpu->info_flags & MPU401_INFO_INPUT) { | ||
111 | spin_lock(&mpu->input_lock); | ||
112 | if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) | ||
113 | snd_mpu401_uart_input_read(mpu); | ||
114 | else | ||
115 | snd_mpu401_uart_clear_rx(mpu); | ||
116 | spin_unlock(&mpu->input_lock); | ||
117 | } | ||
118 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) | ||
119 | /* ok. for better Tx performance try do some output | ||
120 | when input is done */ | ||
121 | uart_interrupt_tx(mpu); | ||
122 | } | ||
123 | |||
117 | /** | 124 | /** |
118 | * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler | 125 | * snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler |
119 | * @irq: the irq number | 126 | * @irq: the irq number |
@@ -135,6 +142,27 @@ irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id, | |||
135 | 142 | ||
136 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt); | 143 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt); |
137 | 144 | ||
145 | /** | ||
146 | * snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler | ||
147 | * @irq: the irq number | ||
148 | * @dev_id: mpu401 instance | ||
149 | * @regs: the reigster | ||
150 | * | ||
151 | * Processes the interrupt for MPU401-UART output. | ||
152 | */ | ||
153 | irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id, | ||
154 | struct pt_regs *regs) | ||
155 | { | ||
156 | struct snd_mpu401 *mpu = dev_id; | ||
157 | |||
158 | if (mpu == NULL) | ||
159 | return IRQ_NONE; | ||
160 | uart_interrupt_tx(mpu); | ||
161 | return IRQ_HANDLED; | ||
162 | } | ||
163 | |||
164 | EXPORT_SYMBOL(snd_mpu401_uart_interrupt_tx); | ||
165 | |||
138 | /* | 166 | /* |
139 | * timer callback | 167 | * timer callback |
140 | * reprogram the timer and call the interrupt job | 168 | * reprogram the timer and call the interrupt job |
@@ -430,14 +458,16 @@ snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up) | |||
430 | * since the output timer might have been removed in | 458 | * since the output timer might have been removed in |
431 | * snd_mpu401_uart_output_write(). | 459 | * snd_mpu401_uart_output_write(). |
432 | */ | 460 | */ |
433 | snd_mpu401_uart_add_timer(mpu, 0); | 461 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) |
462 | snd_mpu401_uart_add_timer(mpu, 0); | ||
434 | 463 | ||
435 | /* output pending data */ | 464 | /* output pending data */ |
436 | spin_lock_irqsave(&mpu->output_lock, flags); | 465 | spin_lock_irqsave(&mpu->output_lock, flags); |
437 | snd_mpu401_uart_output_write(mpu); | 466 | snd_mpu401_uart_output_write(mpu); |
438 | spin_unlock_irqrestore(&mpu->output_lock, flags); | 467 | spin_unlock_irqrestore(&mpu->output_lock, flags); |
439 | } else { | 468 | } else { |
440 | snd_mpu401_uart_remove_timer(mpu, 0); | 469 | if (! (mpu->info_flags & MPU401_INFO_TX_IRQ)) |
470 | snd_mpu401_uart_remove_timer(mpu, 0); | ||
441 | clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); | 471 | clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); |
442 | } | 472 | } |
443 | } | 473 | } |
@@ -475,7 +505,7 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) | |||
475 | * @device: the device index, zero-based | 505 | * @device: the device index, zero-based |
476 | * @hardware: the hardware type, MPU401_HW_XXXX | 506 | * @hardware: the hardware type, MPU401_HW_XXXX |
477 | * @port: the base address of MPU401 port | 507 | * @port: the base address of MPU401 port |
478 | * @integrated: non-zero if the port was already reserved by the chip | 508 | * @info_flags: bitflags MPU401_INFO_XXX |
479 | * @irq: the irq number, -1 if no interrupt for mpu | 509 | * @irq: the irq number, -1 if no interrupt for mpu |
480 | * @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved. | 510 | * @irq_flags: the irq request flags (SA_XXX), 0 if irq was already reserved. |
481 | * @rrawmidi: the pointer to store the new rawmidi instance | 511 | * @rrawmidi: the pointer to store the new rawmidi instance |
@@ -490,17 +520,24 @@ static void snd_mpu401_uart_free(struct snd_rawmidi *rmidi) | |||
490 | */ | 520 | */ |
491 | int snd_mpu401_uart_new(struct snd_card *card, int device, | 521 | int snd_mpu401_uart_new(struct snd_card *card, int device, |
492 | unsigned short hardware, | 522 | unsigned short hardware, |
493 | unsigned long port, int integrated, | 523 | unsigned long port, |
524 | unsigned int info_flags, | ||
494 | int irq, int irq_flags, | 525 | int irq, int irq_flags, |
495 | struct snd_rawmidi ** rrawmidi) | 526 | struct snd_rawmidi ** rrawmidi) |
496 | { | 527 | { |
497 | struct snd_mpu401 *mpu; | 528 | struct snd_mpu401 *mpu; |
498 | struct snd_rawmidi *rmidi; | 529 | struct snd_rawmidi *rmidi; |
530 | int in_enable, out_enable; | ||
499 | int err; | 531 | int err; |
500 | 532 | ||
501 | if (rrawmidi) | 533 | if (rrawmidi) |
502 | *rrawmidi = NULL; | 534 | *rrawmidi = NULL; |
503 | if ((err = snd_rawmidi_new(card, "MPU-401U", device, 1, 1, &rmidi)) < 0) | 535 | if (! (info_flags & (MPU401_INFO_INPUT | MPU401_INFO_OUTPUT))) |
536 | info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT; | ||
537 | in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0; | ||
538 | out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0; | ||
539 | if ((err = snd_rawmidi_new(card, "MPU-401U", device, | ||
540 | out_enable, in_enable, &rmidi)) < 0) | ||
504 | return err; | 541 | return err; |
505 | mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); | 542 | mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); |
506 | if (mpu == NULL) { | 543 | if (mpu == NULL) { |
@@ -514,7 +551,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
514 | spin_lock_init(&mpu->output_lock); | 551 | spin_lock_init(&mpu->output_lock); |
515 | spin_lock_init(&mpu->timer_lock); | 552 | spin_lock_init(&mpu->timer_lock); |
516 | mpu->hardware = hardware; | 553 | mpu->hardware = hardware; |
517 | if (!integrated) { | 554 | if (! (info_flags & MPU401_INFO_INTEGRATED)) { |
518 | int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; | 555 | int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; |
519 | mpu->res = request_region(port, res_size, "MPU401 UART"); | 556 | mpu->res = request_region(port, res_size, "MPU401 UART"); |
520 | if (mpu->res == NULL) { | 557 | if (mpu->res == NULL) { |
@@ -525,15 +562,12 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
525 | return -EBUSY; | 562 | return -EBUSY; |
526 | } | 563 | } |
527 | } | 564 | } |
528 | switch (hardware) { | 565 | if (info_flags & MPU401_INFO_MMIO) { |
529 | case MPU401_HW_AUREAL: | ||
530 | mpu->write = mpu401_write_mmio; | 566 | mpu->write = mpu401_write_mmio; |
531 | mpu->read = mpu401_read_mmio; | 567 | mpu->read = mpu401_read_mmio; |
532 | break; | 568 | } else { |
533 | default: | ||
534 | mpu->write = mpu401_write_port; | 569 | mpu->write = mpu401_write_port; |
535 | mpu->read = mpu401_read_port; | 570 | mpu->read = mpu401_read_port; |
536 | break; | ||
537 | } | 571 | } |
538 | mpu->port = port; | 572 | mpu->port = port; |
539 | if (hardware == MPU401_HW_PC98II) | 573 | if (hardware == MPU401_HW_PC98II) |
@@ -549,6 +583,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
549 | return -EBUSY; | 583 | return -EBUSY; |
550 | } | 584 | } |
551 | } | 585 | } |
586 | mpu->info_flags = info_flags; | ||
552 | mpu->irq = irq; | 587 | mpu->irq = irq; |
553 | mpu->irq_flags = irq_flags; | 588 | mpu->irq_flags = irq_flags; |
554 | if (card->shortname[0]) | 589 | if (card->shortname[0]) |
@@ -556,13 +591,18 @@ int snd_mpu401_uart_new(struct snd_card *card, int device, | |||
556 | card->shortname); | 591 | card->shortname); |
557 | else | 592 | else |
558 | sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device); | 593 | sprintf(rmidi->name, "MPU-401 MIDI %d-%d",card->number, device); |
559 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | 594 | if (out_enable) { |
560 | &snd_mpu401_uart_output); | 595 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, |
561 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | 596 | &snd_mpu401_uart_output); |
562 | &snd_mpu401_uart_input); | 597 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; |
563 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | | 598 | } |
564 | SNDRV_RAWMIDI_INFO_INPUT | | 599 | if (in_enable) { |
565 | SNDRV_RAWMIDI_INFO_DUPLEX; | 600 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, |
601 | &snd_mpu401_uart_input); | ||
602 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | ||
603 | if (out_enable) | ||
604 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | ||
605 | } | ||
566 | mpu->rmidi = rmidi; | 606 | mpu->rmidi = rmidi; |
567 | if (rrawmidi) | 607 | if (rrawmidi) |
568 | *rrawmidi = rmidi; | 608 | *rrawmidi = rmidi; |