~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to sound/usb/6fire/midi.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Linux driver for TerraTec DMX 6Fire USB
 
3
 *
 
4
 * Rawmidi driver
 
5
 *
 
6
 * Author:      Torsten Schenk <torsten.schenk@zoho.com>
 
7
 * Created:     Jan 01, 2011
 
8
 * Version:     0.3.0
 
9
 * Copyright:   (C) Torsten Schenk
 
10
 *
 
11
 * This program is free software; you can redistribute it and/or modify
 
12
 * it under the terms of the GNU General Public License as published by
 
13
 * the Free Software Foundation; either version 2 of the License, or
 
14
 * (at your option) any later version.
 
15
 */
 
16
 
 
17
#include <sound/rawmidi.h>
 
18
 
 
19
#include "midi.h"
 
20
#include "chip.h"
 
21
#include "comm.h"
 
22
 
 
23
static void usb6fire_midi_out_handler(struct urb *urb)
 
24
{
 
25
        struct midi_runtime *rt = urb->context;
 
26
        int ret;
 
27
        unsigned long flags;
 
28
 
 
29
        spin_lock_irqsave(&rt->out_lock, flags);
 
30
 
 
31
        if (rt->out) {
 
32
                ret = snd_rawmidi_transmit(rt->out, rt->out_buffer + 4,
 
33
                                MIDI_BUFSIZE - 4);
 
34
                if (ret > 0) { /* more data available, send next packet */
 
35
                        rt->out_buffer[1] = ret + 2;
 
36
                        rt->out_buffer[3] = rt->out_serial++;
 
37
                        urb->transfer_buffer_length = ret + 4;
 
38
 
 
39
                        ret = usb_submit_urb(urb, GFP_ATOMIC);
 
40
                        if (ret < 0)
 
41
                                snd_printk(KERN_ERR PREFIX "midi out urb "
 
42
                                                "submit failed: %d\n", ret);
 
43
                } else /* no more data to transmit */
 
44
                        rt->out = NULL;
 
45
        }
 
46
        spin_unlock_irqrestore(&rt->out_lock, flags);
 
47
}
 
48
 
 
49
static void usb6fire_midi_in_received(
 
50
                struct midi_runtime *rt, u8 *data, int length)
 
51
{
 
52
        unsigned long flags;
 
53
 
 
54
        spin_lock_irqsave(&rt->in_lock, flags);
 
55
        if (rt->in)
 
56
                snd_rawmidi_receive(rt->in, data, length);
 
57
        spin_unlock_irqrestore(&rt->in_lock, flags);
 
58
}
 
59
 
 
60
static int usb6fire_midi_out_open(struct snd_rawmidi_substream *alsa_sub)
 
61
{
 
62
        return 0;
 
63
}
 
64
 
 
65
static int usb6fire_midi_out_close(struct snd_rawmidi_substream *alsa_sub)
 
66
{
 
67
        return 0;
 
68
}
 
69
 
 
70
static void usb6fire_midi_out_trigger(
 
71
                struct snd_rawmidi_substream *alsa_sub, int up)
 
72
{
 
73
        struct midi_runtime *rt = alsa_sub->rmidi->private_data;
 
74
        struct urb *urb = &rt->out_urb;
 
75
        __s8 ret;
 
76
        unsigned long flags;
 
77
 
 
78
        spin_lock_irqsave(&rt->out_lock, flags);
 
79
        if (up) { /* start transfer */
 
80
                if (rt->out) { /* we are already transmitting so just return */
 
81
                        spin_unlock_irqrestore(&rt->out_lock, flags);
 
82
                        return;
 
83
                }
 
84
 
 
85
                ret = snd_rawmidi_transmit(alsa_sub, rt->out_buffer + 4,
 
86
                                MIDI_BUFSIZE - 4);
 
87
                if (ret > 0) {
 
88
                        rt->out_buffer[1] = ret + 2;
 
89
                        rt->out_buffer[3] = rt->out_serial++;
 
90
                        urb->transfer_buffer_length = ret + 4;
 
91
 
 
92
                        ret = usb_submit_urb(urb, GFP_ATOMIC);
 
93
                        if (ret < 0)
 
94
                                snd_printk(KERN_ERR PREFIX "midi out urb "
 
95
                                                "submit failed: %d\n", ret);
 
96
                        else
 
97
                                rt->out = alsa_sub;
 
98
                }
 
99
        } else if (rt->out == alsa_sub)
 
100
                rt->out = NULL;
 
101
        spin_unlock_irqrestore(&rt->out_lock, flags);
 
102
}
 
