Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.14-rc2 320 lines 7.7 kB view raw
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->max_packet_size]; 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, line6->max_packet_size); 68 69 if (done == 0) 70 break; 71 72 send_midi_async(line6, chunk, done); 73 } 74 75 spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags); 76} 77 78/* 79 Notification of completion of MIDI transmission. 80*/ 81static void midi_sent(struct urb *urb) 82{ 83 unsigned long flags; 84 int status; 85 int num; 86 struct usb_line6 *line6 = (struct usb_line6 *)urb->context; 87 88 status = urb->status; 89 kfree(urb->transfer_buffer); 90 usb_free_urb(urb); 91 92 if (status == -ESHUTDOWN) 93 return; 94 95 spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); 96 num = --line6->line6midi->num_active_send_urbs; 97 98 if (num == 0) { 99 line6_midi_transmit(line6->line6midi->substream_transmit); 100 num = line6->line6midi->num_active_send_urbs; 101 } 102 103 if (num == 0) 104 wake_up(&line6->line6midi->send_wait); 105 106 spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); 107} 108 109/* 110 Send an asynchronous MIDI message. 111 Assumes that line6->line6midi->send_urb_lock is held 112 (i.e., this function is serialized). 113*/ 114static int send_midi_async(struct usb_line6 *line6, unsigned char *data, 115 int length) 116{ 117 struct urb *urb; 118 int retval; 119 unsigned char *transfer_buffer; 120 121 urb = usb_alloc_urb(0, GFP_ATOMIC); 122 123 if (urb == NULL) { 124 dev_err(line6->ifcdev, "Out of memory\n"); 125 return -ENOMEM; 126 } 127 128 transfer_buffer = kmemdup(data, length, GFP_ATOMIC); 129 130 if (transfer_buffer == NULL) { 131 usb_free_urb(urb); 132 dev_err(line6->ifcdev, "Out of memory\n"); 133 return -ENOMEM; 134 } 135 136 usb_fill_int_urb(urb, line6->usbdev, 137 usb_sndbulkpipe(line6->usbdev, 138 line6->ep_control_write), 139 transfer_buffer, length, midi_sent, line6, 140 line6->interval); 141 urb->actual_length = 0; 142 retval = usb_submit_urb(urb, GFP_ATOMIC); 143 144 if (retval < 0) { 145 dev_err(line6->ifcdev, "usb_submit_urb failed\n"); 146 usb_free_urb(urb); 147 return retval; 148 } 149 150 ++line6->line6midi->num_active_send_urbs; 151 return 0; 152} 153 154static int line6_midi_output_open(struct snd_rawmidi_substream *substream) 155{ 156 return 0; 157} 158 159static int line6_midi_output_close(struct snd_rawmidi_substream *substream) 160{ 161 return 0; 162} 163 164static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, 165 int up) 166{ 167 unsigned long flags; 168 struct usb_line6 *line6 = 169 line6_rawmidi_substream_midi(substream)->line6; 170 171 line6->line6midi->substream_transmit = substream; 172 spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); 173 174 if (line6->line6midi->num_active_send_urbs == 0) 175 line6_midi_transmit(substream); 176 177 spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); 178} 179 180static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) 181{ 182 struct usb_line6 *line6 = 183 line6_rawmidi_substream_midi(substream)->line6; 184 struct snd_line6_midi *midi = line6->line6midi; 185 wait_event_interruptible(midi->send_wait, 186 midi->num_active_send_urbs == 0); 187} 188 189static int line6_midi_input_open(struct snd_rawmidi_substream *substream) 190{ 191 return 0; 192} 193 194static int line6_midi_input_close(struct snd_rawmidi_substream *substream) 195{ 196 return 0; 197} 198 199static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, 200 int up) 201{ 202 struct usb_line6 *line6 = 203 line6_rawmidi_substream_midi(substream)->line6; 204 205 if (up) 206 line6->line6midi->substream_receive = substream; 207 else 208 line6->line6midi->substream_receive = NULL; 209} 210 211static struct snd_rawmidi_ops line6_midi_output_ops = { 212 .open = line6_midi_output_open, 213 .close = line6_midi_output_close, 214 .trigger = line6_midi_output_trigger, 215 .drain = line6_midi_output_drain, 216}; 217 218static struct snd_rawmidi_ops line6_midi_input_ops = { 219 .open = line6_midi_input_open, 220 .close = line6_midi_input_close, 221 .trigger = line6_midi_input_trigger, 222}; 223 224/* 225 Cleanup the Line6 MIDI device. 226*/ 227static void line6_cleanup_midi(struct snd_rawmidi *rmidi) 228{ 229} 230 231/* Create a MIDI device */ 232static int snd_line6_new_midi(struct snd_line6_midi *line6midi) 233{ 234 struct snd_rawmidi *rmidi; 235 int err; 236 237 err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, 238 &rmidi); 239 if (err < 0) 240 return err; 241 242 rmidi->private_data = line6midi; 243 rmidi->private_free = line6_cleanup_midi; 244 strcpy(rmidi->id, line6midi->line6->properties->id); 245 strcpy(rmidi->name, line6midi->line6->properties->name); 246 247 rmidi->info_flags = 248 SNDRV_RAWMIDI_INFO_OUTPUT | 249 SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; 250 251 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 252 &line6_midi_output_ops); 253 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 254 &line6_midi_input_ops); 255 return 0; 256} 257 258/* MIDI device destructor */ 259static int snd_line6_midi_free(struct snd_device *device) 260{ 261 struct snd_line6_midi *line6midi = device->device_data; 262 line6_midibuf_destroy(&line6midi->midibuf_in); 263 line6_midibuf_destroy(&line6midi->midibuf_out); 264 return 0; 265} 266 267/* 268 Initialize the Line6 MIDI subsystem. 269*/ 270int line6_init_midi(struct usb_line6 *line6) 271{ 272 static struct snd_device_ops midi_ops = { 273 .dev_free = snd_line6_midi_free, 274 }; 275 276 int err; 277 struct snd_line6_midi *line6midi; 278 279 if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) { 280 /* skip MIDI initialization and report success */ 281 return 0; 282 } 283 284 line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); 285 286 if (line6midi == NULL) 287 return -ENOMEM; 288 289 err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); 290 if (err < 0) { 291 kfree(line6midi); 292 return err; 293 } 294 295 err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); 296 if (err < 0) { 297 kfree(line6midi->midibuf_in.buf); 298 kfree(line6midi); 299 return err; 300 } 301 302 line6midi->line6 = line6; 303 line6->line6midi = line6midi; 304 305 err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, 306 &midi_ops); 307 if (err < 0) 308 return err; 309 310 snd_card_set_dev(line6->card, line6->ifcdev); 311 312 err = snd_line6_new_midi(line6midi); 313 if (err < 0) 314 return err; 315 316 init_waitqueue_head(&line6midi->send_wait); 317 spin_lock_init(&line6midi->send_urb_lock); 318 spin_lock_init(&line6midi->midi_transmit_lock); 319 return 0; 320}