midi.c (3849B)
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 16static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream) 17{ 18 return 0; 19} 20 21static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream) 22{ 23 return 0; 24} 25 26static 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 37static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream) 38{ 39 return 0; 40} 41 42static 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 52static 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 78static 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 92static 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 99static 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 106void 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 115int 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 150void 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}