Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / sound / usb / caiaq / midi.c
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         strlcpy(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 }