Commit | Line | Data |
---|---|---|
705ececd | 1 | /* |
e1a164d7 | 2 | * Line6 Linux USB driver - 0.9.1beta |
705ececd | 3 | * |
1027f476 | 4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
705ececd MG |
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 | ||
5a0e3ad6 | 12 | #include <linux/slab.h> |
1027f476 | 13 | #include <linux/usb.h> |
705ececd MG |
14 | #include <sound/core.h> |
15 | #include <sound/rawmidi.h> | |
16 | ||
17 | #include "audio.h" | |
1027f476 | 18 | #include "driver.h" |
705ececd MG |
19 | #include "midi.h" |
20 | #include "pod.h" | |
21 | #include "usbdefs.h" | |
22 | ||
d7e37336 GKH |
23 | #define line6_rawmidi_substream_midi(substream) \ |
24 | ((struct snd_line6_midi *)((substream)->rmidi->private_data)) | |
705ececd | 25 | |
d7e37336 GKH |
26 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, |
27 | int length); | |
705ececd | 28 | |
705ececd MG |
29 | /* |
30 | Pass data received via USB to MIDI. | |
31 | */ | |
d7e37336 GKH |
32 | void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, |
33 | int length) | |
705ececd | 34 | { |
d7e37336 GKH |
35 | if (line6->line6midi->substream_receive) |
36 | snd_rawmidi_receive(line6->line6midi->substream_receive, | |
37 | data, length); | |
705ececd MG |
38 | } |
39 | ||
40 | /* | |
41 | Read data from MIDI buffer and transmit them via USB. | |
42 | */ | |
43 | static void line6_midi_transmit(struct snd_rawmidi_substream *substream) | |
44 | { | |
e1a164d7 MG |
45 | struct usb_line6 *line6 = |
46 | line6_rawmidi_substream_midi(substream)->line6; | |
705ececd MG |
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 | ||
d7e37336 | 55 | for (;;) { |
1027f476 | 56 | req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); |
705ececd MG |
57 | done = snd_rawmidi_transmit_peek(substream, chunk, req); |
58 | ||
d7e37336 | 59 | if (done == 0) |
705ececd MG |
60 | break; |
61 | ||
1027f476 | 62 | #ifdef CONFIG_LINE6_USB_DUMP_MIDI |
705ececd MG |
63 | line6_write_hexdump(line6, 's', chunk, done); |
64 | #endif | |
1027f476 | 65 | line6_midibuf_write(mb, chunk, done); |
705ececd MG |
66 | snd_rawmidi_transmit_ack(substream, done); |
67 | } | |
68 | ||
d7e37336 | 69 | for (;;) { |
1027f476 | 70 | done = line6_midibuf_read(mb, chunk, line6->max_packet_size); |
705ececd | 71 | |
d7e37336 | 72 | if (done == 0) |
705ececd MG |
73 | break; |
74 | ||
e1a164d7 MG |
75 | if (line6_midibuf_skip_message |
76 | (mb, line6midi->midi_mask_transmit)) | |
705ececd MG |
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 | */ | |
0c7ab158 | 88 | static void midi_sent(struct urb *urb) |
705ececd MG |
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 | ||
d7e37336 | 99 | if (status == -ESHUTDOWN) |
705ececd MG |
100 | return; |
101 | ||
102 | spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); | |
103 | num = --line6->line6midi->num_active_send_urbs; | |
104 | ||
d7e37336 | 105 | if (num == 0) { |
705ececd MG |
106 | line6_midi_transmit(line6->line6midi->substream_transmit); |
107 | num = line6->line6midi->num_active_send_urbs; | |
108 | } | |
109 | ||
d7e37336 | 110 | if (num == 0) |
1027f476 | 111 | wake_up(&line6->line6midi->send_wait); |
705ececd MG |
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 | */ | |
d7e37336 GKH |
121 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, |
122 | int length) | |
705ececd MG |
123 | { |
124 | struct urb *urb; | |
125 | int retval; | |
126 | unsigned char *transfer_buffer; | |
127 | ||
128 | urb = usb_alloc_urb(0, GFP_ATOMIC); | |
129 | ||
597a1e7c | 130 | if (urb == NULL) { |
705ececd MG |
131 | dev_err(line6->ifcdev, "Out of memory\n"); |
132 | return -ENOMEM; | |
133 | } | |
1027f476 | 134 | #ifdef CONFIG_LINE6_USB_DUMP_CTRL |
705ececd MG |
135 | line6_write_hexdump(line6, 'S', data, length); |
136 | #endif | |
137 | ||
cff86387 | 138 | transfer_buffer = kmemdup(data, length, GFP_ATOMIC); |
705ececd | 139 | |
597a1e7c | 140 | if (transfer_buffer == NULL) { |
705ececd MG |
141 | usb_free_urb(urb); |
142 | dev_err(line6->ifcdev, "Out of memory\n"); | |
143 | return -ENOMEM; | |
144 | } | |
145 | ||
d7e37336 GKH |
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); | |
705ececd MG |
151 | urb->actual_length = 0; |
152 | retval = usb_submit_urb(urb, GFP_ATOMIC); | |
153 | ||
d7e37336 | 154 | if (retval < 0) { |
705ececd MG |
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 | ||
d7e37336 | 162 | switch (line6->usbdev->descriptor.idProduct) { |
705ececd MG |
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: | |
1027f476 MG |
170 | line6_pod_midi_postprocess((struct usb_line6_pod *)line6, data, |
171 | length); | |
705ececd MG |
172 | break; |
173 | ||
e1a164d7 | 174 | case LINE6_DEVID_VARIAX: |
1dc403ff | 175 | case LINE6_DEVID_PODHD300: |
4c6fb5fc | 176 | case LINE6_DEVID_PODHD500: |
e1a164d7 MG |
177 | break; |
178 | ||
705ececd MG |
179 | default: |
180 | MISSING_CASE; | |
181 | } | |
182 | ||
183 | return 0; | |
184 | } | |
185 | ||
186 | static int line6_midi_output_open(struct snd_rawmidi_substream *substream) | |
187 | { | |
188 | return 0; | |
189 | } | |
190 | ||
191 | static int line6_midi_output_close(struct snd_rawmidi_substream *substream) | |
192 | { | |
193 | return 0; | |
194 | } | |
195 | ||
d7e37336 GKH |
196 | static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, |
197 | int up) | |
705ececd MG |
198 | { |
199 | unsigned long flags; | |
e1a164d7 MG |
200 | struct usb_line6 *line6 = |
201 | line6_rawmidi_substream_midi(substream)->line6; | |
705ececd MG |
202 | |
203 | line6->line6midi->substream_transmit = substream; | |
204 | spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); | |
205 | ||
d7e37336 | 206 | if (line6->line6midi->num_active_send_urbs == 0) |
705ececd MG |
207 | line6_midi_transmit(substream); |
208 | ||
209 | spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); | |
210 | } | |
211 | ||
212 | static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) | |
213 | { | |
e1a164d7 MG |
214 | struct usb_line6 *line6 = |
215 | line6_rawmidi_substream_midi(substream)->line6; | |
1027f476 | 216 | struct snd_line6_midi *midi = line6->line6midi; |
e1a164d7 MG |
217 | wait_event_interruptible(midi->send_wait, |
218 | midi->num_active_send_urbs == 0); | |
705ececd MG |
219 | } |
220 | ||
221 | static int line6_midi_input_open(struct snd_rawmidi_substream *substream) | |
222 | { | |
223 | return 0; | |
224 | } | |
225 | ||
226 | static int line6_midi_input_close(struct snd_rawmidi_substream *substream) | |
227 | { | |
228 | return 0; | |
229 | } | |
230 | ||
d7e37336 GKH |
231 | static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, |
232 | int up) | |
705ececd | 233 | { |
e1a164d7 MG |
234 | struct usb_line6 *line6 = |
235 | line6_rawmidi_substream_midi(substream)->line6; | |
705ececd | 236 | |
d7e37336 | 237 | if (up) |
705ececd MG |
238 | line6->line6midi->substream_receive = substream; |
239 | else | |
240 | line6->line6midi->substream_receive = 0; | |
241 | } | |
242 | ||
243 | static 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 | ||
250 | static 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 | */ | |
259 | static void line6_cleanup_midi(struct snd_rawmidi *rmidi) | |
260 | { | |
261 | } | |
262 | ||
263 | /* Create a MIDI device */ | |
264 | static int snd_line6_new_midi(struct snd_line6_midi *line6midi) | |
265 | { | |
266 | struct snd_rawmidi *rmidi; | |
267 | int err; | |
268 | ||
d7e37336 GKH |
269 | err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, |
270 | &rmidi); | |
271 | if (err < 0) | |
705ececd MG |
272 | return err; |
273 | ||
274 | rmidi->private_data = line6midi; | |
275 | rmidi->private_free = line6_cleanup_midi; | |
1027f476 | 276 | strcpy(rmidi->id, line6midi->line6->properties->id); |
705ececd MG |
277 | strcpy(rmidi->name, line6midi->line6->properties->name); |
278 | ||
279 | rmidi->info_flags = | |
e1a164d7 MG |
280 | SNDRV_RAWMIDI_INFO_OUTPUT | |
281 | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; | |
705ececd | 282 | |
d7e37336 GKH |
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); | |
705ececd MG |
287 | return 0; |
288 | } | |
289 | ||
290 | /* | |
291 | "read" request on "midi_mask_transmit" special file. | |
292 | */ | |
77491e52 GKH |
293 | static ssize_t midi_get_midi_mask_transmit(struct device *dev, |
294 | struct device_attribute *attr, | |
295 | char *buf) | |
705ececd MG |
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 | */ | |
77491e52 GKH |
305 | static ssize_t midi_set_midi_mask_transmit(struct device *dev, |
306 | struct device_attribute *attr, | |
307 | const char *buf, size_t count) | |
705ececd MG |
308 | { |
309 | struct usb_interface *interface = to_usb_interface(dev); | |
310 | struct usb_line6 *line6 = usb_get_intfdata(interface); | |
4d85fae0 | 311 | unsigned short value; |
334a33d8 SB |
312 | int ret; |
313 | ||
4d85fae0 | 314 | ret = kstrtou16(buf, 10, &value); |
334a33d8 SB |
315 | if (ret) |
316 | return ret; | |
317 | ||
705ececd MG |
318 | line6->line6midi->midi_mask_transmit = value; |
319 | return count; | |
320 | } | |
321 | ||
322 | /* | |
323 | "read" request on "midi_mask_receive" special file. | |
324 | */ | |
77491e52 GKH |
325 | static ssize_t midi_get_midi_mask_receive(struct device *dev, |
326 | struct device_attribute *attr, | |
327 | char *buf) | |
705ececd MG |
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 | */ | |
77491e52 GKH |
337 | static ssize_t midi_set_midi_mask_receive(struct device *dev, |
338 | struct device_attribute *attr, | |
339 | const char *buf, size_t count) | |
705ececd MG |
340 | { |
341 | struct usb_interface *interface = to_usb_interface(dev); | |
342 | struct usb_line6 *line6 = usb_get_intfdata(interface); | |
251c3948 | 343 | unsigned short value; |
334a33d8 SB |
344 | int ret; |
345 | ||
251c3948 | 346 | ret = kstrtou16(buf, 10, &value); |
334a33d8 SB |
347 | if (ret) |
348 | return ret; | |
349 | ||
705ececd MG |
350 | line6->line6midi->midi_mask_receive = value; |
351 | return count; | |
352 | } | |
353 | ||
a3a972a0 | 354 | static DEVICE_ATTR(midi_mask_transmit, S_IWUSR | S_IRUGO, |
e1a164d7 | 355 | midi_get_midi_mask_transmit, midi_set_midi_mask_transmit); |
a3a972a0 | 356 | static DEVICE_ATTR(midi_mask_receive, S_IWUSR | S_IRUGO, |
e1a164d7 | 357 | midi_get_midi_mask_receive, midi_set_midi_mask_receive); |
705ececd MG |
358 | |
359 | /* MIDI device destructor */ | |
360 | static int snd_line6_midi_free(struct snd_device *device) | |
361 | { | |
362 | struct snd_line6_midi *line6midi = device->device_data; | |
e1a164d7 MG |
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); | |
1027f476 MG |
367 | line6_midibuf_destroy(&line6midi->midibuf_in); |
368 | line6_midibuf_destroy(&line6midi->midibuf_out); | |
705ececd MG |
369 | return 0; |
370 | } | |
371 | ||
372 | /* | |
373 | Initialize the Line6 MIDI subsystem. | |
374 | */ | |
375 | int 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 | ||
027360c5 GKH |
384 | if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) { |
385 | /* skip MIDI initialization and report success */ | |
386 | return 0; | |
387 | } | |
705ececd MG |
388 | |
389 | line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); | |
390 | ||
d7e37336 | 391 | if (line6midi == NULL) |
705ececd MG |
392 | return -ENOMEM; |
393 | ||
1027f476 | 394 | err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); |
982d6ab5 JJ |
395 | if (err < 0) { |
396 | kfree(line6midi); | |
705ececd | 397 | return err; |
982d6ab5 | 398 | } |
705ececd | 399 | |
1027f476 | 400 | err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); |
982d6ab5 JJ |
401 | if (err < 0) { |
402 | kfree(line6midi->midibuf_in.buf); | |
403 | kfree(line6midi); | |
705ececd | 404 | return err; |
982d6ab5 | 405 | } |
705ececd MG |
406 | |
407 | line6midi->line6 = line6; | |
4c6fb5fc | 408 | |
bc8fa144 | 409 | switch (line6->product) { |
4c6fb5fc MG |
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 | ||
705ececd MG |
421 | line6->line6midi = line6midi; |
422 | ||
d7e37336 GKH |
423 | err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, |
424 | &midi_ops); | |
425 | if (err < 0) | |
705ececd MG |
426 | return err; |
427 | ||
428 | snd_card_set_dev(line6->card, line6->ifcdev); | |
429 | ||
d7e37336 GKH |
430 | err = snd_line6_new_midi(line6midi); |
431 | if (err < 0) | |
705ececd MG |
432 | return err; |
433 | ||
d7e37336 GKH |
434 | err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_transmit); |
435 | if (err < 0) | |
705ececd MG |
436 | return err; |
437 | ||
d7e37336 GKH |
438 | err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_receive); |
439 | if (err < 0) | |
705ececd MG |
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 | } |