162306a36Sopenharmony_ci/****************************************************************************
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci   Copyright Echo Digital Audio Corporation (c) 1998 - 2004
462306a36Sopenharmony_ci   All rights reserved
562306a36Sopenharmony_ci   www.echoaudio.com
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci   This file is part of Echo Digital Audio's generic driver library.
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci   Echo Digital Audio's generic driver library is free software;
1062306a36Sopenharmony_ci   you can redistribute it and/or modify it under the terms of
1162306a36Sopenharmony_ci   the GNU General Public License as published by the Free Software
1262306a36Sopenharmony_ci   Foundation.
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci   This program is distributed in the hope that it will be useful,
1562306a36Sopenharmony_ci   but WITHOUT ANY WARRANTY; without even the implied warranty of
1662306a36Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1762306a36Sopenharmony_ci   GNU General Public License for more details.
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci   You should have received a copy of the GNU General Public License
2062306a36Sopenharmony_ci   along with this program; if not, write to the Free Software
2162306a36Sopenharmony_ci   Foundation, Inc., 59 Temple Place - Suite 330, Boston,
2262306a36Sopenharmony_ci   MA  02111-1307, USA.
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci   *************************************************************************
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci Translation from C++ and adaptation for use in ALSA-Driver
2762306a36Sopenharmony_ci were made by Giuliano Pochini <pochini@shiny.it>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci****************************************************************************/
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/******************************************************************************
3362306a36Sopenharmony_ci	MIDI lowlevel code
3462306a36Sopenharmony_ci******************************************************************************/
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Start and stop Midi input */
3762306a36Sopenharmony_cistatic int enable_midi_input(struct echoaudio *chip, char enable)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	dev_dbg(chip->card->dev, "enable_midi_input(%d)\n", enable);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (wait_handshake(chip))
4262306a36Sopenharmony_ci		return -EIO;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (enable) {
4562306a36Sopenharmony_ci		chip->mtc_state = MIDI_IN_STATE_NORMAL;
4662306a36Sopenharmony_ci		chip->comm_page->flags |=
4762306a36Sopenharmony_ci			cpu_to_le32(DSP_FLAG_MIDI_INPUT);
4862306a36Sopenharmony_ci	} else
4962306a36Sopenharmony_ci		chip->comm_page->flags &=
5062306a36Sopenharmony_ci			~cpu_to_le32(DSP_FLAG_MIDI_INPUT);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	clear_handshake(chip);
5362306a36Sopenharmony_ci	return send_vector(chip, DSP_VC_UPDATE_FLAGS);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* Send a buffer full of MIDI data to the DSP
5962306a36Sopenharmony_ciReturns how many actually written or < 0 on error */
6062306a36Sopenharmony_cistatic int write_midi(struct echoaudio *chip, u8 *data, int bytes)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	if (snd_BUG_ON(bytes <= 0 || bytes >= MIDI_OUT_BUFFER_SIZE))
6362306a36Sopenharmony_ci		return -EINVAL;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (wait_handshake(chip))
6662306a36Sopenharmony_ci		return -EIO;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* HF4 indicates that it is safe to write MIDI output data */
6962306a36Sopenharmony_ci	if (! (get_dsp_register(chip, CHI32_STATUS_REG) & CHI32_STATUS_REG_HF4))
7062306a36Sopenharmony_ci		return 0;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	chip->comm_page->midi_output[0] = bytes;
7362306a36Sopenharmony_ci	memcpy(&chip->comm_page->midi_output[1], data, bytes);
7462306a36Sopenharmony_ci	chip->comm_page->midi_out_free_count = 0;
7562306a36Sopenharmony_ci	clear_handshake(chip);
7662306a36Sopenharmony_ci	send_vector(chip, DSP_VC_MIDI_WRITE);
7762306a36Sopenharmony_ci	dev_dbg(chip->card->dev, "write_midi: %d\n", bytes);
7862306a36Sopenharmony_ci	return bytes;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/* Run the state machine for MIDI input data
8462306a36Sopenharmony_ciMIDI time code sync isn't supported by this code right now, but you still need
8562306a36Sopenharmony_cithis state machine to parse the incoming MIDI data stream.  Every time the DSP
8662306a36Sopenharmony_cisees a 0xF1 byte come in, it adds the DSP sample position to the MIDI data
8762306a36Sopenharmony_cistream. The DSP sample position is represented as a 32 bit unsigned value,
8862306a36Sopenharmony_ciwith the high 16 bits first, followed by the low 16 bits. Since these aren't
8962306a36Sopenharmony_cireal MIDI bytes, the following logic is needed to skip them. */
9062306a36Sopenharmony_cistatic inline int mtc_process_data(struct echoaudio *chip, short midi_byte)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	switch (chip->mtc_state) {
9362306a36Sopenharmony_ci	case MIDI_IN_STATE_NORMAL:
9462306a36Sopenharmony_ci		if (midi_byte == 0xF1)
9562306a36Sopenharmony_ci			chip->mtc_state = MIDI_IN_STATE_TS_HIGH;
9662306a36Sopenharmony_ci		break;
9762306a36Sopenharmony_ci	case MIDI_IN_STATE_TS_HIGH:
9862306a36Sopenharmony_ci		chip->mtc_state = MIDI_IN_STATE_TS_LOW;
9962306a36Sopenharmony_ci		return MIDI_IN_SKIP_DATA;
10062306a36Sopenharmony_ci		break;
10162306a36Sopenharmony_ci	case MIDI_IN_STATE_TS_LOW:
10262306a36Sopenharmony_ci		chip->mtc_state = MIDI_IN_STATE_F1_DATA;
10362306a36Sopenharmony_ci		return MIDI_IN_SKIP_DATA;
10462306a36Sopenharmony_ci		break;
10562306a36Sopenharmony_ci	case MIDI_IN_STATE_F1_DATA:
10662306a36Sopenharmony_ci		chip->mtc_state = MIDI_IN_STATE_NORMAL;
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/* This function is called from the IRQ handler and it reads the midi data
11562306a36Sopenharmony_cifrom the DSP's buffer.  It returns the number of bytes received. */
11662306a36Sopenharmony_cistatic int midi_service_irq(struct echoaudio *chip)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	short int count, midi_byte, i, received;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	/* The count is at index 0, followed by actual data */
12162306a36Sopenharmony_ci	count = le16_to_cpu(chip->comm_page->midi_input[0]);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (snd_BUG_ON(count >= MIDI_IN_BUFFER_SIZE))
12462306a36Sopenharmony_ci		return 0;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Get the MIDI data from the comm page */
12762306a36Sopenharmony_ci	received = 0;
12862306a36Sopenharmony_ci	for (i = 1; i <= count; i++) {
12962306a36Sopenharmony_ci		/* Get the MIDI byte */
13062306a36Sopenharmony_ci		midi_byte = le16_to_cpu(chip->comm_page->midi_input[i]);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		/* Parse the incoming MIDI stream. The incoming MIDI data
13362306a36Sopenharmony_ci		consists of MIDI bytes and timestamps for the MIDI time code
13462306a36Sopenharmony_ci		0xF1 bytes. mtc_process_data() is a little state machine that
13562306a36Sopenharmony_ci		parses the stream. If you get MIDI_IN_SKIP_DATA back, then
13662306a36Sopenharmony_ci		this is a timestamp byte, not a MIDI byte, so don't store it
13762306a36Sopenharmony_ci		in the MIDI input buffer. */
13862306a36Sopenharmony_ci		if (mtc_process_data(chip, midi_byte) == MIDI_IN_SKIP_DATA)
13962306a36Sopenharmony_ci			continue;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		chip->midi_buffer[received++] = (u8)midi_byte;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return received;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/******************************************************************************
15162306a36Sopenharmony_ci	MIDI interface
15262306a36Sopenharmony_ci******************************************************************************/
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic int snd_echo_midi_input_open(struct snd_rawmidi_substream *substream)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct echoaudio *chip = substream->rmidi->private_data;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	chip->midi_in = substream;
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic void snd_echo_midi_input_trigger(struct snd_rawmidi_substream *substream,
16562306a36Sopenharmony_ci					int up)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct echoaudio *chip = substream->rmidi->private_data;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (up != chip->midi_input_enabled) {
17062306a36Sopenharmony_ci		spin_lock_irq(&chip->lock);
17162306a36Sopenharmony_ci		enable_midi_input(chip, up);
17262306a36Sopenharmony_ci		spin_unlock_irq(&chip->lock);
17362306a36Sopenharmony_ci		chip->midi_input_enabled = up;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int snd_echo_midi_input_close(struct snd_rawmidi_substream *substream)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct echoaudio *chip = substream->rmidi->private_data;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	chip->midi_in = NULL;
18462306a36Sopenharmony_ci	return 0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct echoaudio *chip = substream->rmidi->private_data;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	chip->tinuse = 0;
19462306a36Sopenharmony_ci	chip->midi_full = 0;
19562306a36Sopenharmony_ci	chip->midi_out = substream;
19662306a36Sopenharmony_ci	return 0;
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void snd_echo_midi_output_write(struct timer_list *t)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	struct echoaudio *chip = from_timer(chip, t, timer);
20462306a36Sopenharmony_ci	unsigned long flags;
20562306a36Sopenharmony_ci	int bytes, sent, time;
20662306a36Sopenharmony_ci	unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1];
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	/* No interrupts are involved: we have to check at regular intervals
20962306a36Sopenharmony_ci	if the card's output buffer has room for new data. */
21062306a36Sopenharmony_ci	sent = 0;
21162306a36Sopenharmony_ci	spin_lock_irqsave(&chip->lock, flags);
21262306a36Sopenharmony_ci	chip->midi_full = 0;
21362306a36Sopenharmony_ci	if (!snd_rawmidi_transmit_empty(chip->midi_out)) {
21462306a36Sopenharmony_ci		bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf,
21562306a36Sopenharmony_ci						  MIDI_OUT_BUFFER_SIZE - 1);
21662306a36Sopenharmony_ci		dev_dbg(chip->card->dev, "Try to send %d bytes...\n", bytes);
21762306a36Sopenharmony_ci		sent = write_midi(chip, buf, bytes);
21862306a36Sopenharmony_ci		if (sent < 0) {
21962306a36Sopenharmony_ci			dev_err(chip->card->dev,
22062306a36Sopenharmony_ci				"write_midi() error %d\n", sent);
22162306a36Sopenharmony_ci			/* retry later */
22262306a36Sopenharmony_ci			sent = 9000;
22362306a36Sopenharmony_ci			chip->midi_full = 1;
22462306a36Sopenharmony_ci		} else if (sent > 0) {
22562306a36Sopenharmony_ci			dev_dbg(chip->card->dev, "%d bytes sent\n", sent);
22662306a36Sopenharmony_ci			snd_rawmidi_transmit_ack(chip->midi_out, sent);
22762306a36Sopenharmony_ci		} else {
22862306a36Sopenharmony_ci			/* Buffer is full. DSP's internal buffer is 64 (128 ?)
22962306a36Sopenharmony_ci			bytes long. Let's wait until half of them are sent */
23062306a36Sopenharmony_ci			dev_dbg(chip->card->dev, "Full\n");
23162306a36Sopenharmony_ci			sent = 32;
23262306a36Sopenharmony_ci			chip->midi_full = 1;
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* We restart the timer only if there is some data left to send */
23762306a36Sopenharmony_ci	if (!snd_rawmidi_transmit_empty(chip->midi_out) && chip->tinuse) {
23862306a36Sopenharmony_ci		/* The timer will expire slightly after the data has been
23962306a36Sopenharmony_ci		   sent */
24062306a36Sopenharmony_ci		time = (sent << 3) / 25 + 1;	/* 8/25=0.32ms to send a byte */
24162306a36Sopenharmony_ci		mod_timer(&chip->timer, jiffies + (time * HZ + 999) / 1000);
24262306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
24362306a36Sopenharmony_ci			"Timer armed(%d)\n", ((time * HZ + 999) / 1000));
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->lock, flags);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream,
25162306a36Sopenharmony_ci					 int up)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct echoaudio *chip = substream->rmidi->private_data;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	dev_dbg(chip->card->dev, "snd_echo_midi_output_trigger(%d)\n", up);
25662306a36Sopenharmony_ci	spin_lock_irq(&chip->lock);
25762306a36Sopenharmony_ci	if (up) {
25862306a36Sopenharmony_ci		if (!chip->tinuse) {
25962306a36Sopenharmony_ci			timer_setup(&chip->timer, snd_echo_midi_output_write,
26062306a36Sopenharmony_ci				    0);
26162306a36Sopenharmony_ci			chip->tinuse = 1;
26262306a36Sopenharmony_ci		}
26362306a36Sopenharmony_ci	} else {
26462306a36Sopenharmony_ci		if (chip->tinuse) {
26562306a36Sopenharmony_ci			chip->tinuse = 0;
26662306a36Sopenharmony_ci			spin_unlock_irq(&chip->lock);
26762306a36Sopenharmony_ci			del_timer_sync(&chip->timer);
26862306a36Sopenharmony_ci			dev_dbg(chip->card->dev, "Timer removed\n");
26962306a36Sopenharmony_ci			return;
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci	spin_unlock_irq(&chip->lock);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (up && !chip->midi_full)
27562306a36Sopenharmony_ci		snd_echo_midi_output_write(&chip->timer);
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistatic int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct echoaudio *chip = substream->rmidi->private_data;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	chip->midi_out = NULL;
28562306a36Sopenharmony_ci	return 0;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_echo_midi_input = {
29162306a36Sopenharmony_ci	.open = snd_echo_midi_input_open,
29262306a36Sopenharmony_ci	.close = snd_echo_midi_input_close,
29362306a36Sopenharmony_ci	.trigger = snd_echo_midi_input_trigger,
29462306a36Sopenharmony_ci};
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic const struct snd_rawmidi_ops snd_echo_midi_output = {
29762306a36Sopenharmony_ci	.open = snd_echo_midi_output_open,
29862306a36Sopenharmony_ci	.close = snd_echo_midi_output_close,
29962306a36Sopenharmony_ci	.trigger = snd_echo_midi_output_trigger,
30062306a36Sopenharmony_ci};
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/* <--snd_echo_probe() */
30562306a36Sopenharmony_cistatic int snd_echo_midi_create(struct snd_card *card,
30662306a36Sopenharmony_ci				struct echoaudio *chip)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	int err;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	err = snd_rawmidi_new(card, card->shortname, 0, 1, 1, &chip->rmidi);
31162306a36Sopenharmony_ci	if (err < 0)
31262306a36Sopenharmony_ci		return err;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	strcpy(chip->rmidi->name, card->shortname);
31562306a36Sopenharmony_ci	chip->rmidi->private_data = chip;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	snd_rawmidi_set_ops(chip->rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
31862306a36Sopenharmony_ci			    &snd_echo_midi_input);
31962306a36Sopenharmony_ci	snd_rawmidi_set_ops(chip->rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
32062306a36Sopenharmony_ci			    &snd_echo_midi_output);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	chip->rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
32362306a36Sopenharmony_ci		SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
32462306a36Sopenharmony_ci	return 0;
32562306a36Sopenharmony_ci}
326