Root/drivers/staging/line6/midi.c

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 MidiBuffer *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#ifdef CONFIG_LINE6_USB_DUMP_MIDI
63        line6_write_hexdump(line6, 's', chunk, done);
64#endif
65        line6_midibuf_write(mb, chunk, done);
66        snd_rawmidi_transmit_ack(substream, done);
67    }
68
69    for (;;) {
70        done = line6_midibuf_read(mb, chunk, line6->max_packet_size);
71
72        if (done == 0)
73            break;
74
75        if (line6_midibuf_skip_message
76            (mb, line6midi->midi_mask_transmit))
77            continue;
78
79        send_midi_async(line6, chunk, done);
80    }
81
82    spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags);
83}
84
85/*
86    Notification of completion of MIDI transmission.
87*/
88static void midi_sent(struct urb *urb)
89{
90    unsigned long flags;
91    int status;
92    int num;
93    struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
94
95    status = urb->status;
96    kfree(urb->transfer_buffer);
97    usb_free_urb(urb);
98
99    if (status == -ESHUTDOWN)
100        return;
101
102    spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
103    num = --line6->line6midi->num_active_send_urbs;
104
105    if (num == 0) {
106        line6_midi_transmit(line6->line6midi->substream_transmit);
107        num = line6->line6midi->num_active_send_urbs;
108    }
109
110    if (num == 0)
111        wake_up(&line6->line6midi->send_wait);
112
113    spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
114}
115
116/*
117    Send an asynchronous MIDI message.
118    Assumes that line6->line6midi->send_urb_lock is held
119    (i.e., this function is serialized).
120*/
121static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
122               int length)
123{
124    struct urb *urb;
125    int retval;
126    unsigned char *transfer_buffer;
127
128    urb = usb_alloc_urb(0, GFP_ATOMIC);
129
130    if (urb == NULL) {
131        dev_err(line6->ifcdev, "Out of memory\n");
132        return -ENOMEM;
133    }
134#ifdef CONFIG_LINE6_USB_DUMP_CTRL
135    line6_write_hexdump(line6, 'S', data, length);
136#endif
137
138    transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
139
140    if (transfer_buffer == NULL) {
141        usb_free_urb(urb);
142        dev_err(line6->ifcdev, "Out of memory\n");
143        return -ENOMEM;
144    }
145
146    usb_fill_int_urb(urb, line6->usbdev,
147             usb_sndbulkpipe(line6->usbdev,
148                     line6->ep_control_write),
149             transfer_buffer, length, midi_sent, line6,
150             line6->interval);
151    urb->actual_length = 0;
152    retval = usb_submit_urb(urb, GFP_ATOMIC);
153
154    if (retval < 0) {
155        dev_err(line6->ifcdev, "usb_submit_urb failed\n");
156        usb_free_urb(urb);
157        return -EINVAL;
158    }
159
160    ++line6->line6midi->num_active_send_urbs;
161
162    switch (line6->usbdev->descriptor.idProduct) {
163    case LINE6_DEVID_BASSPODXT:
164    case LINE6_DEVID_BASSPODXTLIVE:
165    case LINE6_DEVID_BASSPODXTPRO:
166    case LINE6_DEVID_PODXT:
167    case LINE6_DEVID_PODXTLIVE:
168    case LINE6_DEVID_PODXTPRO:
169    case LINE6_DEVID_POCKETPOD:
170        line6_pod_midi_postprocess((struct usb_line6_pod *)line6, data,
171                       length);
172        break;
173
174    case LINE6_DEVID_VARIAX:
175    case LINE6_DEVID_PODHD300:
176    case LINE6_DEVID_PODHD500:
177        break;
178
179    default:
180        MISSING_CASE;
181    }
182
183    return 0;
184}
185
186static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
187{
188    return 0;
189}
190
191static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
192{
193    return 0;
194}
195
196static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
197                      int up)
198{
199    unsigned long flags;
200    struct usb_line6 *line6 =
201        line6_rawmidi_substream_midi(substream)->line6;
202
203    line6->line6midi->substream_transmit = substream;
204    spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
205
206    if (line6->line6midi->num_active_send_urbs == 0)
207        line6_midi_transmit(substream);
208
209    spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
210}
211
212static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
213{
214    struct usb_line6 *line6 =
215        line6_rawmidi_substream_midi(substream)->line6;
216    struct snd_line6_midi *midi = line6->line6midi;
217    wait_event_interruptible(midi->send_wait,
218                 midi->num_active_send_urbs == 0);
219}
220
221static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
222{
223    return 0;
224}
225
226static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
227{
228    return 0;
229}
230
231static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
232                     int up)
233{
234    struct usb_line6 *line6 =
235        line6_rawmidi_substream_midi(substream)->line6;
236
237    if (up)
238        line6->line6midi->substream_receive = substream;
239    else
240        line6->line6midi->substream_receive = 0;
241}
242
243static struct snd_rawmidi_ops line6_midi_output_ops = {
244    .open = line6_midi_output_open,
245    .close = line6_midi_output_close,
246    .trigger = line6_midi_output_trigger,
247    .drain = line6_midi_output_drain,
248};
249
250static struct snd_rawmidi_ops line6_midi_input_ops = {
251    .open = line6_midi_input_open,
252    .close = line6_midi_input_close,
253    .trigger = line6_midi_input_trigger,
254};
255
256/*
257    Cleanup the Line6 MIDI device.
258*/
259static void line6_cleanup_midi(struct snd_rawmidi *rmidi)
260{
261}
262
263/* Create a MIDI device */
264static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
265{
266    struct snd_rawmidi *rmidi;
267    int err;
268
269    err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
270                  &rmidi);
271    if (err < 0)
272        return err;
273
274    rmidi->private_data = line6midi;
275    rmidi->private_free = line6_cleanup_midi;
276    strcpy(rmidi->id, line6midi->line6->properties->id);
277    strcpy(rmidi->name, line6midi->line6->properties->name);
278
279    rmidi->info_flags =
280        SNDRV_RAWMIDI_INFO_OUTPUT |
281        SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
282
283    snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
284                &line6_midi_output_ops);
285    snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
286                &line6_midi_input_ops);
287    return 0;
288}
289
290/*
291    "read" request on "midi_mask_transmit" special file.
292*/
293static ssize_t midi_get_midi_mask_transmit(struct device *dev,
294                       struct device_attribute *attr,
295                       char *buf)
296{
297    struct usb_interface *interface = to_usb_interface(dev);
298    struct usb_line6 *line6 = usb_get_intfdata(interface);
299    return sprintf(buf, "%d\n", line6->line6midi->midi_mask_transmit);
300}
301
302/*
303    "write" request on "midi_mask" special file.
304*/
305static ssize_t midi_set_midi_mask_transmit(struct device *dev,
306                       struct device_attribute *attr,
307                       const char *buf, size_t count)
308{
309    struct usb_interface *interface = to_usb_interface(dev);
310    struct usb_line6 *line6 = usb_get_intfdata(interface);
311    unsigned short value;
312    int ret;
313
314    ret = kstrtou16(buf, 10, &value);
315    if (ret)
316        return ret;
317
318    line6->line6midi->midi_mask_transmit = value;
319    return count;
320}
321
322/*
323    "read" request on "midi_mask_receive" special file.
324*/
325static ssize_t midi_get_midi_mask_receive(struct device *dev,
326                      struct device_attribute *attr,
327                      char *buf)
328{
329    struct usb_interface *interface = to_usb_interface(dev);
330    struct usb_line6 *line6 = usb_get_intfdata(interface);
331    return sprintf(buf, "%d\n", line6->line6midi->midi_mask_receive);
332}
333
334/*
335    "write" request on "midi_mask" special file.
336*/
337static ssize_t midi_set_midi_mask_receive(struct device *dev,
338                      struct device_attribute *attr,
339                      const char *buf, size_t count)
340{
341    struct usb_interface *interface = to_usb_interface(dev);
342    struct usb_line6 *line6 = usb_get_intfdata(interface);
343    unsigned short value;
344    int ret;
345
346    ret = kstrtou16(buf, 10, &value);
347    if (ret)
348        return ret;
349
350    line6->line6midi->midi_mask_receive = value;
351    return count;
352}
353
354static DEVICE_ATTR(midi_mask_transmit, S_IWUSR | S_IRUGO,
355           midi_get_midi_mask_transmit, midi_set_midi_mask_transmit);
356static DEVICE_ATTR(midi_mask_receive, S_IWUSR | S_IRUGO,
357           midi_get_midi_mask_receive, midi_set_midi_mask_receive);
358
359/* MIDI device destructor */
360static int snd_line6_midi_free(struct snd_device *device)
361{
362    struct snd_line6_midi *line6midi = device->device_data;
363    device_remove_file(line6midi->line6->ifcdev,
364               &dev_attr_midi_mask_transmit);
365    device_remove_file(line6midi->line6->ifcdev,
366               &dev_attr_midi_mask_receive);
367    line6_midibuf_destroy(&line6midi->midibuf_in);
368    line6_midibuf_destroy(&line6midi->midibuf_out);
369    return 0;
370}
371
372/*
373    Initialize the Line6 MIDI subsystem.
374*/
375int line6_init_midi(struct usb_line6 *line6)
376{
377    static struct snd_device_ops midi_ops = {
378        .dev_free = snd_line6_midi_free,
379    };
380
381    int err;
382    struct snd_line6_midi *line6midi;
383
384    if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) {
385        /* skip MIDI initialization and report success */
386        return 0;
387    }
388
389    line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
390
391    if (line6midi == NULL)
392        return -ENOMEM;
393
394    err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
395    if (err < 0) {
396        kfree(line6midi);
397        return err;
398    }
399
400    err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
401    if (err < 0) {
402        kfree(line6midi->midibuf_in.buf);
403        kfree(line6midi);
404        return err;
405    }
406
407    line6midi->line6 = line6;
408
409    switch (line6->product) {
410    case LINE6_DEVID_PODHD300:
411    case LINE6_DEVID_PODHD500:
412        line6midi->midi_mask_transmit = 1;
413        line6midi->midi_mask_receive = 1;
414        break;
415
416    default:
417        line6midi->midi_mask_transmit = 1;
418        line6midi->midi_mask_receive = 4;
419    }
420
421    line6->line6midi = line6midi;
422
423    err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi,
424                 &midi_ops);
425    if (err < 0)
426        return err;
427
428    snd_card_set_dev(line6->card, line6->ifcdev);
429
430    err = snd_line6_new_midi(line6midi);
431    if (err < 0)
432        return err;
433
434    err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_transmit);
435    if (err < 0)
436        return err;
437
438    err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_receive);
439    if (err < 0)
440        return err;
441
442    init_waitqueue_head(&line6midi->send_wait);
443    spin_lock_init(&line6midi->send_urb_lock);
444    spin_lock_init(&line6midi->midi_transmit_lock);
445    return 0;
446}
447

Archive Download this file



interactive