Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/caiaq/midi.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) 2006,2007 Daniel Mack
4
*/
5
6
#include <linux/device.h>
7
#include <linux/usb.h>
8
#include <linux/gfp.h>
9
#include <sound/rawmidi.h>
10
#include <sound/core.h>
11
#include <sound/pcm.h>
12
13
#include "device.h"
14
#include "midi.h"
15
16
static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream)
17
{
18
return 0;
19
}
20
21
static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream)
22
{
23
return 0;
24
}
25
26
static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
27
{
28
struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
29
30
if (!cdev)
31
return;
32
33
cdev->midi_receive_substream = up ? substream : NULL;
34
}
35
36
37
static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream)
38
{
39
return 0;
40
}
41
42
static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)
43
{
44
struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
45
if (cdev->midi_out_active) {
46
usb_kill_urb(&cdev->midi_out_urb);
47
cdev->midi_out_active = 0;
48
}
49
return 0;
50
}
51
52
static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,
53
struct snd_rawmidi_substream *substream)
54
{
55
int len, ret;
56
struct device *dev = caiaqdev_to_dev(cdev);
57
58
cdev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
59
cdev->midi_out_buf[1] = 0; /* port */
60
len = snd_rawmidi_transmit(substream, cdev->midi_out_buf + 3,
61
EP1_BUFSIZE - 3);
62
63
if (len <= 0)
64
return;
65
66
cdev->midi_out_buf[2] = len;
67
cdev->midi_out_urb.transfer_buffer_length = len+3;
68
69
ret = usb_submit_urb(&cdev->midi_out_urb, GFP_ATOMIC);
70
if (ret < 0)
71
dev_err(dev,
72
"snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
73
"ret=%d, len=%d\n", substream, ret, len);
74
else
75
cdev->midi_out_active = 1;
76
}
77
78
static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
79
{
80
struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
81
82
if (up) {
83
cdev->midi_out_substream = substream;
84
if (!cdev->midi_out_active)
85
snd_usb_caiaq_midi_send(cdev, substream);
86
} else {
87
cdev->midi_out_substream = NULL;
88
}
89
}
90
91
92
static const struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
93
{
94
.open = snd_usb_caiaq_midi_output_open,
95
.close = snd_usb_caiaq_midi_output_close,
96
.trigger = snd_usb_caiaq_midi_output_trigger,
97
};
98
99
static const struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
100
{
101
.open = snd_usb_caiaq_midi_input_open,
102
.close = snd_usb_caiaq_midi_input_close,
103
.trigger = snd_usb_caiaq_midi_input_trigger,
104
};
105
106
void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,
107
int port, const char *buf, int len)
108
{
109
if (!cdev->midi_receive_substream)
110
return;
111
112
snd_rawmidi_receive(cdev->midi_receive_substream, buf, len);
113
}
114
115
int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
116
{
117
int ret;
118
struct snd_rawmidi *rmidi;
119
120
ret = snd_rawmidi_new(device->chip.card, device->product_name, 0,
121
device->spec.num_midi_out,
122
device->spec.num_midi_in,
123
&rmidi);
124
125
if (ret < 0)
126
return ret;
127
128
strscpy(rmidi->name, device->product_name, sizeof(rmidi->name));
129
130
rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
131
rmidi->private_data = device;
132
133
if (device->spec.num_midi_out > 0) {
134
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
135
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
136
&snd_usb_caiaq_midi_output);
137
}
138
139
if (device->spec.num_midi_in > 0) {
140
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
141
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
142
&snd_usb_caiaq_midi_input);
143
}
144
145
device->rmidi = rmidi;
146
147
return 0;
148
}
149
150
void snd_usb_caiaq_midi_output_done(struct urb* urb)
151
{
152
struct snd_usb_caiaqdev *cdev = urb->context;
153
154
cdev->midi_out_active = 0;
155
if (urb->status != 0)
156
return;
157
158
if (!cdev->midi_out_substream)
159
return;
160
161
snd_usb_caiaq_midi_send(cdev, cdev->midi_out_substream);
162
}
163
164