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