Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
  1/*
  2 * Line6 Linux USB driver - 0.9.1beta
  3 *
  4 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  5 *
  6 *	This program is free software; you can redistribute it and/or
  7 *	modify it under the terms of the GNU General Public License as
  8 *	published by the Free Software Foundation, version 2.
  9 *
 10 */
 11
 12#include <linux/slab.h>
 13#include <linux/usb.h>
 14#include <sound/core.h>
 15#include <sound/rawmidi.h>
 16
 17#include "audio.h"
 18#include "driver.h"
 19#include "midi.h"
 20#include "pod.h"
 21#include "usbdefs.h"
 22
 23#define line6_rawmidi_substream_midi(substream) \
 24	((struct snd_line6_midi *)((substream)->rmidi->private_data))
 25
 26static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
 27			   int length);
 28
 29/*
 30	Pass data received via USB to MIDI.
 31*/
 32void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
 33			int length)
 34{
 35	if (line6->line6midi->substream_receive)
 36		snd_rawmidi_receive(line6->line6midi->substream_receive,
 37				    data, length);
 38}
 39
 40/*
 41	Read data from MIDI buffer and transmit them via USB.
 42*/
 43static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
 44{
 45	struct usb_line6 *line6 =
 46	    line6_rawmidi_substream_midi(substream)->line6;
 47	struct snd_line6_midi *line6midi = line6->line6midi;
 48	struct midi_buffer *mb = &line6midi->midibuf_out;
 49	unsigned long flags;
 50	unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
 51	int req, done;
 52
 53	spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
 54
 55	for (;;) {
 56		req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
 57		done = snd_rawmidi_transmit_peek(substream, chunk, req);
 58
 59		if (done == 0)
 60			break;
 61
 62		line6_midibuf_write(mb, chunk, done);
 63		snd_rawmidi_transmit_ack(substream, done);
 64	}
 65
 66	for (;;) {
 67		done = line6_midibuf_read(mb, chunk,
 68					  LINE6_FALLBACK_MAXPACKETSIZE);
 69
 70		if (done == 0)
 71			break;
 72
 73		send_midi_async(line6, chunk, done);
 74	}
 75
 76	spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags);
 77}
 78
 79/*
 80	Notification of completion of MIDI transmission.
 81*/
 82static void midi_sent(struct urb *urb)
 83{
 84	unsigned long flags;
 85	int status;
 86	int num;
 87	struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
 88
 89	status = urb->status;
 90	kfree(urb->transfer_buffer);
 91	usb_free_urb(urb);
 92
 93	if (status == -ESHUTDOWN)
 94		return;
 95
 96	spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
 97	num = --line6->line6midi->num_active_send_urbs;
 98
 99	if (num == 0) {
100		line6_midi_transmit(line6->line6midi->substream_transmit);
101		num = line6->line6midi->num_active_send_urbs;
102	}
103
104	if (num == 0)
105		wake_up(&line6->line6midi->send_wait);
106
107	spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
108}
109
110/*
111	Send an asynchronous MIDI message.
112	Assumes that line6->line6midi->send_urb_lock is held
113	(i.e., this function is serialized).
114*/
115static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
116			   int length)
117{
118	struct urb *urb;
119	int retval;
120	unsigned char *transfer_buffer;
121
122	urb = usb_alloc_urb(0, GFP_ATOMIC);
123
124	if (urb == NULL) {
125		dev_err(line6->ifcdev, "Out of memory\n");
126		return -ENOMEM;
127	}
128
129	transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
130
131	if (transfer_buffer == NULL) {
132		usb_free_urb(urb);
133		dev_err(line6->ifcdev, "Out of memory\n");
134		return -ENOMEM;
135	}
136
137	usb_fill_int_urb(urb, line6->usbdev,
138			 usb_sndbulkpipe(line6->usbdev,
139					 line6->ep_control_write),
140			 transfer_buffer, length, midi_sent, line6,
141			 line6->interval);
142	urb->actual_length = 0;
143	retval = usb_submit_urb(urb, GFP_ATOMIC);
144
145	if (retval < 0) {
146		dev_err(line6->ifcdev, "usb_submit_urb failed\n");
147		usb_free_urb(urb);
148		return retval;
149	}
150
151	++line6->line6midi->num_active_send_urbs;
152	return 0;
153}
154
155static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
156{
157	return 0;
158}
159
160static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
161{
162	return 0;
163}
164
165static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
166				      int up)
167{
168	unsigned long flags;
169	struct usb_line6 *line6 =
170	    line6_rawmidi_substream_midi(substream)->line6;
171
172	line6->line6midi->substream_transmit = substream;
173	spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
174
175	if (line6->line6midi->num_active_send_urbs == 0)
176		line6_midi_transmit(substream);
177
178	spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
179}
180
181static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
182{
183	struct usb_line6 *line6 =
184	    line6_rawmidi_substream_midi(substream)->line6;
185	struct snd_line6_midi *midi = line6->line6midi;
186	wait_event_interruptible(midi->send_wait,
187				 midi->num_active_send_urbs == 0);
188}
189
190static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
191{
192	return 0;
193}
194
195static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
196{
197	return 0;
198}
199
200static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
201				     int up)
202{
203	struct usb_line6 *line6 =
204	    line6_rawmidi_substream_midi(substream)->line6;
205
206	if (up)
207		line6->line6midi->substream_receive = substream;
208	else
209		line6->line6midi->substream_receive = NULL;
210}
211
212static struct snd_rawmidi_ops line6_midi_output_ops = {
213	.open = line6_midi_output_open,
214	.close = line6_midi_output_close,
215	.trigger = line6_midi_output_trigger,
216	.drain = line6_midi_output_drain,
217};
218
219static struct snd_rawmidi_ops line6_midi_input_ops = {
220	.open = line6_midi_input_open,
221	.close = line6_midi_input_close,
222	.trigger = line6_midi_input_trigger,
223};
224
225/*
226	Cleanup the Line6 MIDI device.
227*/
228static void line6_cleanup_midi(struct snd_rawmidi *rmidi)
229{
230}
231
232/* Create a MIDI device */
233static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
234{
235	struct snd_rawmidi *rmidi;
236	int err;
237
238	err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
239			      &rmidi);
240	if (err < 0)
241		return err;
242
243	rmidi->private_data = line6midi;
244	rmidi->private_free = line6_cleanup_midi;
245	strcpy(rmidi->id, line6midi->line6->properties->id);
246	strcpy(rmidi->name, line6midi->line6->properties->name);
247
248	rmidi->info_flags =
249	    SNDRV_RAWMIDI_INFO_OUTPUT |
250	    SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
251
252	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
253			    &line6_midi_output_ops);
254	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
255			    &line6_midi_input_ops);
256	return 0;
257}
258
259/* MIDI device destructor */
260static int snd_line6_midi_free(struct snd_device *device)
261{
262	struct snd_line6_midi *line6midi = device->device_data;
263	line6_midibuf_destroy(&line6midi->midibuf_in);
264	line6_midibuf_destroy(&line6midi->midibuf_out);
265	return 0;
266}
267
268/*
269	Initialize the Line6 MIDI subsystem.
270*/
271int line6_init_midi(struct usb_line6 *line6)
272{
273	static struct snd_device_ops midi_ops = {
274		.dev_free = snd_line6_midi_free,
275	};
276
277	int err;
278	struct snd_line6_midi *line6midi;
279
280	if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) {
281		/* skip MIDI initialization and report success */
282		return 0;
283	}
284
285	line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
286
287	if (line6midi == NULL)
288		return -ENOMEM;
289
290	err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
291	if (err < 0) {
292		kfree(line6midi);
293		return err;
294	}
295
296	err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
297	if (err < 0) {
298		kfree(line6midi->midibuf_in.buf);
299		kfree(line6midi);
300		return err;
301	}
302
303	line6midi->line6 = line6;
304	line6->line6midi = line6midi;
305
306	err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi,
307			     &midi_ops);
308	if (err < 0)
309		return err;
310
311	err = snd_line6_new_midi(line6midi);
312	if (err < 0)
313		return err;
314
315	init_waitqueue_head(&line6midi->send_wait);
316	spin_lock_init(&line6midi->send_urb_lock);
317	spin_lock_init(&line6midi->midi_transmit_lock);
318	return 0;
319}