Lines Matching full:midi
3 * f_midi.c -- USB MIDI class function driver
16 * and drivers/usb/gadget/midi.c,
36 #include <linux/usb/midi.h>
41 MODULE_DESCRIPTION("USB MIDI class function driver");
45 static const char f_midi_longname[] = "MIDI Gadget";
54 /* MIDI message states */
111 static void f_midi_transmit(struct f_midi *midi);
214 [STRING_FUNC_IDX].s = "MIDI function",
239 * Receives a chunk of MIDI data.
244 struct f_midi *midi = ep->driver_data; in f_midi_read_data() local
245 struct snd_rawmidi_substream *substream = midi->out_substream[cable]; in f_midi_read_data()
251 if (!test_bit(cable, &midi->out_triggered)) in f_midi_read_data()
273 struct f_midi *midi = ep->driver_data; in f_midi_complete() local
274 struct usb_composite_dev *cdev = midi->func.config->cdev; in f_midi_complete()
279 if (ep == midi->out_ep) { in f_midi_complete()
282 } else if (ep == midi->in_ep) { in f_midi_complete()
286 queue_work(system_highpri_wq, &midi->work); in f_midi_complete()
297 if (ep == midi->out_ep) { in f_midi_complete()
300 * by the midi->in_req_fifo. */ in f_midi_complete()
325 static void f_midi_drop_out_substreams(struct f_midi *midi) in f_midi_drop_out_substreams() argument
329 for (i = 0; i < midi->in_ports; i++) { in f_midi_drop_out_substreams()
330 struct gmidi_in_port *port = midi->in_ports_array + i; in f_midi_drop_out_substreams()
338 static int f_midi_start_ep(struct f_midi *midi, in f_midi_start_ep() argument
347 err = config_ep_by_speed(midi->gadget, f, ep); in f_midi_start_ep()
359 ep->driver_data = midi; in f_midi_start_ep()
366 struct f_midi *midi = func_to_midi(f); in f_midi_set_alt() local
371 if (intf != midi->ms_id) in f_midi_set_alt()
374 err = f_midi_start_ep(midi, f, midi->in_ep); in f_midi_set_alt()
378 err = f_midi_start_ep(midi, f, midi->out_ep); in f_midi_set_alt()
383 while (kfifo_avail(&midi->in_req_fifo)) { in f_midi_set_alt()
385 midi_alloc_ep_req(midi->in_ep, midi->buflen); in f_midi_set_alt()
393 kfifo_put(&midi->in_req_fifo, req); in f_midi_set_alt()
397 for (i = 0; i < midi->qlen && err == 0; i++) { in f_midi_set_alt()
399 midi_alloc_ep_req(midi->out_ep, midi->buflen); in f_midi_set_alt()
405 err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC); in f_midi_set_alt()
407 ERROR(midi, "%s: couldn't enqueue request: %d\n", in f_midi_set_alt()
408 midi->out_ep->name, err); in f_midi_set_alt()
410 free_ep_req(midi->out_ep, req); in f_midi_set_alt()
420 struct f_midi *midi = func_to_midi(f); in f_midi_disable() local
430 usb_ep_disable(midi->in_ep); in f_midi_disable()
431 usb_ep_disable(midi->out_ep); in f_midi_disable()
434 while (kfifo_get(&midi->in_req_fifo, &req)) in f_midi_disable()
435 free_ep_req(midi->in_ep, req); in f_midi_disable()
437 f_midi_drop_out_substreams(midi); in f_midi_disable()
446 * Converts MIDI commands to USB MIDI packets.
607 static int f_midi_do_transmit(struct f_midi *midi, struct usb_ep *ep) in f_midi_do_transmit() argument
618 len = kfifo_peek(&midi->in_req_fifo, &req); in f_midi_do_transmit()
620 ERROR(midi, "%s: Couldn't get usb request\n", __func__); in f_midi_do_transmit()
633 for (i = midi->in_last_port; i < midi->in_ports; ++i) { in f_midi_do_transmit()
634 struct gmidi_in_port *port = midi->in_ports_array + i; in f_midi_do_transmit()
640 while (req->length + 3 < midi->buflen) { in f_midi_do_transmit()
654 midi->in_last_port = active ? i : 0; in f_midi_do_transmit()
661 ERROR(midi, "%s failed to queue req: %d\n", in f_midi_do_transmit()
662 midi->in_ep->name, err); in f_midi_do_transmit()
666 kfifo_skip(&midi->in_req_fifo); in f_midi_do_transmit()
667 kfifo_put(&midi->in_req_fifo, req); in f_midi_do_transmit()
674 static void f_midi_transmit(struct f_midi *midi) in f_midi_transmit() argument
676 struct usb_ep *ep = midi->in_ep; in f_midi_transmit()
684 spin_lock_irqsave(&midi->transmit_lock, flags); in f_midi_transmit()
687 ret = f_midi_do_transmit(midi, ep); in f_midi_transmit()
689 spin_unlock_irqrestore(&midi->transmit_lock, flags); in f_midi_transmit()
694 spin_unlock_irqrestore(&midi->transmit_lock, flags); in f_midi_transmit()
699 f_midi_drop_out_substreams(midi); in f_midi_transmit()
704 struct f_midi *midi; in f_midi_in_work() local
706 midi = container_of(work, struct f_midi, work); in f_midi_in_work()
707 f_midi_transmit(midi); in f_midi_in_work()
712 struct f_midi *midi = substream->rmidi->private_data; in f_midi_in_open() local
715 if (substream->number >= midi->in_ports) in f_midi_in_open()
718 VDBG(midi, "%s()\n", __func__); in f_midi_in_open()
719 port = midi->in_ports_array + substream->number; in f_midi_in_open()
727 struct f_midi *midi = substream->rmidi->private_data; in f_midi_in_close() local
729 VDBG(midi, "%s()\n", __func__); in f_midi_in_close()
735 struct f_midi *midi = substream->rmidi->private_data; in f_midi_in_trigger() local
737 if (substream->number >= midi->in_ports) in f_midi_in_trigger()
740 VDBG(midi, "%s() %d\n", __func__, up); in f_midi_in_trigger()
741 midi->in_ports_array[substream->number].active = up; in f_midi_in_trigger()
743 queue_work(system_highpri_wq, &midi->work); in f_midi_in_trigger()
748 struct f_midi *midi = substream->rmidi->private_data; in f_midi_out_open() local
753 VDBG(midi, "%s()\n", __func__); in f_midi_out_open()
754 midi->out_substream[substream->number] = substream; in f_midi_out_open()
760 struct f_midi *midi = substream->rmidi->private_data; in f_midi_out_close() local
762 VDBG(midi, "%s()\n", __func__); in f_midi_out_close()
768 struct f_midi *midi = substream->rmidi->private_data; in f_midi_out_trigger() local
770 VDBG(midi, "%s()\n", __func__); in f_midi_out_trigger()
773 set_bit(substream->number, &midi->out_triggered); in f_midi_out_trigger()
775 clear_bit(substream->number, &midi->out_triggered); in f_midi_out_trigger()
790 static inline void f_midi_unregister_card(struct f_midi *midi) in f_midi_unregister_card() argument
792 if (midi->card) { in f_midi_unregister_card()
793 snd_card_free(midi->card); in f_midi_unregister_card()
794 midi->card = NULL; in f_midi_unregister_card()
799 static int f_midi_register_card(struct f_midi *midi) in f_midi_register_card() argument
808 err = snd_card_new(&midi->gadget->dev, midi->index, midi->id, in f_midi_register_card()
811 ERROR(midi, "snd_card_new() failed\n"); in f_midi_register_card()
814 midi->card = card; in f_midi_register_card()
816 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, midi, &ops); in f_midi_register_card()
818 ERROR(midi, "snd_device_new() failed: error %d\n", err); in f_midi_register_card()
827 snd_component_add(card, "MIDI"); in f_midi_register_card()
829 midi->out_ports, midi->in_ports, &rmidi); in f_midi_register_card()
831 ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err); in f_midi_register_card()
834 midi->rmidi = rmidi; in f_midi_register_card()
835 midi->in_last_port = 0; in f_midi_register_card()
840 rmidi->private_data = midi; in f_midi_register_card()
842 midi->free_ref++; in f_midi_register_card()
854 ERROR(midi, "snd_card_register() failed\n"); in f_midi_register_card()
858 VDBG(midi, "%s() finished ok\n", __func__); in f_midi_register_card()
862 f_midi_unregister_card(midi); in f_midi_register_card()
866 /* MIDI function driver setup/binding */
876 struct f_midi *midi = func_to_midi(f); in f_midi_bind() local
880 midi->gadget = cdev->gadget; in f_midi_bind()
881 INIT_WORK(&midi->work, f_midi_in_work); in f_midi_bind()
882 status = f_midi_register_card(midi); in f_midi_bind()
906 midi->ms_id = status; in f_midi_bind()
920 midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc); in f_midi_bind()
921 if (!midi->in_ep) in f_midi_bind()
924 midi->out_ep = usb_ep_autoconfig(cdev->gadget, &bulk_out_desc); in f_midi_bind()
925 if (!midi->out_ep) in f_midi_bind()
938 * input and output MIDI ports is configurable, we have to do in f_midi_bind()
949 + (midi->in_ports + midi->out_ports) * in f_midi_bind()
956 for (n = 0; n < midi->in_ports; n++) { in f_midi_bind()
984 for (n = 0; n < midi->out_ports; n++) { in f_midi_bind()
1012 ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); in f_midi_bind()
1013 ms_out_desc.bNumEmbMIDIJack = midi->out_ports; in f_midi_bind()
1015 ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); in f_midi_bind()
1016 ms_in_desc.bNumEmbMIDIJack = midi->in_ports; in f_midi_bind()
1069 f_midi_unregister_card(midi); in f_midi_bind()
1297 struct f_midi *midi; in f_midi_free() local
1301 midi = func_to_midi(f); in f_midi_free()
1304 if (!--midi->free_ref) { in f_midi_free()
1305 kfree(midi->id); in f_midi_free()
1306 kfifo_free(&midi->in_req_fifo); in f_midi_free()
1307 kfree(midi); in f_midi_free()
1324 struct f_midi *midi = func_to_midi(f); in f_midi_unbind() local
1332 card = midi->card; in f_midi_unbind()
1333 midi->card = NULL; in f_midi_unbind()
1342 struct f_midi *midi = NULL; in f_midi_alloc() local
1356 midi = kzalloc(struct_size(midi, in_ports_array, opts->in_ports), in f_midi_alloc()
1358 if (!midi) { in f_midi_alloc()
1362 midi->in_ports = opts->in_ports; in f_midi_alloc()
1365 midi->in_ports_array[i].cable = i; in f_midi_alloc()
1367 /* set up ALSA midi devices */ in f_midi_alloc()
1368 midi->id = kstrdup(opts->id, GFP_KERNEL); in f_midi_alloc()
1369 if (opts->id && !midi->id) { in f_midi_alloc()
1373 midi->out_ports = opts->out_ports; in f_midi_alloc()
1374 midi->index = opts->index; in f_midi_alloc()
1375 midi->buflen = opts->buflen; in f_midi_alloc()
1376 midi->qlen = opts->qlen; in f_midi_alloc()
1377 midi->in_last_port = 0; in f_midi_alloc()
1378 midi->free_ref = 1; in f_midi_alloc()
1380 status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL); in f_midi_alloc()
1384 spin_lock_init(&midi->transmit_lock); in f_midi_alloc()
1389 midi->func.name = "gmidi function"; in f_midi_alloc()
1390 midi->func.bind = f_midi_bind; in f_midi_alloc()
1391 midi->func.unbind = f_midi_unbind; in f_midi_alloc()
1392 midi->func.set_alt = f_midi_set_alt; in f_midi_alloc()
1393 midi->func.disable = f_midi_disable; in f_midi_alloc()
1394 midi->func.free_func = f_midi_free; in f_midi_alloc()
1396 return &midi->func; in f_midi_alloc()
1399 if (midi) in f_midi_alloc()
1400 kfree(midi->id); in f_midi_alloc()
1401 kfree(midi); in f_midi_alloc()
1408 DECLARE_USB_FUNCTION_INIT(midi, f_midi_alloc_inst, f_midi_alloc);