linux/drivers/staging/line6/midi.c
<<
>>
Prefs
   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 -EINVAL;
 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 = 0;
 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}
 321