162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
462306a36Sopenharmony_ci *  Routines for control of EMU10K1 MPU-401 in UART mode
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/time.h>
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <sound/core.h>
1062306a36Sopenharmony_ci#include <sound/emu10k1.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define EMU10K1_MIDI_MODE_INPUT		(1<<0)
1362306a36Sopenharmony_ci#define EMU10K1_MIDI_MODE_OUTPUT	(1<<1)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic inline unsigned char mpu401_read(struct snd_emu10k1 *emu,
1662306a36Sopenharmony_ci					struct snd_emu10k1_midi *mpu, int idx)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	if (emu->audigy)
1962306a36Sopenharmony_ci		return (unsigned char)snd_emu10k1_ptr_read(emu, mpu->port + idx, 0);
2062306a36Sopenharmony_ci	else
2162306a36Sopenharmony_ci		return inb(emu->port + mpu->port + idx);
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic inline void mpu401_write(struct snd_emu10k1 *emu,
2562306a36Sopenharmony_ci				struct snd_emu10k1_midi *mpu, int data, int idx)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	if (emu->audigy)
2862306a36Sopenharmony_ci		snd_emu10k1_ptr_write(emu, mpu->port + idx, 0, data);
2962306a36Sopenharmony_ci	else
3062306a36Sopenharmony_ci		outb(data, emu->port + mpu->port + idx);
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define mpu401_write_data(emu, mpu, data)	mpu401_write(emu, mpu, data, 0)
3462306a36Sopenharmony_ci#define mpu401_write_cmd(emu, mpu, data)	mpu401_write(emu, mpu, data, 1)
3562306a36Sopenharmony_ci#define mpu401_read_data(emu, mpu)		mpu401_read(emu, mpu, 0)
3662306a36Sopenharmony_ci#define mpu401_read_stat(emu, mpu)		mpu401_read(emu, mpu, 1)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define mpu401_input_avail(emu,mpu)	(!(mpu401_read_stat(emu,mpu) & 0x80))
3962306a36Sopenharmony_ci#define mpu401_output_ready(emu,mpu)	(!(mpu401_read_stat(emu,mpu) & 0x40))
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define MPU401_RESET		0xff
4262306a36Sopenharmony_ci#define MPU401_ENTER_UART	0x3f
4362306a36Sopenharmony_ci#define MPU401_ACK		0xfe
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic void mpu401_clear_rx(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *mpu)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	int timeout = 100000;
4862306a36Sopenharmony_ci	for (; timeout > 0 && mpu401_input_avail(emu, mpu); timeout--)
4962306a36Sopenharmony_ci		mpu401_read_data(emu, mpu);
5062306a36Sopenharmony_ci#ifdef CONFIG_SND_DEBUG
5162306a36Sopenharmony_ci	if (timeout <= 0)
5262306a36Sopenharmony_ci		dev_err(emu->card->dev,
5362306a36Sopenharmony_ci			"cmd: clear rx timeout (status = 0x%x)\n",
5462306a36Sopenharmony_ci			mpu401_read_stat(emu, mpu));
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/*
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void do_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, unsigned int status)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	unsigned char byte;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (midi->rmidi == NULL) {
6762306a36Sopenharmony_ci		snd_emu10k1_intr_disable(emu, midi->tx_enable | midi->rx_enable);
6862306a36Sopenharmony_ci		return;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	spin_lock(&midi->input_lock);
7262306a36Sopenharmony_ci	if ((status & midi->ipr_rx) && mpu401_input_avail(emu, midi)) {
7362306a36Sopenharmony_ci		if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
7462306a36Sopenharmony_ci			mpu401_clear_rx(emu, midi);
7562306a36Sopenharmony_ci		} else {
7662306a36Sopenharmony_ci			byte = mpu401_read_data(emu, midi);
7762306a36Sopenharmony_ci			if (midi->substream_input)
7862306a36Sopenharmony_ci				snd_rawmidi_receive(midi->substream_input, &byte, 1);
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci	spin_unlock(&midi->input_lock);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	spin_lock(&midi->output_lock);
8462306a36Sopenharmony_ci	if ((status & midi->ipr_tx) && mpu401_output_ready(emu, midi)) {
8562306a36Sopenharmony_ci		if (midi->substream_output &&
8662306a36Sopenharmony_ci		    snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
8762306a36Sopenharmony_ci			mpu401_write_data(emu, midi, byte);
8862306a36Sopenharmony_ci		} else {
8962306a36Sopenharmony_ci			snd_emu10k1_intr_disable(emu, midi->tx_enable);
9062306a36Sopenharmony_ci		}
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci	spin_unlock(&midi->output_lock);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic void snd_emu10k1_midi_interrupt(struct snd_emu10k1 *emu, unsigned int status)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	do_emu10k1_midi_interrupt(emu, &emu->midi, status);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic void snd_emu10k1_midi_interrupt2(struct snd_emu10k1 *emu, unsigned int status)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	do_emu10k1_midi_interrupt(emu, &emu->midi2, status);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_midi *midi, unsigned char cmd, int ack)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	int timeout, ok;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	spin_lock_irq(&midi->input_lock);
11062306a36Sopenharmony_ci	mpu401_write_data(emu, midi, 0x00);
11162306a36Sopenharmony_ci	/* mpu401_clear_rx(emu, midi); */
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	mpu401_write_cmd(emu, midi, cmd);
11462306a36Sopenharmony_ci	if (ack) {
11562306a36Sopenharmony_ci		ok = 0;
11662306a36Sopenharmony_ci		timeout = 10000;
11762306a36Sopenharmony_ci		while (!ok && timeout-- > 0) {
11862306a36Sopenharmony_ci			if (mpu401_input_avail(emu, midi)) {
11962306a36Sopenharmony_ci				if (mpu401_read_data(emu, midi) == MPU401_ACK)
12062306a36Sopenharmony_ci					ok = 1;
12162306a36Sopenharmony_ci			}
12262306a36Sopenharmony_ci		}
12362306a36Sopenharmony_ci		if (!ok && mpu401_read_data(emu, midi) == MPU401_ACK)
12462306a36Sopenharmony_ci			ok = 1;
12562306a36Sopenharmony_ci	} else {
12662306a36Sopenharmony_ci		ok = 1;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci	spin_unlock_irq(&midi->input_lock);
12962306a36Sopenharmony_ci	if (!ok) {
13062306a36Sopenharmony_ci		dev_err(emu->card->dev,
13162306a36Sopenharmony_ci			"midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n",
13262306a36Sopenharmony_ci			   cmd, emu->port,
13362306a36Sopenharmony_ci			   mpu401_read_stat(emu, midi),
13462306a36Sopenharmony_ci			   mpu401_read_data(emu, midi));
13562306a36Sopenharmony_ci		return 1;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci	return 0;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic int snd_emu10k1_midi_input_open(struct snd_rawmidi_substream *substream)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct snd_emu10k1 *emu;
14362306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	emu = midi->emu;
14662306a36Sopenharmony_ci	if (snd_BUG_ON(!emu))
14762306a36Sopenharmony_ci		return -ENXIO;
14862306a36Sopenharmony_ci	spin_lock_irq(&midi->open_lock);
14962306a36Sopenharmony_ci	midi->midi_mode |= EMU10K1_MIDI_MODE_INPUT;
15062306a36Sopenharmony_ci	midi->substream_input = substream;
15162306a36Sopenharmony_ci	if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
15262306a36Sopenharmony_ci		spin_unlock_irq(&midi->open_lock);
15362306a36Sopenharmony_ci		if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
15462306a36Sopenharmony_ci			goto error_out;
15562306a36Sopenharmony_ci		if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
15662306a36Sopenharmony_ci			goto error_out;
15762306a36Sopenharmony_ci	} else {
15862306a36Sopenharmony_ci		spin_unlock_irq(&midi->open_lock);
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci	return 0;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cierror_out:
16362306a36Sopenharmony_ci	return -EIO;
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic int snd_emu10k1_midi_output_open(struct snd_rawmidi_substream *substream)
16762306a36Sopenharmony_ci{
16862306a36Sopenharmony_ci	struct snd_emu10k1 *emu;
16962306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	emu = midi->emu;
17262306a36Sopenharmony_ci	if (snd_BUG_ON(!emu))
17362306a36Sopenharmony_ci		return -ENXIO;
17462306a36Sopenharmony_ci	spin_lock_irq(&midi->open_lock);
17562306a36Sopenharmony_ci	midi->midi_mode |= EMU10K1_MIDI_MODE_OUTPUT;
17662306a36Sopenharmony_ci	midi->substream_output = substream;
17762306a36Sopenharmony_ci	if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
17862306a36Sopenharmony_ci		spin_unlock_irq(&midi->open_lock);
17962306a36Sopenharmony_ci		if (snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 1))
18062306a36Sopenharmony_ci			goto error_out;
18162306a36Sopenharmony_ci		if (snd_emu10k1_midi_cmd(emu, midi, MPU401_ENTER_UART, 1))
18262306a36Sopenharmony_ci			goto error_out;
18362306a36Sopenharmony_ci	} else {
18462306a36Sopenharmony_ci		spin_unlock_irq(&midi->open_lock);
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cierror_out:
18962306a36Sopenharmony_ci	return -EIO;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int snd_emu10k1_midi_input_close(struct snd_rawmidi_substream *substream)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct snd_emu10k1 *emu;
19562306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
19662306a36Sopenharmony_ci	int err = 0;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	emu = midi->emu;
19962306a36Sopenharmony_ci	if (snd_BUG_ON(!emu))
20062306a36Sopenharmony_ci		return -ENXIO;
20162306a36Sopenharmony_ci	spin_lock_irq(&midi->open_lock);
20262306a36Sopenharmony_ci	snd_emu10k1_intr_disable(emu, midi->rx_enable);
20362306a36Sopenharmony_ci	midi->midi_mode &= ~EMU10K1_MIDI_MODE_INPUT;
20462306a36Sopenharmony_ci	midi->substream_input = NULL;
20562306a36Sopenharmony_ci	if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT)) {
20662306a36Sopenharmony_ci		spin_unlock_irq(&midi->open_lock);
20762306a36Sopenharmony_ci		err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
20862306a36Sopenharmony_ci	} else {
20962306a36Sopenharmony_ci		spin_unlock_irq(&midi->open_lock);
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	return err;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic int snd_emu10k1_midi_output_close(struct snd_rawmidi_substream *substream)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct snd_emu10k1 *emu;
21762306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
21862306a36Sopenharmony_ci	int err = 0;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	emu = midi->emu;
22162306a36Sopenharmony_ci	if (snd_BUG_ON(!emu))
22262306a36Sopenharmony_ci		return -ENXIO;
22362306a36Sopenharmony_ci	spin_lock_irq(&midi->open_lock);
22462306a36Sopenharmony_ci	snd_emu10k1_intr_disable(emu, midi->tx_enable);
22562306a36Sopenharmony_ci	midi->midi_mode &= ~EMU10K1_MIDI_MODE_OUTPUT;
22662306a36Sopenharmony_ci	midi->substream_output = NULL;
22762306a36Sopenharmony_ci	if (!(midi->midi_mode & EMU10K1_MIDI_MODE_INPUT)) {
22862306a36Sopenharmony_ci		spin_unlock_irq(&midi->open_lock);
22962306a36Sopenharmony_ci		err = snd_emu10k1_midi_cmd(emu, midi, MPU401_RESET, 0);
23062306a36Sopenharmony_ci	} else {
23162306a36Sopenharmony_ci		spin_unlock_irq(&midi->open_lock);
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	return err;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void snd_emu10k1_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct snd_emu10k1 *emu;
23962306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
24062306a36Sopenharmony_ci	emu = midi->emu;
24162306a36Sopenharmony_ci	if (snd_BUG_ON(!emu))
24262306a36Sopenharmony_ci		return;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (up)
24562306a36Sopenharmony_ci		snd_emu10k1_intr_enable(emu, midi->rx_enable);
24662306a36Sopenharmony_ci	else
24762306a36Sopenharmony_ci		snd_emu10k1_intr_disable(emu, midi->rx_enable);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct snd_emu10k1 *emu;
25362306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi = (struct snd_emu10k1_midi *)substream->rmidi->private_data;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	emu = midi->emu;
25662306a36Sopenharmony_ci	if (snd_BUG_ON(!emu))
25762306a36Sopenharmony_ci		return;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (up) {
26062306a36Sopenharmony_ci		int max = 4;
26162306a36Sopenharmony_ci		unsigned char byte;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		/* try to send some amount of bytes here before interrupts */
26462306a36Sopenharmony_ci		spin_lock_irq(&midi->output_lock);
26562306a36Sopenharmony_ci		while (max > 0) {
26662306a36Sopenharmony_ci			if (mpu401_output_ready(emu, midi)) {
26762306a36Sopenharmony_ci				if (!(midi->midi_mode & EMU10K1_MIDI_MODE_OUTPUT) ||
26862306a36Sopenharmony_ci				    snd_rawmidi_transmit(substream, &byte, 1) != 1) {
26962306a36Sopenharmony_ci					/* no more data */
27062306a36Sopenharmony_ci					spin_unlock_irq(&midi->output_lock);
27162306a36Sopenharmony_ci					return;
27262306a36Sopenharmony_ci				}
27362306a36Sopenharmony_ci				mpu401_write_data(emu, midi, byte);
27462306a36Sopenharmony_ci				max--;
27562306a36Sopenharmony_ci			} else {
27662306a36Sopenharmony_ci				break;
27762306a36Sopenharmony_ci			}
27862306a36Sopenharmony_ci		}
27962306a36Sopenharmony_ci		spin_unlock_irq(&midi->output_lock);
28062306a36Sopenharmony_ci		snd_emu10k1_intr_enable(emu, midi->tx_enable);
28162306a36Sopenharmony_ci	} else {
28262306a36Sopenharmony_ci		snd_emu10k1_intr_disable(emu, midi->tx_enable);
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci/*
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci */
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_emu10k1_midi_output =
29162306a36Sopenharmony_ci{
29262306a36Sopenharmony_ci	.open =		snd_emu10k1_midi_output_open,
29362306a36Sopenharmony_ci	.close =	snd_emu10k1_midi_output_close,
29462306a36Sopenharmony_ci	.trigger =	snd_emu10k1_midi_output_trigger,
29562306a36Sopenharmony_ci};
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_emu10k1_midi_input =
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	.open =		snd_emu10k1_midi_input_open,
30062306a36Sopenharmony_ci	.close =	snd_emu10k1_midi_input_close,
30162306a36Sopenharmony_ci	.trigger =	snd_emu10k1_midi_input_trigger,
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi = rmidi->private_data;
30762306a36Sopenharmony_ci	midi->interrupt = NULL;
30862306a36Sopenharmony_ci	midi->rmidi = NULL;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct snd_rawmidi *rmidi;
31462306a36Sopenharmony_ci	int err;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	err = snd_rawmidi_new(emu->card, name, device, 1, 1, &rmidi);
31762306a36Sopenharmony_ci	if (err < 0)
31862306a36Sopenharmony_ci		return err;
31962306a36Sopenharmony_ci	midi->emu = emu;
32062306a36Sopenharmony_ci	spin_lock_init(&midi->open_lock);
32162306a36Sopenharmony_ci	spin_lock_init(&midi->input_lock);
32262306a36Sopenharmony_ci	spin_lock_init(&midi->output_lock);
32362306a36Sopenharmony_ci	strcpy(rmidi->name, name);
32462306a36Sopenharmony_ci	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_emu10k1_midi_output);
32562306a36Sopenharmony_ci	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_emu10k1_midi_input);
32662306a36Sopenharmony_ci	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
32762306a36Sopenharmony_ci	                     SNDRV_RAWMIDI_INFO_INPUT |
32862306a36Sopenharmony_ci	                     SNDRV_RAWMIDI_INFO_DUPLEX;
32962306a36Sopenharmony_ci	rmidi->private_data = midi;
33062306a36Sopenharmony_ci	rmidi->private_free = snd_emu10k1_midi_free;
33162306a36Sopenharmony_ci	midi->rmidi = rmidi;
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciint snd_emu10k1_midi(struct snd_emu10k1 *emu)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi = &emu->midi;
33862306a36Sopenharmony_ci	int err;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	err = emu10k1_midi_init(emu, midi, 0, "EMU10K1 MPU-401 (UART)");
34162306a36Sopenharmony_ci	if (err < 0)
34262306a36Sopenharmony_ci		return err;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	midi->tx_enable = INTE_MIDITXENABLE;
34562306a36Sopenharmony_ci	midi->rx_enable = INTE_MIDIRXENABLE;
34662306a36Sopenharmony_ci	midi->port = MUDATA;
34762306a36Sopenharmony_ci	midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
34862306a36Sopenharmony_ci	midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
34962306a36Sopenharmony_ci	midi->interrupt = snd_emu10k1_midi_interrupt;
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ciint snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct snd_emu10k1_midi *midi;
35662306a36Sopenharmony_ci	int err;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	midi = &emu->midi;
35962306a36Sopenharmony_ci	err = emu10k1_midi_init(emu, midi, 0, "Audigy MPU-401 (UART)");
36062306a36Sopenharmony_ci	if (err < 0)
36162306a36Sopenharmony_ci		return err;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	midi->tx_enable = INTE_MIDITXENABLE;
36462306a36Sopenharmony_ci	midi->rx_enable = INTE_MIDIRXENABLE;
36562306a36Sopenharmony_ci	midi->port = A_MUDATA1;
36662306a36Sopenharmony_ci	midi->ipr_tx = IPR_MIDITRANSBUFEMPTY;
36762306a36Sopenharmony_ci	midi->ipr_rx = IPR_MIDIRECVBUFEMPTY;
36862306a36Sopenharmony_ci	midi->interrupt = snd_emu10k1_midi_interrupt;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	midi = &emu->midi2;
37162306a36Sopenharmony_ci	err = emu10k1_midi_init(emu, midi, 1, "Audigy MPU-401 #2");
37262306a36Sopenharmony_ci	if (err < 0)
37362306a36Sopenharmony_ci		return err;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	midi->tx_enable = INTE_A_MIDITXENABLE2;
37662306a36Sopenharmony_ci	midi->rx_enable = INTE_A_MIDIRXENABLE2;
37762306a36Sopenharmony_ci	midi->port = A_MUDATA2;
37862306a36Sopenharmony_ci	midi->ipr_tx = IPR_A_MIDITRANSBUFEMPTY2;
37962306a36Sopenharmony_ci	midi->ipr_rx = IPR_A_MIDIRECVBUFEMPTY2;
38062306a36Sopenharmony_ci	midi->interrupt = snd_emu10k1_midi_interrupt2;
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci}
383