[ALSA] snd-ca0106: Add midi support.

Modules: PCI drivers,CA0106 driver

Author: Tilman Kranz <tilde@tk-sls.de>

Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index f6920ef..aaaef9e 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -338,6 +338,18 @@
 	spin_unlock_irqrestore(&emu->emu_lock, flags);
 }
 
+static void snd_ca0106_intr_disable(ca0106_t *emu, unsigned int intrenb)
+{
+	unsigned long flags;
+	unsigned int enable;
+  
+	spin_lock_irqsave(&emu->emu_lock, flags);
+	enable = inl(emu->port + INTE) & ~intrenb;
+	outl(enable, emu->port + INTE);
+	spin_unlock_irqrestore(&emu->emu_lock, flags);
+}
+
+
 static void snd_ca0106_pcm_free_substream(snd_pcm_runtime_t *runtime)
 {
 	kfree(runtime->private_data);
@@ -1040,6 +1052,15 @@
 
         snd_ca0106_ptr_write(chip, EXTENDED_INT, 0, stat76);
 	spin_lock(&chip->emu_lock);
+
+	if (chip->midi.dev_id &&
+	  (status & (chip->midi.ipr_tx|chip->midi.ipr_rx))) {
+		if (chip->midi.interrupt)
+			chip->midi.interrupt(&chip->midi, status);
+		else
+			chip->midi.interrupt_disable(&chip->midi, chip->midi.tx_enable | chip->midi.rx_enable);
+	}
+
 	// acknowledge the interrupt if necessary
 	outl(status, chip->port+IPR);
 
@@ -1309,6 +1330,82 @@
 	return 0;
 }
 
+
+void ca0106_midi_interrupt_enable(ca_midi_t *midi, int intr){
+	snd_ca0106_intr_enable((ca0106_t *)(midi->dev_id), intr);
+}
+
+void ca0106_midi_interrupt_disable(ca_midi_t *midi, int intr){
+	snd_ca0106_intr_disable((ca0106_t *)(midi->dev_id), intr);
+}
+
+unsigned char ca0106_midi_read(ca_midi_t *midi, int idx){
+	return (unsigned char)snd_ca0106_ptr_read((ca0106_t *)(midi->dev_id), midi->port + idx, 0);
+}
+
+void ca0106_midi_write(ca_midi_t *midi, int data, int idx){
+	snd_ca0106_ptr_write((ca0106_t *)(midi->dev_id), midi->port + idx, 0, data);
+}
+
+snd_card_t *ca0106_dev_id_card(void *dev_id){
+	return ((ca0106_t *)dev_id)->card;
+}
+
+int ca0106_dev_id_port(void *dev_id){
+	return ((ca0106_t *)dev_id)->port;
+}
+
+static int __devinit snd_ca0106_midi(ca0106_t *chip, unsigned int channel)
+{
+	ca_midi_t *midi;
+	char *name;
+	int err;
+
+        if(channel==CA0106_MIDI_CHAN_B) {
+		name = "CA0106 MPU-401 (UART) B";
+		midi =  &chip->midi2;
+		midi->tx_enable = INTE_MIDI_TX_B;
+		midi->rx_enable = INTE_MIDI_RX_B;
+		midi->ipr_tx = IPR_MIDI_TX_B;
+		midi->ipr_rx = IPR_MIDI_RX_B;
+		midi->port = MIDI_UART_B_DATA;
+	} else {
+		name = "CA0106 MPU-401 (UART)";
+		midi =  &chip->midi;
+		midi->tx_enable = INTE_MIDI_TX_A;
+		midi->rx_enable = INTE_MIDI_TX_B;
+		midi->ipr_tx = IPR_MIDI_TX_A;
+		midi->ipr_rx = IPR_MIDI_RX_A;
+		midi->port = MIDI_UART_A_DATA;
+	}
+
+	midi->reset = CA0106_MPU401_RESET;
+	midi->enter_uart = CA0106_MPU401_ENTER_UART;
+	midi->ack = CA0106_MPU401_ACK;
+
+	midi->input_avail = CA0106_MIDI_INPUT_AVAIL;
+	midi->output_ready = CA0106_MIDI_OUTPUT_READY;
+
+	midi->channel = channel;
+
+	midi->interrupt_enable = ca0106_midi_interrupt_enable;
+	midi->interrupt_disable = ca0106_midi_interrupt_disable;
+
+	midi->read = ca0106_midi_read;
+	midi->write = ca0106_midi_write;
+
+	midi->get_dev_id_card = ca0106_dev_id_card;
+	midi->get_dev_id_port = ca0106_dev_id_port;
+
+	midi->dev_id = chip;
+	
+	if ((err = ca_midi_init(chip, midi, 0, name)) < 0)
+		return err;
+
+	return 0;
+}
+
+
 static int __devinit snd_ca0106_probe(struct pci_dev *pci,
 					const struct pci_device_id *pci_id)
 {
@@ -1360,6 +1457,20 @@
 		return err;
 	}
 
+#ifdef CONFIG_SND_DEBUG_DETECT
+	printk("ca0106: probe for MIDI channel A ...");
+#endif
+	if ((err = snd_ca0106_midi(chip,CA0106_MIDI_CHAN_A)) < 0) {
+		snd_card_free(card);
+#ifdef CONFIG_SND_DEBUG_DETECT
+		printk(" failed, err=0x%x\n",err);
+#endif
+		return err;
+	}
+#ifdef CONFIG_SND_DEBUG_DETECT
+	printk(" done.\n");
+#endif
+
 	snd_ca0106_proc_init(chip);
 
 	if ((err = snd_card_register(card)) < 0) {