xref: /openbmc/linux/sound/pci/ca0106/ca_midi.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28a5afd29SJames Courtier-Dutton /*
38a5afd29SJames Courtier-Dutton  *  Copyright 10/16/2005 Tilman Kranz <tilde@tk-sls.de>
48a5afd29SJames Courtier-Dutton  *  Creative Audio MIDI, for the CA0106 Driver
58a5afd29SJames Courtier-Dutton  *  Version: 0.0.1
68a5afd29SJames Courtier-Dutton  *
78a5afd29SJames Courtier-Dutton  *  Changelog:
88a5afd29SJames Courtier-Dutton  *    Implementation is based on mpu401 and emu10k1x and
98a5afd29SJames Courtier-Dutton  *    tested with ca0106.
10c1017a4cSJaroslav Kysela  *    mpu401: Copyright (c) by Jaroslav Kysela <perex@perex.cz>
117b4260f2SJames Courtier-Dutton  *    emu10k1x: Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
128a5afd29SJames Courtier-Dutton  */
138a5afd29SJames Courtier-Dutton 
148a5afd29SJames Courtier-Dutton #include <linux/spinlock.h>
158a5afd29SJames Courtier-Dutton #include <sound/core.h>
168a5afd29SJames Courtier-Dutton #include <sound/rawmidi.h>
178a5afd29SJames Courtier-Dutton 
188a5afd29SJames Courtier-Dutton #include "ca_midi.h"
198a5afd29SJames Courtier-Dutton 
208a5afd29SJames Courtier-Dutton #define ca_midi_write_data(midi, data)	midi->write(midi, data, 0)
218a5afd29SJames Courtier-Dutton #define ca_midi_write_cmd(midi, data)	midi->write(midi, data, 1)
228a5afd29SJames Courtier-Dutton #define ca_midi_read_data(midi)		midi->read(midi, 0)
238a5afd29SJames Courtier-Dutton #define ca_midi_read_stat(midi)		midi->read(midi, 1)
248a5afd29SJames Courtier-Dutton #define ca_midi_input_avail(midi)	(!(ca_midi_read_stat(midi) & midi->input_avail))
258a5afd29SJames Courtier-Dutton #define ca_midi_output_ready(midi)	(!(ca_midi_read_stat(midi) & midi->output_ready))
268a5afd29SJames Courtier-Dutton 
ca_midi_clear_rx(struct snd_ca_midi * midi)27e4a3d145STakashi Iwai static void ca_midi_clear_rx(struct snd_ca_midi *midi)
288a5afd29SJames Courtier-Dutton {
298a5afd29SJames Courtier-Dutton 	int timeout = 100000;
308a5afd29SJames Courtier-Dutton 	for (; timeout > 0 && ca_midi_input_avail(midi); timeout--)
318a5afd29SJames Courtier-Dutton 		ca_midi_read_data(midi);
328a5afd29SJames Courtier-Dutton #ifdef CONFIG_SND_DEBUG
338a5afd29SJames Courtier-Dutton 	if (timeout <= 0)
3474103227STakashi Iwai 		pr_err("ca_midi_clear_rx: timeout (status = 0x%x)\n",
35e4a3d145STakashi Iwai 			   ca_midi_read_stat(midi));
368a5afd29SJames Courtier-Dutton #endif
378a5afd29SJames Courtier-Dutton }
388a5afd29SJames Courtier-Dutton 
ca_midi_interrupt(struct snd_ca_midi * midi,unsigned int status)39e4a3d145STakashi Iwai static void ca_midi_interrupt(struct snd_ca_midi *midi, unsigned int status)
40e4a3d145STakashi Iwai {
418a5afd29SJames Courtier-Dutton 	unsigned char byte;
428a5afd29SJames Courtier-Dutton 
438a5afd29SJames Courtier-Dutton 	if (midi->rmidi == NULL) {
448a5afd29SJames Courtier-Dutton 		midi->interrupt_disable(midi,midi->tx_enable | midi->rx_enable);
458a5afd29SJames Courtier-Dutton 		return;
468a5afd29SJames Courtier-Dutton 	}
478a5afd29SJames Courtier-Dutton 
488a5afd29SJames Courtier-Dutton 	spin_lock(&midi->input_lock);
498a5afd29SJames Courtier-Dutton 	if ((status & midi->ipr_rx) && ca_midi_input_avail(midi)) {
508a5afd29SJames Courtier-Dutton 		if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
518a5afd29SJames Courtier-Dutton 			ca_midi_clear_rx(midi);
528a5afd29SJames Courtier-Dutton 		} else {
538a5afd29SJames Courtier-Dutton 			byte = ca_midi_read_data(midi);
548a5afd29SJames Courtier-Dutton 			if(midi->substream_input)
558a5afd29SJames Courtier-Dutton 				snd_rawmidi_receive(midi->substream_input, &byte, 1);
568a5afd29SJames Courtier-Dutton 
578a5afd29SJames Courtier-Dutton 
588a5afd29SJames Courtier-Dutton 		}
598a5afd29SJames Courtier-Dutton 	}
608a5afd29SJames Courtier-Dutton 	spin_unlock(&midi->input_lock);
618a5afd29SJames Courtier-Dutton 
628a5afd29SJames Courtier-Dutton 	spin_lock(&midi->output_lock);
638a5afd29SJames Courtier-Dutton 	if ((status & midi->ipr_tx) && ca_midi_output_ready(midi)) {
648a5afd29SJames Courtier-Dutton 		if (midi->substream_output &&
658a5afd29SJames Courtier-Dutton 		    snd_rawmidi_transmit(midi->substream_output, &byte, 1) == 1) {
668a5afd29SJames Courtier-Dutton 			ca_midi_write_data(midi, byte);
678a5afd29SJames Courtier-Dutton 		} else {
688a5afd29SJames Courtier-Dutton 			midi->interrupt_disable(midi,midi->tx_enable);
698a5afd29SJames Courtier-Dutton 		}
708a5afd29SJames Courtier-Dutton 	}
718a5afd29SJames Courtier-Dutton 	spin_unlock(&midi->output_lock);
728a5afd29SJames Courtier-Dutton 
738a5afd29SJames Courtier-Dutton }
748a5afd29SJames Courtier-Dutton 
ca_midi_cmd(struct snd_ca_midi * midi,unsigned char cmd,int ack)75e4a3d145STakashi Iwai static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack)
768a5afd29SJames Courtier-Dutton {
778a5afd29SJames Courtier-Dutton 	unsigned long flags;
788a5afd29SJames Courtier-Dutton 	int timeout, ok;
798a5afd29SJames Courtier-Dutton 
808a5afd29SJames Courtier-Dutton 	spin_lock_irqsave(&midi->input_lock, flags);
818a5afd29SJames Courtier-Dutton 	ca_midi_write_data(midi, 0x00);
828a5afd29SJames Courtier-Dutton 	/* ca_midi_clear_rx(midi); */
838a5afd29SJames Courtier-Dutton 
848a5afd29SJames Courtier-Dutton 	ca_midi_write_cmd(midi, cmd);
858a5afd29SJames Courtier-Dutton 	if (ack) {
868a5afd29SJames Courtier-Dutton 		ok = 0;
878a5afd29SJames Courtier-Dutton 		timeout = 10000;
888a5afd29SJames Courtier-Dutton 		while (!ok && timeout-- > 0) {
898a5afd29SJames Courtier-Dutton 			if (ca_midi_input_avail(midi)) {
908a5afd29SJames Courtier-Dutton 				if (ca_midi_read_data(midi) == midi->ack)
918a5afd29SJames Courtier-Dutton 					ok = 1;
928a5afd29SJames Courtier-Dutton 			}
938a5afd29SJames Courtier-Dutton 		}
948a5afd29SJames Courtier-Dutton 		if (!ok && ca_midi_read_data(midi) == midi->ack)
958a5afd29SJames Courtier-Dutton 			ok = 1;
968a5afd29SJames Courtier-Dutton 	} else {
978a5afd29SJames Courtier-Dutton 		ok = 1;
988a5afd29SJames Courtier-Dutton 	}
998a5afd29SJames Courtier-Dutton 	spin_unlock_irqrestore(&midi->input_lock, flags);
1008a5afd29SJames Courtier-Dutton 	if (!ok)
10174103227STakashi Iwai 		pr_err("ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n",
1028a5afd29SJames Courtier-Dutton 			   cmd,
1038a5afd29SJames Courtier-Dutton 			   midi->get_dev_id_port(midi->dev_id),
1048a5afd29SJames Courtier-Dutton 			   ca_midi_read_stat(midi),
1058a5afd29SJames Courtier-Dutton 			   ca_midi_read_data(midi));
1068a5afd29SJames Courtier-Dutton }
1078a5afd29SJames Courtier-Dutton 
ca_midi_input_open(struct snd_rawmidi_substream * substream)108e4a3d145STakashi Iwai static int ca_midi_input_open(struct snd_rawmidi_substream *substream)
1098a5afd29SJames Courtier-Dutton {
110e4a3d145STakashi Iwai 	struct snd_ca_midi *midi = substream->rmidi->private_data;
1118a5afd29SJames Courtier-Dutton 	unsigned long flags;
1128a5afd29SJames Courtier-Dutton 
113da3cec35STakashi Iwai 	if (snd_BUG_ON(!midi->dev_id))
114da3cec35STakashi Iwai 		return -ENXIO;
1158a5afd29SJames Courtier-Dutton 	spin_lock_irqsave(&midi->open_lock, flags);
1168a5afd29SJames Courtier-Dutton 	midi->midi_mode |= CA_MIDI_MODE_INPUT;
1178a5afd29SJames Courtier-Dutton 	midi->substream_input = substream;
1188a5afd29SJames Courtier-Dutton 	if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) {
1198a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->open_lock, flags);
1208a5afd29SJames Courtier-Dutton 		ca_midi_cmd(midi, midi->reset, 1);
1218a5afd29SJames Courtier-Dutton 		ca_midi_cmd(midi, midi->enter_uart, 1);
1228a5afd29SJames Courtier-Dutton 	} else {
1238a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->open_lock, flags);
1248a5afd29SJames Courtier-Dutton 	}
1258a5afd29SJames Courtier-Dutton 	return 0;
1268a5afd29SJames Courtier-Dutton }
1278a5afd29SJames Courtier-Dutton 
ca_midi_output_open(struct snd_rawmidi_substream * substream)128e4a3d145STakashi Iwai static int ca_midi_output_open(struct snd_rawmidi_substream *substream)
1298a5afd29SJames Courtier-Dutton {
130e4a3d145STakashi Iwai 	struct snd_ca_midi *midi = substream->rmidi->private_data;
1318a5afd29SJames Courtier-Dutton 	unsigned long flags;
1328a5afd29SJames Courtier-Dutton 
133da3cec35STakashi Iwai 	if (snd_BUG_ON(!midi->dev_id))
134da3cec35STakashi Iwai 		return -ENXIO;
1358a5afd29SJames Courtier-Dutton 	spin_lock_irqsave(&midi->open_lock, flags);
1368a5afd29SJames Courtier-Dutton 	midi->midi_mode |= CA_MIDI_MODE_OUTPUT;
1378a5afd29SJames Courtier-Dutton 	midi->substream_output = substream;
1388a5afd29SJames Courtier-Dutton 	if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
1398a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->open_lock, flags);
1408a5afd29SJames Courtier-Dutton 		ca_midi_cmd(midi, midi->reset, 1);
1418a5afd29SJames Courtier-Dutton 		ca_midi_cmd(midi, midi->enter_uart, 1);
1428a5afd29SJames Courtier-Dutton 	} else {
1438a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->open_lock, flags);
1448a5afd29SJames Courtier-Dutton 	}
1458a5afd29SJames Courtier-Dutton 	return 0;
1468a5afd29SJames Courtier-Dutton }
1478a5afd29SJames Courtier-Dutton 
ca_midi_input_close(struct snd_rawmidi_substream * substream)148e4a3d145STakashi Iwai static int ca_midi_input_close(struct snd_rawmidi_substream *substream)
1498a5afd29SJames Courtier-Dutton {
150e4a3d145STakashi Iwai 	struct snd_ca_midi *midi = substream->rmidi->private_data;
1518a5afd29SJames Courtier-Dutton 	unsigned long flags;
1528a5afd29SJames Courtier-Dutton 
153da3cec35STakashi Iwai 	if (snd_BUG_ON(!midi->dev_id))
154da3cec35STakashi Iwai 		return -ENXIO;
1558a5afd29SJames Courtier-Dutton 	spin_lock_irqsave(&midi->open_lock, flags);
1568a5afd29SJames Courtier-Dutton 	midi->interrupt_disable(midi,midi->rx_enable);
1578a5afd29SJames Courtier-Dutton 	midi->midi_mode &= ~CA_MIDI_MODE_INPUT;
1588a5afd29SJames Courtier-Dutton 	midi->substream_input = NULL;
1598a5afd29SJames Courtier-Dutton 	if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT)) {
1608a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->open_lock, flags);
1618a5afd29SJames Courtier-Dutton 		ca_midi_cmd(midi, midi->reset, 0);
1628a5afd29SJames Courtier-Dutton 	} else {
1638a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->open_lock, flags);
1648a5afd29SJames Courtier-Dutton 	}
1658a5afd29SJames Courtier-Dutton 	return 0;
1668a5afd29SJames Courtier-Dutton }
1678a5afd29SJames Courtier-Dutton 
ca_midi_output_close(struct snd_rawmidi_substream * substream)168e4a3d145STakashi Iwai static int ca_midi_output_close(struct snd_rawmidi_substream *substream)
1698a5afd29SJames Courtier-Dutton {
170e4a3d145STakashi Iwai 	struct snd_ca_midi *midi = substream->rmidi->private_data;
1718a5afd29SJames Courtier-Dutton 	unsigned long flags;
172da3cec35STakashi Iwai 
173da3cec35STakashi Iwai 	if (snd_BUG_ON(!midi->dev_id))
174da3cec35STakashi Iwai 		return -ENXIO;
1758a5afd29SJames Courtier-Dutton 
1768a5afd29SJames Courtier-Dutton 	spin_lock_irqsave(&midi->open_lock, flags);
1778a5afd29SJames Courtier-Dutton 
1788a5afd29SJames Courtier-Dutton 	midi->interrupt_disable(midi,midi->tx_enable);
1798a5afd29SJames Courtier-Dutton 	midi->midi_mode &= ~CA_MIDI_MODE_OUTPUT;
1808a5afd29SJames Courtier-Dutton 	midi->substream_output = NULL;
1818a5afd29SJames Courtier-Dutton 
1828a5afd29SJames Courtier-Dutton 	if (!(midi->midi_mode & CA_MIDI_MODE_INPUT)) {
1838a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->open_lock, flags);
1848a5afd29SJames Courtier-Dutton 		ca_midi_cmd(midi, midi->reset, 0);
1858a5afd29SJames Courtier-Dutton 	} else {
1868a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->open_lock, flags);
1878a5afd29SJames Courtier-Dutton 	}
1888a5afd29SJames Courtier-Dutton 	return 0;
1898a5afd29SJames Courtier-Dutton }
1908a5afd29SJames Courtier-Dutton 
ca_midi_input_trigger(struct snd_rawmidi_substream * substream,int up)191e4a3d145STakashi Iwai static void ca_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
1928a5afd29SJames Courtier-Dutton {
193e4a3d145STakashi Iwai 	struct snd_ca_midi *midi = substream->rmidi->private_data;
194da3cec35STakashi Iwai 
195da3cec35STakashi Iwai 	if (snd_BUG_ON(!midi->dev_id))
196da3cec35STakashi Iwai 		return;
1978a5afd29SJames Courtier-Dutton 
1988a5afd29SJames Courtier-Dutton 	if (up) {
1998a5afd29SJames Courtier-Dutton 		midi->interrupt_enable(midi,midi->rx_enable);
2008a5afd29SJames Courtier-Dutton 	} else {
2018a5afd29SJames Courtier-Dutton 		midi->interrupt_disable(midi, midi->rx_enable);
2028a5afd29SJames Courtier-Dutton 	}
2038a5afd29SJames Courtier-Dutton }
2048a5afd29SJames Courtier-Dutton 
ca_midi_output_trigger(struct snd_rawmidi_substream * substream,int up)205e4a3d145STakashi Iwai static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
2068a5afd29SJames Courtier-Dutton {
207e4a3d145STakashi Iwai 	struct snd_ca_midi *midi = substream->rmidi->private_data;
2088a5afd29SJames Courtier-Dutton 	unsigned long flags;
2098a5afd29SJames Courtier-Dutton 
210da3cec35STakashi Iwai 	if (snd_BUG_ON(!midi->dev_id))
211da3cec35STakashi Iwai 		return;
2128a5afd29SJames Courtier-Dutton 
2138a5afd29SJames Courtier-Dutton 	if (up) {
2148a5afd29SJames Courtier-Dutton 		int max = 4;
2158a5afd29SJames Courtier-Dutton 		unsigned char byte;
2168a5afd29SJames Courtier-Dutton 
2178a5afd29SJames Courtier-Dutton 		spin_lock_irqsave(&midi->output_lock, flags);
2188a5afd29SJames Courtier-Dutton 
2198a5afd29SJames Courtier-Dutton 		/* try to send some amount of bytes here before interrupts */
2208a5afd29SJames Courtier-Dutton 		while (max > 0) {
2218a5afd29SJames Courtier-Dutton 			if (ca_midi_output_ready(midi)) {
2228a5afd29SJames Courtier-Dutton 				if (!(midi->midi_mode & CA_MIDI_MODE_OUTPUT) ||
2238a5afd29SJames Courtier-Dutton 				    snd_rawmidi_transmit(substream, &byte, 1) != 1) {
2248a5afd29SJames Courtier-Dutton 					/* no more data */
2258a5afd29SJames Courtier-Dutton 					spin_unlock_irqrestore(&midi->output_lock, flags);
2268a5afd29SJames Courtier-Dutton 					return;
2278a5afd29SJames Courtier-Dutton 				}
2288a5afd29SJames Courtier-Dutton 				ca_midi_write_data(midi, byte);
2298a5afd29SJames Courtier-Dutton 				max--;
2308a5afd29SJames Courtier-Dutton 			} else {
2318a5afd29SJames Courtier-Dutton 				break;
2328a5afd29SJames Courtier-Dutton 			}
2338a5afd29SJames Courtier-Dutton 		}
2348a5afd29SJames Courtier-Dutton 
2358a5afd29SJames Courtier-Dutton 		spin_unlock_irqrestore(&midi->output_lock, flags);
2368a5afd29SJames Courtier-Dutton 		midi->interrupt_enable(midi,midi->tx_enable);
2378a5afd29SJames Courtier-Dutton 
2388a5afd29SJames Courtier-Dutton 	} else {
2398a5afd29SJames Courtier-Dutton 		midi->interrupt_disable(midi,midi->tx_enable);
2408a5afd29SJames Courtier-Dutton 	}
2418a5afd29SJames Courtier-Dutton }
2428a5afd29SJames Courtier-Dutton 
243485885b9STakashi Iwai static const struct snd_rawmidi_ops ca_midi_output =
2448a5afd29SJames Courtier-Dutton {
2458a5afd29SJames Courtier-Dutton 	.open =		ca_midi_output_open,
2468a5afd29SJames Courtier-Dutton 	.close =	ca_midi_output_close,
2478a5afd29SJames Courtier-Dutton 	.trigger =	ca_midi_output_trigger,
2488a5afd29SJames Courtier-Dutton };
2498a5afd29SJames Courtier-Dutton 
250485885b9STakashi Iwai static const struct snd_rawmidi_ops ca_midi_input =
2518a5afd29SJames Courtier-Dutton {
2528a5afd29SJames Courtier-Dutton 	.open =		ca_midi_input_open,
2538a5afd29SJames Courtier-Dutton 	.close =	ca_midi_input_close,
2548a5afd29SJames Courtier-Dutton 	.trigger =	ca_midi_input_trigger,
2558a5afd29SJames Courtier-Dutton };
2568a5afd29SJames Courtier-Dutton 
ca_midi_free(struct snd_ca_midi * midi)257e4a3d145STakashi Iwai static void ca_midi_free(struct snd_ca_midi *midi)
258e4a3d145STakashi Iwai {
2598a5afd29SJames Courtier-Dutton 	midi->interrupt = NULL;
2608a5afd29SJames Courtier-Dutton 	midi->interrupt_enable = NULL;
2618a5afd29SJames Courtier-Dutton 	midi->interrupt_disable = NULL;
2628a5afd29SJames Courtier-Dutton 	midi->read = NULL;
2638a5afd29SJames Courtier-Dutton 	midi->write = NULL;
2648a5afd29SJames Courtier-Dutton 	midi->get_dev_id_card = NULL;
2658a5afd29SJames Courtier-Dutton 	midi->get_dev_id_port = NULL;
2668a5afd29SJames Courtier-Dutton 	midi->rmidi = NULL;
2678a5afd29SJames Courtier-Dutton }
2688a5afd29SJames Courtier-Dutton 
ca_rmidi_free(struct snd_rawmidi * rmidi)269e4a3d145STakashi Iwai static void ca_rmidi_free(struct snd_rawmidi *rmidi)
2708a5afd29SJames Courtier-Dutton {
271e4a3d145STakashi Iwai 	ca_midi_free(rmidi->private_data);
2728a5afd29SJames Courtier-Dutton }
2738a5afd29SJames Courtier-Dutton 
ca_midi_init(void * dev_id,struct snd_ca_midi * midi,int device,char * name)274e23e7a14SBill Pemberton int ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name)
2758a5afd29SJames Courtier-Dutton {
276e4a3d145STakashi Iwai 	struct snd_rawmidi *rmidi;
2778a5afd29SJames Courtier-Dutton 	int err;
2788a5afd29SJames Courtier-Dutton 
279*59c39cd3STakashi Iwai 	err = snd_rawmidi_new(midi->get_dev_id_card(midi->dev_id), name, device, 1, 1, &rmidi);
280*59c39cd3STakashi Iwai 	if (err < 0)
2818a5afd29SJames Courtier-Dutton 		return err;
2828a5afd29SJames Courtier-Dutton 
2838a5afd29SJames Courtier-Dutton 	midi->dev_id = dev_id;
2848a5afd29SJames Courtier-Dutton 	midi->interrupt = ca_midi_interrupt;
2858a5afd29SJames Courtier-Dutton 
2868a5afd29SJames Courtier-Dutton 	spin_lock_init(&midi->open_lock);
2878a5afd29SJames Courtier-Dutton 	spin_lock_init(&midi->input_lock);
2888a5afd29SJames Courtier-Dutton 	spin_lock_init(&midi->output_lock);
2898a5afd29SJames Courtier-Dutton 
2908a5afd29SJames Courtier-Dutton 	strcpy(rmidi->name, name);
2918a5afd29SJames Courtier-Dutton 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &ca_midi_output);
2928a5afd29SJames Courtier-Dutton 	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &ca_midi_input);
2938a5afd29SJames Courtier-Dutton 	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
2948a5afd29SJames Courtier-Dutton 	                     SNDRV_RAWMIDI_INFO_INPUT |
2958a5afd29SJames Courtier-Dutton 	                     SNDRV_RAWMIDI_INFO_DUPLEX;
2968a5afd29SJames Courtier-Dutton 	rmidi->private_data = midi;
2978a5afd29SJames Courtier-Dutton 	rmidi->private_free = ca_rmidi_free;
2988a5afd29SJames Courtier-Dutton 
2998a5afd29SJames Courtier-Dutton 	midi->rmidi = rmidi;
3008a5afd29SJames Courtier-Dutton 	return 0;
3018a5afd29SJames Courtier-Dutton }
3028a5afd29SJames Courtier-Dutton 
303