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 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 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 } 163