xref: /openbmc/linux/sound/usb/caiaq/midi.c (revision 63dc02bd)
1 /*
2  *   Copyright (c) 2006,2007 Daniel Mack
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program; if not, write to the Free Software
16  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 */
18 
19 #include <linux/usb.h>
20 #include <linux/gfp.h>
21 #include <sound/rawmidi.h>
22 #include <sound/core.h>
23 #include <sound/pcm.h>
24 
25 #include "device.h"
26 #include "midi.h"
27 
28 static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream)
29 {
30 	return 0;
31 }
32 
33 static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream)
34 {
35 	return 0;
36 }
37 
38 static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
39 {
40 	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
41 
42 	if (!dev)
43 		return;
44 
45 	dev->midi_receive_substream = up ? substream : NULL;
46 }
47 
48 
49 static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream)
50 {
51 	return 0;
52 }
53 
54 static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)
55 {
56 	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
57 	if (dev->midi_out_active) {
58 		usb_kill_urb(&dev->midi_out_urb);
59 		dev->midi_out_active = 0;
60 	}
61 	return 0;
62 }
63 
64 static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev,
65 				    struct snd_rawmidi_substream *substream)
66 {
67 	int len, ret;
68 
69 	dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
70 	dev->midi_out_buf[1] = 0; /* port */
71 	len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3,
72 				   EP1_BUFSIZE - 3);
73 
74 	if (len <= 0)
75 		return;
76 
77 	dev->midi_out_buf[2] = len;
78 	dev->midi_out_urb.transfer_buffer_length = len+3;
79 
80 	ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC);
81 	if (ret < 0)
82 		log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
83 		    "ret=%d, len=%d\n",
84 		    substream, ret, len);
85 	else
86 		dev->midi_out_active = 1;
87 }
88 
89 static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
90 {
91 	struct snd_usb_caiaqdev *dev = substream->rmidi->private_data;
92 
93 	if (up) {
94 		dev->midi_out_substream = substream;
95 		if (!dev->midi_out_active)
96 			snd_usb_caiaq_midi_send(dev, substream);
97 	} else {
98 		dev->midi_out_substream = NULL;
99 	}
100 }
101 
102 
103 static struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
104 {
105 	.open =		snd_usb_caiaq_midi_output_open,
106 	.close =	snd_usb_caiaq_midi_output_close,
107 	.trigger =      snd_usb_caiaq_midi_output_trigger,
108 };
109 
110 static struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
111 {
112 	.open =		snd_usb_caiaq_midi_input_open,
113 	.close =	snd_usb_caiaq_midi_input_close,
114 	.trigger =      snd_usb_caiaq_midi_input_trigger,
115 };
116 
117 void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev,
118 				     int port, const char *buf, int len)
119 {
120 	if (!dev->midi_receive_substream)
121 		return;
122 
123 	snd_rawmidi_receive(dev->midi_receive_substream, buf, len);
124 }
125 
126 int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
127 {
128 	int ret;
129 	struct snd_rawmidi *rmidi;
130 
131 	ret = snd_rawmidi_new(device->chip.card, device->product_name, 0,
132 					device->spec.num_midi_out,
133 					device->spec.num_midi_in,
134 					&rmidi);
135 
136 	if (ret < 0)
137 		return ret;
138 
139 	strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name));
140 
141 	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
142 	rmidi->private_data = device;
143 
144 	if (device->spec.num_midi_out > 0) {
145 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
146 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
147 				    &snd_usb_caiaq_midi_output);
148 	}
149 
150 	if (device->spec.num_midi_in > 0) {
151 		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
152 		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
153 				    &snd_usb_caiaq_midi_input);
154 	}
155 
156 	device->rmidi = rmidi;
157 
158 	return 0;
159 }
160 
161 void snd_usb_caiaq_midi_output_done(struct urb* urb)
162 {
163 	struct snd_usb_caiaqdev *dev = urb->context;
164 
165 	dev->midi_out_active = 0;
166 	if (urb->status != 0)
167 		return;
168 
169 	if (!dev->midi_out_substream)
170 		return;
171 
172 	snd_usb_caiaq_midi_send(dev, dev->midi_out_substream);
173 }
174 
175