1 // SPDX-License-Identifier: GPL-2.0-only
3 * Line 6 Linux USB driver
5 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
8 #include <linux/slab.h>
10 #include <linux/export.h>
11 #include <sound/core.h>
12 #include <sound/rawmidi.h>
17 #define line6_rawmidi_substream_midi(substream) \
18 ((struct snd_line6_midi *)((substream)->rmidi->private_data))
20 static int send_midi_async(struct usb_line6
*line6
, unsigned char *data
,
24 Pass data received via USB to MIDI.
26 void line6_midi_receive(struct usb_line6
*line6
, unsigned char *data
,
29 if (line6
->line6midi
->substream_receive
)
30 snd_rawmidi_receive(line6
->line6midi
->substream_receive
,
35 Read data from MIDI buffer and transmit them via USB.
37 static void line6_midi_transmit(struct snd_rawmidi_substream
*substream
)
39 struct usb_line6
*line6
=
40 line6_rawmidi_substream_midi(substream
)->line6
;
41 struct snd_line6_midi
*line6midi
= line6
->line6midi
;
42 struct midi_buffer
*mb
= &line6midi
->midibuf_out
;
43 unsigned char chunk
[LINE6_FALLBACK_MAXPACKETSIZE
];
47 req
= min(line6_midibuf_bytes_free(mb
), line6
->max_packet_size
);
48 done
= snd_rawmidi_transmit_peek(substream
, chunk
, req
);
53 line6_midibuf_write(mb
, chunk
, done
);
54 snd_rawmidi_transmit_ack(substream
, done
);
58 done
= line6_midibuf_read(mb
, chunk
,
59 LINE6_FALLBACK_MAXPACKETSIZE
);
64 send_midi_async(line6
, chunk
, done
);
69 Notification of completion of MIDI transmission.
71 static void midi_sent(struct urb
*urb
)
76 struct usb_line6
*line6
= (struct usb_line6
*)urb
->context
;
79 kfree(urb
->transfer_buffer
);
82 if (status
== -ESHUTDOWN
)
85 spin_lock_irqsave(&line6
->line6midi
->lock
, flags
);
86 num
= --line6
->line6midi
->num_active_send_urbs
;
89 line6_midi_transmit(line6
->line6midi
->substream_transmit
);
90 num
= line6
->line6midi
->num_active_send_urbs
;
94 wake_up(&line6
->line6midi
->send_wait
);
96 spin_unlock_irqrestore(&line6
->line6midi
->lock
, flags
);
100 Send an asynchronous MIDI message.
101 Assumes that line6->line6midi->lock is held
102 (i.e., this function is serialized).
104 static int send_midi_async(struct usb_line6
*line6
, unsigned char *data
,
109 unsigned char *transfer_buffer
;
111 urb
= usb_alloc_urb(0, GFP_ATOMIC
);
116 transfer_buffer
= kmemdup(data
, length
, GFP_ATOMIC
);
118 if (transfer_buffer
== NULL
) {
123 usb_fill_int_urb(urb
, line6
->usbdev
,
124 usb_sndintpipe(line6
->usbdev
,
125 line6
->properties
->ep_ctrl_w
),
126 transfer_buffer
, length
, midi_sent
, line6
,
128 urb
->actual_length
= 0;
129 retval
= usb_urb_ep_type_check(urb
);
133 retval
= usb_submit_urb(urb
, GFP_ATOMIC
);
137 ++line6
->line6midi
->num_active_send_urbs
;
141 dev_err(line6
->ifcdev
, "usb_submit_urb failed\n");
146 static int line6_midi_output_open(struct snd_rawmidi_substream
*substream
)
151 static int line6_midi_output_close(struct snd_rawmidi_substream
*substream
)
156 static void line6_midi_output_trigger(struct snd_rawmidi_substream
*substream
,
160 struct usb_line6
*line6
=
161 line6_rawmidi_substream_midi(substream
)->line6
;
163 line6
->line6midi
->substream_transmit
= substream
;
164 spin_lock_irqsave(&line6
->line6midi
->lock
, flags
);
166 if (line6
->line6midi
->num_active_send_urbs
== 0)
167 line6_midi_transmit(substream
);
169 spin_unlock_irqrestore(&line6
->line6midi
->lock
, flags
);
172 static void line6_midi_output_drain(struct snd_rawmidi_substream
*substream
)
174 struct usb_line6
*line6
=
175 line6_rawmidi_substream_midi(substream
)->line6
;
176 struct snd_line6_midi
*midi
= line6
->line6midi
;
178 wait_event_interruptible(midi
->send_wait
,
179 midi
->num_active_send_urbs
== 0);
182 static int line6_midi_input_open(struct snd_rawmidi_substream
*substream
)
187 static int line6_midi_input_close(struct snd_rawmidi_substream
*substream
)
192 static void line6_midi_input_trigger(struct snd_rawmidi_substream
*substream
,
195 struct usb_line6
*line6
=
196 line6_rawmidi_substream_midi(substream
)->line6
;
199 line6
->line6midi
->substream_receive
= substream
;
201 line6
->line6midi
->substream_receive
= NULL
;
204 static const struct snd_rawmidi_ops line6_midi_output_ops
= {
205 .open
= line6_midi_output_open
,
206 .close
= line6_midi_output_close
,
207 .trigger
= line6_midi_output_trigger
,
208 .drain
= line6_midi_output_drain
,
211 static const struct snd_rawmidi_ops line6_midi_input_ops
= {
212 .open
= line6_midi_input_open
,
213 .close
= line6_midi_input_close
,
214 .trigger
= line6_midi_input_trigger
,
217 /* Create a MIDI device */
218 static int snd_line6_new_midi(struct usb_line6
*line6
,
219 struct snd_rawmidi
**rmidi_ret
)
221 struct snd_rawmidi
*rmidi
;
224 err
= snd_rawmidi_new(line6
->card
, "Line 6 MIDI", 0, 1, 1, rmidi_ret
);
229 strcpy(rmidi
->id
, line6
->properties
->id
);
230 strcpy(rmidi
->name
, line6
->properties
->name
);
233 SNDRV_RAWMIDI_INFO_OUTPUT
|
234 SNDRV_RAWMIDI_INFO_INPUT
| SNDRV_RAWMIDI_INFO_DUPLEX
;
236 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_OUTPUT
,
237 &line6_midi_output_ops
);
238 snd_rawmidi_set_ops(rmidi
, SNDRV_RAWMIDI_STREAM_INPUT
,
239 &line6_midi_input_ops
);
243 /* MIDI device destructor */
244 static void snd_line6_midi_free(struct snd_rawmidi
*rmidi
)
246 struct snd_line6_midi
*line6midi
= rmidi
->private_data
;
248 line6_midibuf_destroy(&line6midi
->midibuf_in
);
249 line6_midibuf_destroy(&line6midi
->midibuf_out
);
254 Initialize the Line 6 MIDI subsystem.
256 int line6_init_midi(struct usb_line6
*line6
)
259 struct snd_rawmidi
*rmidi
;
260 struct snd_line6_midi
*line6midi
;
262 if (!(line6
->properties
->capabilities
& LINE6_CAP_CONTROL_MIDI
)) {
263 /* skip MIDI initialization and report success */
267 err
= snd_line6_new_midi(line6
, &rmidi
);
271 line6midi
= kzalloc(sizeof(struct snd_line6_midi
), GFP_KERNEL
);
275 rmidi
->private_data
= line6midi
;
276 rmidi
->private_free
= snd_line6_midi_free
;
278 init_waitqueue_head(&line6midi
->send_wait
);
279 spin_lock_init(&line6midi
->lock
);
280 line6midi
->line6
= line6
;
282 err
= line6_midibuf_init(&line6midi
->midibuf_in
, MIDI_BUFFER_SIZE
, 0);
286 err
= line6_midibuf_init(&line6midi
->midibuf_out
, MIDI_BUFFER_SIZE
, 1);
290 line6
->line6midi
= line6midi
;
293 EXPORT_SYMBOL_GPL(line6_init_midi
);