Commit | Line | Data |
---|---|---|
d5daf49b DM |
1 | /* |
2 | * f_midi.c -- USB MIDI class function driver | |
3 | * | |
4 | * Copyright (C) 2006 Thumtronics Pty Ltd. | |
5 | * Developed for Thumtronics by Grey Innovation | |
6 | * Ben Williamson <ben.williamson@greyinnovation.com> | |
7 | * | |
8 | * Rewritten for the composite framework | |
9 | * Copyright (C) 2011 Daniel Mack <zonque@gmail.com> | |
10 | * | |
11 | * Based on drivers/usb/gadget/f_audio.c, | |
12 | * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org> | |
13 | * Copyright (C) 2008 Analog Devices, Inc | |
14 | * | |
15 | * and drivers/usb/gadget/midi.c, | |
16 | * Copyright (C) 2006 Thumtronics Pty Ltd. | |
17 | * Ben Williamson <ben.williamson@greyinnovation.com> | |
18 | * | |
19 | * Licensed under the GPL-2 or later. | |
20 | */ | |
21 | ||
22 | #include <linux/kernel.h> | |
b85e9de9 | 23 | #include <linux/module.h> |
d5daf49b | 24 | #include <linux/slab.h> |
d5daf49b | 25 | #include <linux/device.h> |
e1e3d7ec | 26 | #include <linux/kfifo.h> |
9acdf4df | 27 | #include <linux/spinlock.h> |
d5daf49b DM |
28 | |
29 | #include <sound/core.h> | |
30 | #include <sound/initval.h> | |
31 | #include <sound/rawmidi.h> | |
32 | ||
33 | #include <linux/usb/ch9.h> | |
34 | #include <linux/usb/gadget.h> | |
35 | #include <linux/usb/audio.h> | |
36 | #include <linux/usb/midi.h> | |
37 | ||
1efd54ea | 38 | #include "u_f.h" |
b85e9de9 | 39 | #include "u_midi.h" |
1efd54ea | 40 | |
d5daf49b DM |
41 | MODULE_AUTHOR("Ben Williamson"); |
42 | MODULE_LICENSE("GPL v2"); | |
43 | ||
44 | static const char f_midi_shortname[] = "f_midi"; | |
45 | static const char f_midi_longname[] = "MIDI Gadget"; | |
46 | ||
c8933c3f DM |
47 | /* |
48 | * We can only handle 16 cables on one single endpoint, as cable numbers are | |
49 | * stored in 4-bit fields. And as the interface currently only holds one | |
50 | * single endpoint, this is the maximum number of ports we can allow. | |
51 | */ | |
52 | #define MAX_PORTS 16 | |
53 | ||
f42ab18c FT |
54 | /* MIDI message states */ |
55 | enum { | |
56 | STATE_INITIAL = 0, /* pseudo state */ | |
57 | STATE_1PARAM, | |
58 | STATE_2PARAM_1, | |
59 | STATE_2PARAM_2, | |
60 | STATE_SYSEX_0, | |
61 | STATE_SYSEX_1, | |
62 | STATE_SYSEX_2, | |
63 | STATE_REAL_TIME, | |
64 | STATE_FINISHED, /* pseudo state */ | |
65 | }; | |
66 | ||
d5daf49b DM |
67 | /* |
68 | * This is a gadget, and the IN/OUT naming is from the host's perspective. | |
69 | * USB -> OUT endpoint -> rawmidi | |
70 | * USB <- IN endpoint <- rawmidi | |
71 | */ | |
72 | struct gmidi_in_port { | |
4111d494 | 73 | struct snd_rawmidi_substream *substream; |
d5daf49b | 74 | int active; |
c8933c3f | 75 | uint8_t cable; |
d5daf49b | 76 | uint8_t state; |
d5daf49b DM |
77 | uint8_t data[2]; |
78 | }; | |
79 | ||
80 | struct f_midi { | |
81 | struct usb_function func; | |
82 | struct usb_gadget *gadget; | |
83 | struct usb_ep *in_ep, *out_ep; | |
84 | struct snd_card *card; | |
85 | struct snd_rawmidi *rmidi; | |
919de443 | 86 | u8 ms_id; |
d5daf49b | 87 | |
c8933c3f | 88 | struct snd_rawmidi_substream *out_substream[MAX_PORTS]; |
c8933c3f | 89 | |
d5daf49b DM |
90 | unsigned long out_triggered; |
91 | struct tasklet_struct tasklet; | |
c8933c3f DM |
92 | unsigned int in_ports; |
93 | unsigned int out_ports; | |
d5daf49b DM |
94 | int index; |
95 | char *id; | |
96 | unsigned int buflen, qlen; | |
e1e3d7ec FT |
97 | /* This fifo is used as a buffer ring for pre-allocated IN usb_requests */ |
98 | DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *); | |
9acdf4df | 99 | spinlock_t transmit_lock; |
e1e3d7ec | 100 | unsigned int in_last_port; |
bf0028f8 MN |
101 | |
102 | struct gmidi_in_port in_ports_array[/* in_ports */]; | |
d5daf49b DM |
103 | }; |
104 | ||
105 | static inline struct f_midi *func_to_midi(struct usb_function *f) | |
106 | { | |
107 | return container_of(f, struct f_midi, func); | |
108 | } | |
109 | ||
e1e3d7ec | 110 | static void f_midi_transmit(struct f_midi *midi); |
d5daf49b DM |
111 | |
112 | DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); | |
113 | DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); | |
c8933c3f | 114 | DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16); |
d5daf49b DM |
115 | |
116 | /* B.3.1 Standard AC Interface Descriptor */ | |
b85e9de9 | 117 | static struct usb_interface_descriptor ac_interface_desc = { |
d5daf49b DM |
118 | .bLength = USB_DT_INTERFACE_SIZE, |
119 | .bDescriptorType = USB_DT_INTERFACE, | |
120 | /* .bInterfaceNumber = DYNAMIC */ | |
121 | /* .bNumEndpoints = DYNAMIC */ | |
122 | .bInterfaceClass = USB_CLASS_AUDIO, | |
123 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | |
124 | /* .iInterface = DYNAMIC */ | |
125 | }; | |
126 | ||
127 | /* B.3.2 Class-Specific AC Interface Descriptor */ | |
b85e9de9 | 128 | static struct uac1_ac_header_descriptor_1 ac_header_desc = { |
d5daf49b DM |
129 | .bLength = UAC_DT_AC_HEADER_SIZE(1), |
130 | .bDescriptorType = USB_DT_CS_INTERFACE, | |
131 | .bDescriptorSubtype = USB_MS_HEADER, | |
132 | .bcdADC = cpu_to_le16(0x0100), | |
133 | .wTotalLength = cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)), | |
134 | .bInCollection = 1, | |
135 | /* .baInterfaceNr = DYNAMIC */ | |
136 | }; | |
137 | ||
138 | /* B.4.1 Standard MS Interface Descriptor */ | |
b85e9de9 | 139 | static struct usb_interface_descriptor ms_interface_desc = { |
d5daf49b DM |
140 | .bLength = USB_DT_INTERFACE_SIZE, |
141 | .bDescriptorType = USB_DT_INTERFACE, | |
142 | /* .bInterfaceNumber = DYNAMIC */ | |
143 | .bNumEndpoints = 2, | |
144 | .bInterfaceClass = USB_CLASS_AUDIO, | |
145 | .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, | |
146 | /* .iInterface = DYNAMIC */ | |
147 | }; | |
148 | ||
149 | /* B.4.2 Class-Specific MS Interface Descriptor */ | |
b85e9de9 | 150 | static struct usb_ms_header_descriptor ms_header_desc = { |
d5daf49b DM |
151 | .bLength = USB_DT_MS_HEADER_SIZE, |
152 | .bDescriptorType = USB_DT_CS_INTERFACE, | |
153 | .bDescriptorSubtype = USB_MS_HEADER, | |
154 | .bcdMSC = cpu_to_le16(0x0100), | |
c8933c3f | 155 | /* .wTotalLength = DYNAMIC */ |
d5daf49b DM |
156 | }; |
157 | ||
d5daf49b DM |
158 | /* B.5.1 Standard Bulk OUT Endpoint Descriptor */ |
159 | static struct usb_endpoint_descriptor bulk_out_desc = { | |
160 | .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, | |
161 | .bDescriptorType = USB_DT_ENDPOINT, | |
162 | .bEndpointAddress = USB_DIR_OUT, | |
163 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | |
164 | }; | |
165 | ||
166 | /* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */ | |
c8933c3f DM |
167 | static struct usb_ms_endpoint_descriptor_16 ms_out_desc = { |
168 | /* .bLength = DYNAMIC */ | |
d5daf49b DM |
169 | .bDescriptorType = USB_DT_CS_ENDPOINT, |
170 | .bDescriptorSubtype = USB_MS_GENERAL, | |
c8933c3f DM |
171 | /* .bNumEmbMIDIJack = DYNAMIC */ |
172 | /* .baAssocJackID = DYNAMIC */ | |
d5daf49b DM |
173 | }; |
174 | ||
175 | /* B.6.1 Standard Bulk IN Endpoint Descriptor */ | |
176 | static struct usb_endpoint_descriptor bulk_in_desc = { | |
177 | .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, | |
178 | .bDescriptorType = USB_DT_ENDPOINT, | |
179 | .bEndpointAddress = USB_DIR_IN, | |
180 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | |
181 | }; | |
182 | ||
183 | /* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */ | |
c8933c3f DM |
184 | static struct usb_ms_endpoint_descriptor_16 ms_in_desc = { |
185 | /* .bLength = DYNAMIC */ | |
d5daf49b DM |
186 | .bDescriptorType = USB_DT_CS_ENDPOINT, |
187 | .bDescriptorSubtype = USB_MS_GENERAL, | |
c8933c3f DM |
188 | /* .bNumEmbMIDIJack = DYNAMIC */ |
189 | /* .baAssocJackID = DYNAMIC */ | |
d5daf49b DM |
190 | }; |
191 | ||
192 | /* string IDs are assigned dynamically */ | |
193 | ||
194 | #define STRING_FUNC_IDX 0 | |
195 | ||
196 | static struct usb_string midi_string_defs[] = { | |
197 | [STRING_FUNC_IDX].s = "MIDI function", | |
198 | { } /* end of list */ | |
199 | }; | |
200 | ||
201 | static struct usb_gadget_strings midi_stringtab = { | |
202 | .language = 0x0409, /* en-us */ | |
203 | .strings = midi_string_defs, | |
204 | }; | |
205 | ||
206 | static struct usb_gadget_strings *midi_strings[] = { | |
207 | &midi_stringtab, | |
208 | NULL, | |
209 | }; | |
210 | ||
1efd54ea AP |
211 | static inline struct usb_request *midi_alloc_ep_req(struct usb_ep *ep, |
212 | unsigned length) | |
d5daf49b | 213 | { |
aadbe812 | 214 | return alloc_ep_req(ep, length); |
d5daf49b DM |
215 | } |
216 | ||
d5daf49b DM |
217 | static const uint8_t f_midi_cin_length[] = { |
218 | 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 | |
219 | }; | |
220 | ||
221 | /* | |
222 | * Receives a chunk of MIDI data. | |
223 | */ | |
224 | static void f_midi_read_data(struct usb_ep *ep, int cable, | |
225 | uint8_t *data, int length) | |
226 | { | |
227 | struct f_midi *midi = ep->driver_data; | |
c8933c3f | 228 | struct snd_rawmidi_substream *substream = midi->out_substream[cable]; |
d5daf49b | 229 | |
c8933c3f | 230 | if (!substream) |
d5daf49b DM |
231 | /* Nobody is listening - throw it on the floor. */ |
232 | return; | |
233 | ||
c8933c3f | 234 | if (!test_bit(cable, &midi->out_triggered)) |
d5daf49b DM |
235 | return; |
236 | ||
c8933c3f | 237 | snd_rawmidi_receive(substream, data, length); |
d5daf49b DM |
238 | } |
239 | ||
240 | static void f_midi_handle_out_data(struct usb_ep *ep, struct usb_request *req) | |
241 | { | |
242 | unsigned int i; | |
243 | u8 *buf = req->buf; | |
244 | ||
245 | for (i = 0; i + 3 < req->actual; i += 4) | |
246 | if (buf[i] != 0) { | |
247 | int cable = buf[i] >> 4; | |
248 | int length = f_midi_cin_length[buf[i] & 0x0f]; | |
249 | f_midi_read_data(ep, cable, &buf[i + 1], length); | |
250 | } | |
251 | } | |
252 | ||
253 | static void | |
254 | f_midi_complete(struct usb_ep *ep, struct usb_request *req) | |
255 | { | |
256 | struct f_midi *midi = ep->driver_data; | |
257 | struct usb_composite_dev *cdev = midi->func.config->cdev; | |
258 | int status = req->status; | |
259 | ||
260 | switch (status) { | |
261 | case 0: /* normal completion */ | |
262 | if (ep == midi->out_ep) { | |
263 | /* We received stuff. req is queued again, below */ | |
264 | f_midi_handle_out_data(ep, req); | |
265 | } else if (ep == midi->in_ep) { | |
266 | /* Our transmit completed. See if there's more to go. | |
267 | * f_midi_transmit eats req, don't queue it again. */ | |
e1e3d7ec FT |
268 | req->length = 0; |
269 | f_midi_transmit(midi); | |
d5daf49b DM |
270 | return; |
271 | } | |
272 | break; | |
273 | ||
274 | /* this endpoint is normally active while we're configured */ | |
275 | case -ECONNABORTED: /* hardware forced ep reset */ | |
276 | case -ECONNRESET: /* request dequeued */ | |
277 | case -ESHUTDOWN: /* disconnect from host */ | |
278 | VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status, | |
279 | req->actual, req->length); | |
e1e3d7ec | 280 | if (ep == midi->out_ep) { |
d5daf49b | 281 | f_midi_handle_out_data(ep, req); |
e1e3d7ec FT |
282 | /* We don't need to free IN requests because it's handled |
283 | * by the midi->in_req_fifo. */ | |
284 | free_ep_req(ep, req); | |
285 | } | |
d5daf49b DM |
286 | return; |
287 | ||
288 | case -EOVERFLOW: /* buffer overrun on read means that | |
289 | * we didn't provide a big enough buffer. | |
290 | */ | |
291 | default: | |
292 | DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name, | |
293 | status, req->actual, req->length); | |
294 | break; | |
295 | case -EREMOTEIO: /* short read */ | |
296 | break; | |
297 | } | |
298 | ||
299 | status = usb_ep_queue(ep, req, GFP_ATOMIC); | |
300 | if (status) { | |
301 | ERROR(cdev, "kill %s: resubmit %d bytes --> %d\n", | |
302 | ep->name, req->length, status); | |
303 | usb_ep_set_halt(ep); | |
304 | /* FIXME recover later ... somehow */ | |
305 | } | |
306 | } | |
307 | ||
f8ca46ae FT |
308 | static void f_midi_drop_out_substreams(struct f_midi *midi) |
309 | { | |
310 | unsigned int i; | |
311 | ||
312 | for (i = 0; i < midi->in_ports; i++) { | |
313 | struct gmidi_in_port *port = midi->in_ports_array + i; | |
314 | struct snd_rawmidi_substream *substream = port->substream; | |
315 | ||
316 | if (port->active && substream) | |
317 | snd_rawmidi_drop_output(substream); | |
318 | } | |
319 | } | |
320 | ||
d5daf49b DM |
321 | static int f_midi_start_ep(struct f_midi *midi, |
322 | struct usb_function *f, | |
323 | struct usb_ep *ep) | |
324 | { | |
325 | int err; | |
326 | struct usb_composite_dev *cdev = f->config->cdev; | |
327 | ||
ce723951 | 328 | usb_ep_disable(ep); |
d5daf49b DM |
329 | |
330 | err = config_ep_by_speed(midi->gadget, f, ep); | |
331 | if (err) { | |
332 | ERROR(cdev, "can't configure %s: %d\n", ep->name, err); | |
333 | return err; | |
334 | } | |
335 | ||
336 | err = usb_ep_enable(ep); | |
337 | if (err) { | |
338 | ERROR(cdev, "can't start %s: %d\n", ep->name, err); | |
339 | return err; | |
340 | } | |
341 | ||
342 | ep->driver_data = midi; | |
343 | ||
344 | return 0; | |
345 | } | |
346 | ||
347 | static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) | |
348 | { | |
349 | struct f_midi *midi = func_to_midi(f); | |
d5daf49b DM |
350 | unsigned i; |
351 | int err; | |
352 | ||
919de443 FT |
353 | /* we only set alt for MIDIStreaming interface */ |
354 | if (intf != midi->ms_id) | |
4ef7a4a1 RB |
355 | return 0; |
356 | ||
d5daf49b DM |
357 | err = f_midi_start_ep(midi, f, midi->in_ep); |
358 | if (err) | |
359 | return err; | |
360 | ||
361 | err = f_midi_start_ep(midi, f, midi->out_ep); | |
362 | if (err) | |
363 | return err; | |
364 | ||
e1e3d7ec FT |
365 | /* pre-allocate write usb requests to use on f_midi_transmit. */ |
366 | while (kfifo_avail(&midi->in_req_fifo)) { | |
367 | struct usb_request *req = | |
368 | midi_alloc_ep_req(midi->in_ep, midi->buflen); | |
369 | ||
370 | if (req == NULL) | |
371 | return -ENOMEM; | |
372 | ||
373 | req->length = 0; | |
374 | req->complete = f_midi_complete; | |
375 | ||
376 | kfifo_put(&midi->in_req_fifo, req); | |
377 | } | |
378 | ||
d5daf49b DM |
379 | /* allocate a bunch of read buffers and queue them all at once. */ |
380 | for (i = 0; i < midi->qlen && err == 0; i++) { | |
381 | struct usb_request *req = | |
4a655f15 FT |
382 | midi_alloc_ep_req(midi->out_ep, midi->buflen); |
383 | ||
d5daf49b DM |
384 | if (req == NULL) |
385 | return -ENOMEM; | |
386 | ||
387 | req->complete = f_midi_complete; | |
388 | err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC); | |
389 | if (err) { | |
f0f1b8ca | 390 | ERROR(midi, "%s: couldn't enqueue request: %d\n", |
d5daf49b | 391 | midi->out_ep->name, err); |
ad0d1a05 | 392 | free_ep_req(midi->out_ep, req); |
f0f1b8ca | 393 | return err; |
d5daf49b DM |
394 | } |
395 | } | |
396 | ||
397 | return 0; | |
398 | } | |
399 | ||
400 | static void f_midi_disable(struct usb_function *f) | |
401 | { | |
402 | struct f_midi *midi = func_to_midi(f); | |
403 | struct usb_composite_dev *cdev = f->config->cdev; | |
e1e3d7ec | 404 | struct usb_request *req = NULL; |
d5daf49b DM |
405 | |
406 | DBG(cdev, "disable\n"); | |
407 | ||
408 | /* | |
409 | * just disable endpoints, forcing completion of pending i/o. | |
410 | * all our completion handlers free their requests in this case. | |
411 | */ | |
412 | usb_ep_disable(midi->in_ep); | |
413 | usb_ep_disable(midi->out_ep); | |
e1e3d7ec FT |
414 | |
415 | /* release IN requests */ | |
416 | while (kfifo_get(&midi->in_req_fifo, &req)) | |
417 | free_ep_req(midi->in_ep, req); | |
f8ca46ae FT |
418 | |
419 | f_midi_drop_out_substreams(midi); | |
d5daf49b DM |
420 | } |
421 | ||
d5daf49b DM |
422 | static int f_midi_snd_free(struct snd_device *device) |
423 | { | |
424 | return 0; | |
425 | } | |
426 | ||
d5daf49b DM |
427 | /* |
428 | * Converts MIDI commands to USB MIDI packets. | |
429 | */ | |
430 | static void f_midi_transmit_byte(struct usb_request *req, | |
431 | struct gmidi_in_port *port, uint8_t b) | |
432 | { | |
f42ab18c FT |
433 | uint8_t p[4] = { port->cable << 4, 0, 0, 0 }; |
434 | uint8_t next_state = STATE_INITIAL; | |
435 | ||
436 | switch (b) { | |
437 | case 0xf8 ... 0xff: | |
438 | /* System Real-Time Messages */ | |
439 | p[0] |= 0x0f; | |
440 | p[1] = b; | |
441 | next_state = port->state; | |
442 | port->state = STATE_REAL_TIME; | |
443 | break; | |
444 | ||
445 | case 0xf7: | |
446 | /* End of SysEx */ | |
447 | switch (port->state) { | |
448 | case STATE_SYSEX_0: | |
449 | p[0] |= 0x05; | |
450 | p[1] = 0xf7; | |
451 | next_state = STATE_FINISHED; | |
452 | break; | |
453 | case STATE_SYSEX_1: | |
454 | p[0] |= 0x06; | |
455 | p[1] = port->data[0]; | |
456 | p[2] = 0xf7; | |
457 | next_state = STATE_FINISHED; | |
458 | break; | |
459 | case STATE_SYSEX_2: | |
460 | p[0] |= 0x07; | |
461 | p[1] = port->data[0]; | |
462 | p[2] = port->data[1]; | |
463 | p[3] = 0xf7; | |
464 | next_state = STATE_FINISHED; | |
465 | break; | |
466 | default: | |
467 | /* Ignore byte */ | |
468 | next_state = port->state; | |
469 | port->state = STATE_INITIAL; | |
470 | } | |
471 | break; | |
d5daf49b | 472 | |
f42ab18c FT |
473 | case 0xf0 ... 0xf6: |
474 | /* System Common Messages */ | |
475 | port->data[0] = port->data[1] = 0; | |
476 | port->state = STATE_INITIAL; | |
d5daf49b DM |
477 | switch (b) { |
478 | case 0xf0: | |
479 | port->data[0] = b; | |
f42ab18c FT |
480 | port->data[1] = 0; |
481 | next_state = STATE_SYSEX_1; | |
d5daf49b DM |
482 | break; |
483 | case 0xf1: | |
484 | case 0xf3: | |
485 | port->data[0] = b; | |
f42ab18c | 486 | next_state = STATE_1PARAM; |
d5daf49b DM |
487 | break; |
488 | case 0xf2: | |
489 | port->data[0] = b; | |
f42ab18c | 490 | next_state = STATE_2PARAM_1; |
d5daf49b DM |
491 | break; |
492 | case 0xf4: | |
493 | case 0xf5: | |
f42ab18c | 494 | next_state = STATE_INITIAL; |
d5daf49b DM |
495 | break; |
496 | case 0xf6: | |
f42ab18c FT |
497 | p[0] |= 0x05; |
498 | p[1] = 0xf6; | |
499 | next_state = STATE_FINISHED; | |
d5daf49b DM |
500 | break; |
501 | } | |
f42ab18c FT |
502 | break; |
503 | ||
504 | case 0x80 ... 0xef: | |
505 | /* | |
506 | * Channel Voice Messages, Channel Mode Messages | |
507 | * and Control Change Messages. | |
508 | */ | |
d5daf49b | 509 | port->data[0] = b; |
f42ab18c FT |
510 | port->data[1] = 0; |
511 | port->state = STATE_INITIAL; | |
d5daf49b | 512 | if (b >= 0xc0 && b <= 0xdf) |
f42ab18c | 513 | next_state = STATE_1PARAM; |
d5daf49b | 514 | else |
f42ab18c FT |
515 | next_state = STATE_2PARAM_1; |
516 | break; | |
517 | ||
518 | case 0x00 ... 0x7f: | |
519 | /* Message parameters */ | |
d5daf49b DM |
520 | switch (port->state) { |
521 | case STATE_1PARAM: | |
f42ab18c FT |
522 | if (port->data[0] < 0xf0) |
523 | p[0] |= port->data[0] >> 4; | |
524 | else | |
525 | p[0] |= 0x02; | |
526 | ||
527 | p[1] = port->data[0]; | |
528 | p[2] = b; | |
529 | /* This is to allow Running State Messages */ | |
530 | next_state = STATE_1PARAM; | |
d5daf49b DM |
531 | break; |
532 | case STATE_2PARAM_1: | |
533 | port->data[1] = b; | |
f42ab18c | 534 | next_state = STATE_2PARAM_2; |
d5daf49b DM |
535 | break; |
536 | case STATE_2PARAM_2: | |
f42ab18c FT |
537 | if (port->data[0] < 0xf0) |
538 | p[0] |= port->data[0] >> 4; | |
539 | else | |
540 | p[0] |= 0x03; | |
541 | ||
542 | p[1] = port->data[0]; | |
543 | p[2] = port->data[1]; | |
544 | p[3] = b; | |
545 | /* This is to allow Running State Messages */ | |
546 | next_state = STATE_2PARAM_1; | |
d5daf49b DM |
547 | break; |
548 | case STATE_SYSEX_0: | |
549 | port->data[0] = b; | |
f42ab18c | 550 | next_state = STATE_SYSEX_1; |
d5daf49b DM |
551 | break; |
552 | case STATE_SYSEX_1: | |
553 | port->data[1] = b; | |
f42ab18c | 554 | next_state = STATE_SYSEX_2; |
d5daf49b DM |
555 | break; |
556 | case STATE_SYSEX_2: | |
f42ab18c FT |
557 | p[0] |= 0x04; |
558 | p[1] = port->data[0]; | |
559 | p[2] = port->data[1]; | |
560 | p[3] = b; | |
561 | next_state = STATE_SYSEX_0; | |
d5daf49b DM |
562 | break; |
563 | } | |
f42ab18c FT |
564 | break; |
565 | } | |
566 | ||
567 | /* States where we have to write into the USB request */ | |
568 | if (next_state == STATE_FINISHED || | |
569 | port->state == STATE_SYSEX_2 || | |
570 | port->state == STATE_1PARAM || | |
571 | port->state == STATE_2PARAM_2 || | |
572 | port->state == STATE_REAL_TIME) { | |
573 | ||
574 | unsigned int length = req->length; | |
575 | u8 *buf = (u8 *)req->buf + length; | |
576 | ||
577 | memcpy(buf, p, sizeof(p)); | |
578 | req->length = length + sizeof(p); | |
579 | ||
580 | if (next_state == STATE_FINISHED) { | |
581 | next_state = STATE_INITIAL; | |
582 | port->data[0] = port->data[1] = 0; | |
583 | } | |
d5daf49b | 584 | } |
f42ab18c FT |
585 | |
586 | port->state = next_state; | |
d5daf49b DM |
587 | } |
588 | ||
9a71eb56 | 589 | static int f_midi_do_transmit(struct f_midi *midi, struct usb_ep *ep) |
e1e3d7ec | 590 | { |
9a71eb56 MN |
591 | struct usb_request *req = NULL; |
592 | unsigned int len, i; | |
593 | bool active = false; | |
594 | int err; | |
e1e3d7ec | 595 | |
9a71eb56 MN |
596 | /* |
597 | * We peek the request in order to reuse it if it fails to enqueue on | |
598 | * its endpoint | |
599 | */ | |
600 | len = kfifo_peek(&midi->in_req_fifo, &req); | |
601 | if (len != 1) { | |
602 | ERROR(midi, "%s: Couldn't get usb request\n", __func__); | |
603 | return -1; | |
604 | } | |
e1e3d7ec | 605 | |
9a71eb56 MN |
606 | /* |
607 | * If buffer overrun, then we ignore this transmission. | |
608 | * IMPORTANT: This will cause the user-space rawmidi device to block | |
609 | * until a) usb requests have been completed or b) snd_rawmidi_write() | |
610 | * times out. | |
611 | */ | |
612 | if (req->length > 0) | |
613 | return 0; | |
e1e3d7ec | 614 | |
bf0028f8 MN |
615 | for (i = midi->in_last_port; i < midi->in_ports; ++i) { |
616 | struct gmidi_in_port *port = midi->in_ports_array + i; | |
4111d494 | 617 | struct snd_rawmidi_substream *substream = port->substream; |
bf0028f8 | 618 | |
9a71eb56 MN |
619 | if (!port->active || !substream) |
620 | continue; | |
e1e3d7ec | 621 | |
9a71eb56 MN |
622 | while (req->length + 3 < midi->buflen) { |
623 | uint8_t b; | |
e1e3d7ec | 624 | |
9a71eb56 MN |
625 | if (snd_rawmidi_transmit(substream, &b, 1) != 1) { |
626 | port->active = 0; | |
e1e3d7ec FT |
627 | break; |
628 | } | |
9a71eb56 MN |
629 | f_midi_transmit_byte(req, port, b); |
630 | } | |
e1e3d7ec | 631 | |
9a71eb56 | 632 | active = !!port->active; |
06cd928b | 633 | if (active) |
9a71eb56 | 634 | break; |
9a71eb56 | 635 | } |
06cd928b | 636 | midi->in_last_port = active ? i : 0; |
e1e3d7ec | 637 | |
9a71eb56 | 638 | if (req->length <= 0) |
06cd928b | 639 | goto done; |
9a71eb56 MN |
640 | |
641 | err = usb_ep_queue(ep, req, GFP_ATOMIC); | |
642 | if (err < 0) { | |
643 | ERROR(midi, "%s failed to queue req: %d\n", | |
644 | midi->in_ep->name, err); | |
645 | req->length = 0; /* Re-use request next time. */ | |
646 | } else { | |
647 | /* Upon success, put request at the back of the queue. */ | |
648 | kfifo_skip(&midi->in_req_fifo); | |
649 | kfifo_put(&midi->in_req_fifo, req); | |
650 | } | |
e1e3d7ec | 651 | |
06cd928b | 652 | done: |
9a71eb56 MN |
653 | return active; |
654 | } | |
e1e3d7ec | 655 | |
9a71eb56 MN |
656 | static void f_midi_transmit(struct f_midi *midi) |
657 | { | |
658 | struct usb_ep *ep = midi->in_ep; | |
659 | int ret; | |
9acdf4df | 660 | unsigned long flags; |
d5daf49b | 661 | |
9a71eb56 MN |
662 | /* We only care about USB requests if IN endpoint is enabled */ |
663 | if (!ep || !ep->enabled) | |
664 | goto drop_out; | |
f35fe4be | 665 | |
9acdf4df FT |
666 | spin_lock_irqsave(&midi->transmit_lock, flags); |
667 | ||
9a71eb56 MN |
668 | do { |
669 | ret = f_midi_do_transmit(midi, ep); | |
4fc50ba5 DC |
670 | if (ret < 0) { |
671 | spin_unlock_irqrestore(&midi->transmit_lock, flags); | |
9a71eb56 | 672 | goto drop_out; |
4fc50ba5 | 673 | } |
9a71eb56 | 674 | } while (ret); |
e1e3d7ec | 675 | |
9acdf4df FT |
676 | spin_unlock_irqrestore(&midi->transmit_lock, flags); |
677 | ||
e1e3d7ec FT |
678 | return; |
679 | ||
680 | drop_out: | |
681 | f_midi_drop_out_substreams(midi); | |
d5daf49b DM |
682 | } |
683 | ||
684 | static void f_midi_in_tasklet(unsigned long data) | |
685 | { | |
686 | struct f_midi *midi = (struct f_midi *) data; | |
e1e3d7ec | 687 | f_midi_transmit(midi); |
d5daf49b DM |
688 | } |
689 | ||
690 | static int f_midi_in_open(struct snd_rawmidi_substream *substream) | |
691 | { | |
692 | struct f_midi *midi = substream->rmidi->private_data; | |
4111d494 | 693 | struct gmidi_in_port *port; |
d5daf49b | 694 | |
bf0028f8 | 695 | if (substream->number >= midi->in_ports) |
c8933c3f DM |
696 | return -EINVAL; |
697 | ||
d5daf49b | 698 | VDBG(midi, "%s()\n", __func__); |
4111d494 MN |
699 | port = midi->in_ports_array + substream->number; |
700 | port->substream = substream; | |
f42ab18c | 701 | port->state = STATE_INITIAL; |
d5daf49b DM |
702 | return 0; |
703 | } | |
704 | ||
705 | static int f_midi_in_close(struct snd_rawmidi_substream *substream) | |
706 | { | |
707 | struct f_midi *midi = substream->rmidi->private_data; | |
708 | ||
709 | VDBG(midi, "%s()\n", __func__); | |
710 | return 0; | |
711 | } | |
712 | ||
713 | static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up) | |
714 | { | |
715 | struct f_midi *midi = substream->rmidi->private_data; | |
716 | ||
bf0028f8 | 717 | if (substream->number >= midi->in_ports) |
c8933c3f DM |
718 | return; |
719 | ||
d5daf49b | 720 | VDBG(midi, "%s() %d\n", __func__, up); |
bf0028f8 | 721 | midi->in_ports_array[substream->number].active = up; |
d5daf49b DM |
722 | if (up) |
723 | tasklet_hi_schedule(&midi->tasklet); | |
724 | } | |
725 | ||
726 | static int f_midi_out_open(struct snd_rawmidi_substream *substream) | |
727 | { | |
728 | struct f_midi *midi = substream->rmidi->private_data; | |
729 | ||
08895512 | 730 | if (substream->number >= MAX_PORTS) |
c8933c3f DM |
731 | return -EINVAL; |
732 | ||
d5daf49b | 733 | VDBG(midi, "%s()\n", __func__); |
c8933c3f | 734 | midi->out_substream[substream->number] = substream; |
d5daf49b DM |
735 | return 0; |
736 | } | |
737 | ||
738 | static int f_midi_out_close(struct snd_rawmidi_substream *substream) | |
739 | { | |
740 | struct f_midi *midi = substream->rmidi->private_data; | |
741 | ||
742 | VDBG(midi, "%s()\n", __func__); | |
743 | return 0; | |
744 | } | |
745 | ||
746 | static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up) | |
747 | { | |
748 | struct f_midi *midi = substream->rmidi->private_data; | |
749 | ||
750 | VDBG(midi, "%s()\n", __func__); | |
751 | ||
752 | if (up) | |
753 | set_bit(substream->number, &midi->out_triggered); | |
754 | else | |
755 | clear_bit(substream->number, &midi->out_triggered); | |
756 | } | |
757 | ||
758 | static struct snd_rawmidi_ops gmidi_in_ops = { | |
759 | .open = f_midi_in_open, | |
760 | .close = f_midi_in_close, | |
761 | .trigger = f_midi_in_trigger, | |
762 | }; | |
763 | ||
764 | static struct snd_rawmidi_ops gmidi_out_ops = { | |
765 | .open = f_midi_out_open, | |
766 | .close = f_midi_out_close, | |
767 | .trigger = f_midi_out_trigger | |
768 | }; | |
769 | ||
d23b4c3e AP |
770 | static inline void f_midi_unregister_card(struct f_midi *midi) |
771 | { | |
772 | if (midi->card) { | |
773 | snd_card_free(midi->card); | |
774 | midi->card = NULL; | |
775 | } | |
776 | } | |
777 | ||
d5daf49b DM |
778 | /* register as a sound "card" */ |
779 | static int f_midi_register_card(struct f_midi *midi) | |
780 | { | |
781 | struct snd_card *card; | |
782 | struct snd_rawmidi *rmidi; | |
783 | int err; | |
d5daf49b DM |
784 | static struct snd_device_ops ops = { |
785 | .dev_free = f_midi_snd_free, | |
786 | }; | |
787 | ||
13345095 TI |
788 | err = snd_card_new(&midi->gadget->dev, midi->index, midi->id, |
789 | THIS_MODULE, 0, &card); | |
d5daf49b | 790 | if (err < 0) { |
13345095 | 791 | ERROR(midi, "snd_card_new() failed\n"); |
d5daf49b DM |
792 | goto fail; |
793 | } | |
794 | midi->card = card; | |
795 | ||
796 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, midi, &ops); | |
797 | if (err < 0) { | |
798 | ERROR(midi, "snd_device_new() failed: error %d\n", err); | |
799 | goto fail; | |
800 | } | |
801 | ||
802 | strcpy(card->driver, f_midi_longname); | |
803 | strcpy(card->longname, f_midi_longname); | |
804 | strcpy(card->shortname, f_midi_shortname); | |
805 | ||
806 | /* Set up rawmidi */ | |
d5daf49b DM |
807 | snd_component_add(card, "MIDI"); |
808 | err = snd_rawmidi_new(card, card->longname, 0, | |
c8933c3f | 809 | midi->out_ports, midi->in_ports, &rmidi); |
d5daf49b DM |
810 | if (err < 0) { |
811 | ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err); | |
812 | goto fail; | |
813 | } | |
814 | midi->rmidi = rmidi; | |
e1e3d7ec | 815 | midi->in_last_port = 0; |
d5daf49b DM |
816 | strcpy(rmidi->name, card->shortname); |
817 | rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | | |
818 | SNDRV_RAWMIDI_INFO_INPUT | | |
819 | SNDRV_RAWMIDI_INFO_DUPLEX; | |
820 | rmidi->private_data = midi; | |
821 | ||
822 | /* | |
823 | * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. | |
824 | * It's an upside-down world being a gadget. | |
825 | */ | |
826 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops); | |
827 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops); | |
828 | ||
d5daf49b DM |
829 | /* register it - we're ready to go */ |
830 | err = snd_card_register(card); | |
831 | if (err < 0) { | |
832 | ERROR(midi, "snd_card_register() failed\n"); | |
833 | goto fail; | |
834 | } | |
835 | ||
836 | VDBG(midi, "%s() finished ok\n", __func__); | |
837 | return 0; | |
838 | ||
839 | fail: | |
d23b4c3e | 840 | f_midi_unregister_card(midi); |
d5daf49b DM |
841 | return err; |
842 | } | |
843 | ||
844 | /* MIDI function driver setup/binding */ | |
845 | ||
b85e9de9 | 846 | static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) |
d5daf49b | 847 | { |
74203de0 | 848 | struct usb_descriptor_header **midi_function; |
c8933c3f | 849 | struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS]; |
74203de0 | 850 | struct usb_midi_in_jack_descriptor jack_in_emb_desc[MAX_PORTS]; |
c8933c3f | 851 | struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS]; |
74203de0 | 852 | struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS]; |
d5daf49b DM |
853 | struct usb_composite_dev *cdev = c->cdev; |
854 | struct f_midi *midi = func_to_midi(f); | |
9caa0d77 | 855 | struct usb_string *us; |
c8933c3f | 856 | int status, n, jack = 1, i = 0; |
d5daf49b | 857 | |
b85e9de9 AP |
858 | midi->gadget = cdev->gadget; |
859 | tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); | |
860 | status = f_midi_register_card(midi); | |
861 | if (status < 0) | |
862 | goto fail_register; | |
863 | ||
d5daf49b | 864 | /* maybe allocate device-global string ID */ |
9caa0d77 AP |
865 | us = usb_gstrings_attach(c->cdev, midi_strings, |
866 | ARRAY_SIZE(midi_string_defs)); | |
867 | if (IS_ERR(us)) { | |
868 | status = PTR_ERR(us); | |
869 | goto fail; | |
d5daf49b | 870 | } |
9caa0d77 | 871 | ac_interface_desc.iInterface = us[STRING_FUNC_IDX].id; |
d5daf49b DM |
872 | |
873 | /* We have two interfaces, AudioControl and MIDIStreaming */ | |
874 | status = usb_interface_id(c, f); | |
875 | if (status < 0) | |
876 | goto fail; | |
877 | ac_interface_desc.bInterfaceNumber = status; | |
878 | ||
879 | status = usb_interface_id(c, f); | |
880 | if (status < 0) | |
881 | goto fail; | |
882 | ms_interface_desc.bInterfaceNumber = status; | |
883 | ac_header_desc.baInterfaceNr[0] = status; | |
919de443 | 884 | midi->ms_id = status; |
d5daf49b DM |
885 | |
886 | status = -ENODEV; | |
887 | ||
888 | /* allocate instance-specific endpoints */ | |
889 | midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc); | |
890 | if (!midi->in_ep) | |
891 | goto fail; | |
d5daf49b DM |
892 | |
893 | midi->out_ep = usb_ep_autoconfig(cdev->gadget, &bulk_out_desc); | |
894 | if (!midi->out_ep) | |
895 | goto fail; | |
d5daf49b | 896 | |
74203de0 | 897 | /* allocate temporary function list */ |
2a5be878 | 898 | midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function), |
74203de0 DM |
899 | GFP_KERNEL); |
900 | if (!midi_function) { | |
901 | status = -ENOMEM; | |
902 | goto fail; | |
903 | } | |
904 | ||
c8933c3f DM |
905 | /* |
906 | * construct the function's descriptor set. As the number of | |
907 | * input and output MIDI ports is configurable, we have to do | |
908 | * it that way. | |
909 | */ | |
910 | ||
911 | /* add the headers - these are always the same */ | |
912 | midi_function[i++] = (struct usb_descriptor_header *) &ac_interface_desc; | |
913 | midi_function[i++] = (struct usb_descriptor_header *) &ac_header_desc; | |
914 | midi_function[i++] = (struct usb_descriptor_header *) &ms_interface_desc; | |
915 | ||
916 | /* calculate the header's wTotalLength */ | |
917 | n = USB_DT_MS_HEADER_SIZE | |
74203de0 DM |
918 | + (midi->in_ports + midi->out_ports) * |
919 | (USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1)); | |
c8933c3f DM |
920 | ms_header_desc.wTotalLength = cpu_to_le16(n); |
921 | ||
922 | midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc; | |
923 | ||
74203de0 | 924 | /* configure the external IN jacks, each linked to an embedded OUT jack */ |
c8933c3f | 925 | for (n = 0; n < midi->in_ports; n++) { |
74203de0 DM |
926 | struct usb_midi_in_jack_descriptor *in_ext = &jack_in_ext_desc[n]; |
927 | struct usb_midi_out_jack_descriptor_1 *out_emb = &jack_out_emb_desc[n]; | |
928 | ||
929 | in_ext->bLength = USB_DT_MIDI_IN_SIZE; | |
930 | in_ext->bDescriptorType = USB_DT_CS_INTERFACE; | |
931 | in_ext->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; | |
932 | in_ext->bJackType = USB_MS_EXTERNAL; | |
933 | in_ext->bJackID = jack++; | |
934 | in_ext->iJack = 0; | |
935 | midi_function[i++] = (struct usb_descriptor_header *) in_ext; | |
936 | ||
937 | out_emb->bLength = USB_DT_MIDI_OUT_SIZE(1); | |
938 | out_emb->bDescriptorType = USB_DT_CS_INTERFACE; | |
939 | out_emb->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK; | |
940 | out_emb->bJackType = USB_MS_EMBEDDED; | |
941 | out_emb->bJackID = jack++; | |
942 | out_emb->bNrInputPins = 1; | |
943 | out_emb->pins[0].baSourcePin = 1; | |
944 | out_emb->pins[0].baSourceID = in_ext->bJackID; | |
945 | out_emb->iJack = 0; | |
946 | midi_function[i++] = (struct usb_descriptor_header *) out_emb; | |
947 | ||
948 | /* link it to the endpoint */ | |
949 | ms_in_desc.baAssocJackID[n] = out_emb->bJackID; | |
c8933c3f DM |
950 | } |
951 | ||
74203de0 | 952 | /* configure the external OUT jacks, each linked to an embedded IN jack */ |
c8933c3f | 953 | for (n = 0; n < midi->out_ports; n++) { |
74203de0 DM |
954 | struct usb_midi_in_jack_descriptor *in_emb = &jack_in_emb_desc[n]; |
955 | struct usb_midi_out_jack_descriptor_1 *out_ext = &jack_out_ext_desc[n]; | |
956 | ||
957 | in_emb->bLength = USB_DT_MIDI_IN_SIZE; | |
958 | in_emb->bDescriptorType = USB_DT_CS_INTERFACE; | |
959 | in_emb->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; | |
960 | in_emb->bJackType = USB_MS_EMBEDDED; | |
961 | in_emb->bJackID = jack++; | |
962 | in_emb->iJack = 0; | |
963 | midi_function[i++] = (struct usb_descriptor_header *) in_emb; | |
964 | ||
965 | out_ext->bLength = USB_DT_MIDI_OUT_SIZE(1); | |
966 | out_ext->bDescriptorType = USB_DT_CS_INTERFACE; | |
967 | out_ext->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK; | |
968 | out_ext->bJackType = USB_MS_EXTERNAL; | |
969 | out_ext->bJackID = jack++; | |
970 | out_ext->bNrInputPins = 1; | |
971 | out_ext->iJack = 0; | |
972 | out_ext->pins[0].baSourceID = in_emb->bJackID; | |
973 | out_ext->pins[0].baSourcePin = 1; | |
974 | midi_function[i++] = (struct usb_descriptor_header *) out_ext; | |
975 | ||
976 | /* link it to the endpoint */ | |
977 | ms_out_desc.baAssocJackID[n] = in_emb->bJackID; | |
c8933c3f DM |
978 | } |
979 | ||
980 | /* configure the endpoint descriptors ... */ | |
981 | ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); | |
982 | ms_out_desc.bNumEmbMIDIJack = midi->in_ports; | |
c8933c3f DM |
983 | |
984 | ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); | |
985 | ms_in_desc.bNumEmbMIDIJack = midi->out_ports; | |
c8933c3f DM |
986 | |
987 | /* ... and add them to the list */ | |
988 | midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc; | |
989 | midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc; | |
990 | midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc; | |
991 | midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc; | |
992 | midi_function[i++] = NULL; | |
993 | ||
d5daf49b DM |
994 | /* |
995 | * support all relevant hardware speeds... we expect that when | |
996 | * hardware is dual speed, all bulk-capable endpoints work at | |
997 | * both speeds | |
998 | */ | |
999 | /* copy descriptors, and track endpoint copies */ | |
10287bae SAS |
1000 | f->fs_descriptors = usb_copy_descriptors(midi_function); |
1001 | if (!f->fs_descriptors) | |
7f2a9268 | 1002 | goto fail_f_midi; |
10287bae | 1003 | |
d5daf49b | 1004 | if (gadget_is_dualspeed(c->cdev->gadget)) { |
d5daf49b DM |
1005 | bulk_in_desc.wMaxPacketSize = cpu_to_le16(512); |
1006 | bulk_out_desc.wMaxPacketSize = cpu_to_le16(512); | |
1007 | f->hs_descriptors = usb_copy_descriptors(midi_function); | |
7f2a9268 SAS |
1008 | if (!f->hs_descriptors) |
1009 | goto fail_f_midi; | |
d5daf49b DM |
1010 | } |
1011 | ||
74203de0 DM |
1012 | kfree(midi_function); |
1013 | ||
d5daf49b DM |
1014 | return 0; |
1015 | ||
7f2a9268 SAS |
1016 | fail_f_midi: |
1017 | kfree(midi_function); | |
1018 | usb_free_descriptors(f->hs_descriptors); | |
d5daf49b | 1019 | fail: |
b85e9de9 AP |
1020 | f_midi_unregister_card(midi); |
1021 | fail_register: | |
d5daf49b DM |
1022 | ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); |
1023 | ||
1024 | return status; | |
1025 | } | |
1026 | ||
6f1de344 AP |
1027 | static inline struct f_midi_opts *to_f_midi_opts(struct config_item *item) |
1028 | { | |
1029 | return container_of(to_config_group(item), struct f_midi_opts, | |
1030 | func_inst.group); | |
1031 | } | |
1032 | ||
6f1de344 AP |
1033 | static void midi_attr_release(struct config_item *item) |
1034 | { | |
1035 | struct f_midi_opts *opts = to_f_midi_opts(item); | |
1036 | ||
1037 | usb_put_function_instance(&opts->func_inst); | |
1038 | } | |
1039 | ||
1040 | static struct configfs_item_operations midi_item_ops = { | |
1041 | .release = midi_attr_release, | |
6f1de344 AP |
1042 | }; |
1043 | ||
1044 | #define F_MIDI_OPT(name, test_limit, limit) \ | |
3755a273 | 1045 | static ssize_t f_midi_opts_##name##_show(struct config_item *item, char *page) \ |
6f1de344 | 1046 | { \ |
3755a273 | 1047 | struct f_midi_opts *opts = to_f_midi_opts(item); \ |
6f1de344 AP |
1048 | int result; \ |
1049 | \ | |
1050 | mutex_lock(&opts->lock); \ | |
1051 | result = sprintf(page, "%d\n", opts->name); \ | |
1052 | mutex_unlock(&opts->lock); \ | |
1053 | \ | |
1054 | return result; \ | |
1055 | } \ | |
1056 | \ | |
3755a273 | 1057 | static ssize_t f_midi_opts_##name##_store(struct config_item *item, \ |
6f1de344 AP |
1058 | const char *page, size_t len) \ |
1059 | { \ | |
3755a273 | 1060 | struct f_midi_opts *opts = to_f_midi_opts(item); \ |
6f1de344 AP |
1061 | int ret; \ |
1062 | u32 num; \ | |
1063 | \ | |
1064 | mutex_lock(&opts->lock); \ | |
1065 | if (opts->refcnt) { \ | |
1066 | ret = -EBUSY; \ | |
1067 | goto end; \ | |
1068 | } \ | |
1069 | \ | |
1070 | ret = kstrtou32(page, 0, &num); \ | |
1071 | if (ret) \ | |
1072 | goto end; \ | |
1073 | \ | |
1074 | if (test_limit && num > limit) { \ | |
1075 | ret = -EINVAL; \ | |
1076 | goto end; \ | |
1077 | } \ | |
1078 | opts->name = num; \ | |
1079 | ret = len; \ | |
1080 | \ | |
1081 | end: \ | |
1082 | mutex_unlock(&opts->lock); \ | |
1083 | return ret; \ | |
1084 | } \ | |
1085 | \ | |
3755a273 | 1086 | CONFIGFS_ATTR(f_midi_opts_, name); |
6f1de344 AP |
1087 | |
1088 | F_MIDI_OPT(index, true, SNDRV_CARDS); | |
1089 | F_MIDI_OPT(buflen, false, 0); | |
1090 | F_MIDI_OPT(qlen, false, 0); | |
1091 | F_MIDI_OPT(in_ports, true, MAX_PORTS); | |
1092 | F_MIDI_OPT(out_ports, true, MAX_PORTS); | |
1093 | ||
3755a273 | 1094 | static ssize_t f_midi_opts_id_show(struct config_item *item, char *page) |
6f1de344 | 1095 | { |
3755a273 | 1096 | struct f_midi_opts *opts = to_f_midi_opts(item); |
6f1de344 AP |
1097 | int result; |
1098 | ||
1099 | mutex_lock(&opts->lock); | |
a25a23cc PS |
1100 | if (opts->id) { |
1101 | result = strlcpy(page, opts->id, PAGE_SIZE); | |
1102 | } else { | |
1103 | page[0] = 0; | |
1104 | result = 0; | |
1105 | } | |
1106 | ||
6f1de344 AP |
1107 | mutex_unlock(&opts->lock); |
1108 | ||
1109 | return result; | |
1110 | } | |
1111 | ||
3755a273 | 1112 | static ssize_t f_midi_opts_id_store(struct config_item *item, |
6f1de344 AP |
1113 | const char *page, size_t len) |
1114 | { | |
3755a273 | 1115 | struct f_midi_opts *opts = to_f_midi_opts(item); |
6f1de344 AP |
1116 | int ret; |
1117 | char *c; | |
1118 | ||
1119 | mutex_lock(&opts->lock); | |
1120 | if (opts->refcnt) { | |
1121 | ret = -EBUSY; | |
1122 | goto end; | |
1123 | } | |
1124 | ||
1125 | c = kstrndup(page, len, GFP_KERNEL); | |
1126 | if (!c) { | |
1127 | ret = -ENOMEM; | |
1128 | goto end; | |
1129 | } | |
1130 | if (opts->id_allocated) | |
1131 | kfree(opts->id); | |
1132 | opts->id = c; | |
1133 | opts->id_allocated = true; | |
1134 | ret = len; | |
1135 | end: | |
1136 | mutex_unlock(&opts->lock); | |
1137 | return ret; | |
1138 | } | |
1139 | ||
3755a273 | 1140 | CONFIGFS_ATTR(f_midi_opts_, id); |
6f1de344 AP |
1141 | |
1142 | static struct configfs_attribute *midi_attrs[] = { | |
3755a273 CH |
1143 | &f_midi_opts_attr_index, |
1144 | &f_midi_opts_attr_buflen, | |
1145 | &f_midi_opts_attr_qlen, | |
1146 | &f_midi_opts_attr_in_ports, | |
1147 | &f_midi_opts_attr_out_ports, | |
1148 | &f_midi_opts_attr_id, | |
6f1de344 AP |
1149 | NULL, |
1150 | }; | |
1151 | ||
1152 | static struct config_item_type midi_func_type = { | |
1153 | .ct_item_ops = &midi_item_ops, | |
1154 | .ct_attrs = midi_attrs, | |
1155 | .ct_owner = THIS_MODULE, | |
1156 | }; | |
1157 | ||
b85e9de9 AP |
1158 | static void f_midi_free_inst(struct usb_function_instance *f) |
1159 | { | |
1160 | struct f_midi_opts *opts; | |
1161 | ||
1162 | opts = container_of(f, struct f_midi_opts, func_inst); | |
1163 | ||
6f1de344 AP |
1164 | if (opts->id_allocated) |
1165 | kfree(opts->id); | |
1166 | ||
b85e9de9 AP |
1167 | kfree(opts); |
1168 | } | |
1169 | ||
1170 | static struct usb_function_instance *f_midi_alloc_inst(void) | |
1171 | { | |
1172 | struct f_midi_opts *opts; | |
1173 | ||
1174 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | |
1175 | if (!opts) | |
1176 | return ERR_PTR(-ENOMEM); | |
6f1de344 AP |
1177 | |
1178 | mutex_init(&opts->lock); | |
b85e9de9 | 1179 | opts->func_inst.free_func_inst = f_midi_free_inst; |
6f1de344 AP |
1180 | opts->index = SNDRV_DEFAULT_IDX1; |
1181 | opts->id = SNDRV_DEFAULT_STR1; | |
7ea9fde7 | 1182 | opts->buflen = 512; |
6f1de344 AP |
1183 | opts->qlen = 32; |
1184 | opts->in_ports = 1; | |
1185 | opts->out_ports = 1; | |
1186 | ||
1187 | config_group_init_type_name(&opts->func_inst.group, "", | |
1188 | &midi_func_type); | |
b85e9de9 AP |
1189 | |
1190 | return &opts->func_inst; | |
1191 | } | |
1192 | ||
1193 | static void f_midi_free(struct usb_function *f) | |
1194 | { | |
1195 | struct f_midi *midi; | |
1196 | struct f_midi_opts *opts; | |
b85e9de9 AP |
1197 | |
1198 | midi = func_to_midi(f); | |
1199 | opts = container_of(f->fi, struct f_midi_opts, func_inst); | |
1200 | kfree(midi->id); | |
6f1de344 | 1201 | mutex_lock(&opts->lock); |
e1e3d7ec | 1202 | kfifo_free(&midi->in_req_fifo); |
b85e9de9 | 1203 | kfree(midi); |
6f1de344 AP |
1204 | --opts->refcnt; |
1205 | mutex_unlock(&opts->lock); | |
b85e9de9 AP |
1206 | } |
1207 | ||
1208 | static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) | |
1209 | { | |
1210 | struct usb_composite_dev *cdev = f->config->cdev; | |
1211 | struct f_midi *midi = func_to_midi(f); | |
1212 | struct snd_card *card; | |
1213 | ||
1214 | DBG(cdev, "unbind\n"); | |
1215 | ||
1216 | /* just to be sure */ | |
1217 | f_midi_disable(f); | |
1218 | ||
1219 | card = midi->card; | |
1220 | midi->card = NULL; | |
1221 | if (card) | |
1222 | snd_card_free(card); | |
1223 | ||
1224 | usb_free_all_descriptors(f); | |
1225 | } | |
1226 | ||
f509fee8 | 1227 | static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) |
b85e9de9 | 1228 | { |
413489c8 | 1229 | struct f_midi *midi = NULL; |
b85e9de9 AP |
1230 | struct f_midi_opts *opts; |
1231 | int status, i; | |
1232 | ||
1233 | opts = container_of(fi, struct f_midi_opts, func_inst); | |
6f1de344 AP |
1234 | |
1235 | mutex_lock(&opts->lock); | |
b85e9de9 | 1236 | /* sanity check */ |
6f1de344 | 1237 | if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) { |
413489c8 DC |
1238 | status = -EINVAL; |
1239 | goto setup_fail; | |
6f1de344 | 1240 | } |
b85e9de9 AP |
1241 | |
1242 | /* allocate and initialize one new instance */ | |
bf0028f8 MN |
1243 | midi = kzalloc( |
1244 | sizeof(*midi) + opts->in_ports * sizeof(*midi->in_ports_array), | |
1245 | GFP_KERNEL); | |
6f1de344 | 1246 | if (!midi) { |
413489c8 DC |
1247 | status = -ENOMEM; |
1248 | goto setup_fail; | |
6f1de344 | 1249 | } |
b85e9de9 | 1250 | |
bf0028f8 MN |
1251 | for (i = 0; i < opts->in_ports; i++) |
1252 | midi->in_ports_array[i].cable = i; | |
b85e9de9 AP |
1253 | |
1254 | /* set up ALSA midi devices */ | |
1255 | midi->id = kstrdup(opts->id, GFP_KERNEL); | |
1256 | if (opts->id && !midi->id) { | |
1257 | status = -ENOMEM; | |
b2e2c94b | 1258 | goto setup_fail; |
b85e9de9 AP |
1259 | } |
1260 | midi->in_ports = opts->in_ports; | |
1261 | midi->out_ports = opts->out_ports; | |
1262 | midi->index = opts->index; | |
1263 | midi->buflen = opts->buflen; | |
1264 | midi->qlen = opts->qlen; | |
e1e3d7ec FT |
1265 | midi->in_last_port = 0; |
1266 | ||
1267 | status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL); | |
1268 | if (status) | |
1269 | goto setup_fail; | |
1270 | ||
9acdf4df FT |
1271 | spin_lock_init(&midi->transmit_lock); |
1272 | ||
6f1de344 AP |
1273 | ++opts->refcnt; |
1274 | mutex_unlock(&opts->lock); | |
b85e9de9 AP |
1275 | |
1276 | midi->func.name = "gmidi function"; | |
b85e9de9 AP |
1277 | midi->func.bind = f_midi_bind; |
1278 | midi->func.unbind = f_midi_unbind; | |
1279 | midi->func.set_alt = f_midi_set_alt; | |
1280 | midi->func.disable = f_midi_disable; | |
1281 | midi->func.free_func = f_midi_free; | |
1282 | ||
1283 | return &midi->func; | |
1284 | ||
b85e9de9 | 1285 | setup_fail: |
413489c8 | 1286 | mutex_unlock(&opts->lock); |
b85e9de9 AP |
1287 | kfree(midi); |
1288 | return ERR_PTR(status); | |
1289 | } | |
1290 | ||
1291 | DECLARE_USB_FUNCTION_INIT(midi, f_midi_alloc_inst, f_midi_alloc); |