103
 
 
104
static void usb6fire_midi_out_drain(struct snd_rawmidi_substream *alsa_sub)
 
105
{
 
106
        struct midi_runtime *rt = alsa_sub->rmidi->private_data;
 
107
        int retry = 0;
 
108
 
 
109
        while (rt->out && retry++ < 100)
 
110
                msleep(10);
 
111
}
 
112
 
 
113
static int usb6fire_midi_in_open(struct snd_rawmidi_substream *alsa_sub)
 
114
{
 
115
        return 0;
 
116
}
 
117
 
 
118
static int usb6fire_midi_in_close(struct snd_rawmidi_substream *alsa_sub)
 
119
{
 
120
        return 0;
 
121
}
 
122
 
 
123
static void usb6fire_midi_in_trigger(
 
124
                struct snd_rawmidi_substream *alsa_sub, int up)
 
125
{
 
126
        struct midi_runtime *rt = alsa_sub->rmidi->private_data;
 
127
        unsigned long flags;
 
128
 
 
129
        spin_lock_irqsave(&rt->in_lock, flags);
 
130
        if (up)
 
131
                rt->in = alsa_sub;
 
132
        else
 
133
                rt->in = NULL;
 
134
        spin_unlock_irqrestore(&rt->in_lock, flags);
 
135
}
 
136
 
 
137
static struct snd_rawmidi_ops out_ops = {
 
138
        .open = usb6fire_midi_out_open,
 
139
        .close = usb6fire_midi_out_close,
 
140
        .trigger = usb6fire_midi_out_trigger,
 
141
        .drain = usb6fire_midi_out_drain
 
142
};
 
143
 
 
144
static struct snd_rawmidi_ops in_ops = {
 
145
        .open = usb6fire_midi_in_open,
 
146
        .close = usb6fire_midi_in_close,
 
147
        .trigger = usb6fire_midi_in_trigger
 
148
};
 
149
 
 
150
int __devinit usb6fire_midi_init(struct sfire_chip *chip)
 
151
{
 
152
        int ret;
 
153
        struct midi_runtime *rt = kzalloc(sizeof(struct midi_runtime),
 
154
                        GFP_KERNEL);
 
155
        struct comm_runtime *comm_rt = chip->comm;
 
156
 
 
157
        if (!rt)
 
158
                return -ENOMEM;
 
159
 
 
160
        rt->chip = chip;
 
161
        rt->in_received = usb6fire_midi_in_received;
 
162
        rt->out_buffer[0] = 0x80; /* 'send midi' command */
 
163
        rt->out_buffer[1] = 0x00; /* size of data */
 
164
        rt->out_buffer[2] = 0x00; /* always 0 */
 
165
        spin_lock_init(&rt->in_lock);
 
166
        spin_lock_init(&rt->out_lock);
 
167
 
 
168
        comm_rt->init_urb(comm_rt, &rt->out_urb, rt->out_buffer, rt,
 
169
                        usb6fire_midi_out_handler);
 
170
 
 
171
        ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance);
 
172
        if (ret < 0) {
 
173
                kfree(rt);
 
174
                snd_printk(KERN_ERR PREFIX "unable to create midi.\n");
 
175
                return ret;
 
176
        }
 
177
        rt->instance->private_data = rt;
 
178
        strcpy(rt->instance->name, "DMX6FireUSB MIDI");
 
179
        rt->instance->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
 
180
                        SNDRV_RAWMIDI_INFO_INPUT |
 
181
                        SNDRV_RAWMIDI_INFO_DUPLEX;
 
182
        snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_OUTPUT,
 
183
                        &out_ops);
 
184
        snd_rawmidi_set_ops(rt->instance, SNDRV_RAWMIDI_STREAM_INPUT,
 
185
                        &in_ops);
 
186
 
 
187
        chip->midi = rt;
 
188
        return 0;
 
189
}
 
190
 
 
191
void usb6fire_midi_abort(struct sfire_chip *chip)
 
192
{
 
193
        struct midi_runtime *rt = chip->midi;
 
194
 
 
195
        if (rt)
 
196
                usb_poison_urb(&rt->out_urb);
 
197
}
 
198
 
 
199
void usb6fire_midi_destroy(struct sfire_chip *chip)
 
200
{
 
201
        kfree(chip->midi);
 
202
        chip->midi = NULL;
 
203
}