1 /* 2 * Copyright (c) 2006,2007 Daniel Mack 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 #include <linux/usb.h> 20 #include <sound/rawmidi.h> 21 #include <sound/core.h> 22 #include <sound/pcm.h> 23 24 #include "device.h" 25 #include "midi.h" 26 27 static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream) 28 { 29 return 0; 30 } 31 32 static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream) 33 { 34 return 0; 35 } 36 37 static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 38 { 39 struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; 40 41 if (!dev) 42 return; 43 44 dev->midi_receive_substream = up ? substream : NULL; 45 } 46 47 48 static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream) 49 { 50 return 0; 51 } 52 53 static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream) 54 { 55 struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; 56 if (dev->midi_out_active) { 57 usb_kill_urb(&dev->midi_out_urb); 58 dev->midi_out_active = 0; 59 } 60 return 0; 61 } 62 63 static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, 64 struct snd_rawmidi_substream *substream) 65 { 66 int len, ret; 67 68 dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; 69 dev->midi_out_buf[1] = 0; /* port */ 70 len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3, 71 EP1_BUFSIZE - 3); 72 73 if (len <= 0) 74 return; 75 76 dev->midi_out_buf[2] = len; 77 dev->midi_out_urb.transfer_buffer_length = len+3; 78 79 ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC); 80 if (ret < 0) 81 log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," 82 "ret=%d, len=%d\n", 83 substream, ret, len); 84 else 85 dev->midi_out_active = 1; 86 } 87 88 static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 89 { 90 struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; 91 92 if (up) { 93 dev->midi_out_substream = substream; 94 if (!dev->midi_out_active) 95 snd_usb_caiaq_midi_send(dev, substream); 96 } else { 97 dev->midi_out_substream = NULL; 98 } 99 } 100 101 102 static struct snd_rawmidi_ops snd_usb_caiaq_midi_output = 103 { 104 .open = snd_usb_caiaq_midi_output_open, 105 .close = snd_usb_caiaq_midi_output_close, 106 .trigger = snd_usb_caiaq_midi_output_trigger, 107 }; 108 109 static struct snd_rawmidi_ops snd_usb_caiaq_midi_input = 110 { 111 .open = snd_usb_caiaq_midi_input_open, 112 .close = snd_usb_caiaq_midi_input_close, 113 .trigger = snd_usb_caiaq_midi_input_trigger, 114 }; 115 116 void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, 117 int port, const char *buf, int len) 118 { 119 if (!dev->midi_receive_substream) 120 return; 121 122 snd_rawmidi_receive(dev->midi_receive_substream, buf, len); 123 } 124 125 int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) 126 { 127 int ret; 128 struct snd_rawmidi *rmidi; 129 130 ret = snd_rawmidi_new(device->chip.card, device->product_name, 0, 131 device->spec.num_midi_out, 132 device->spec.num_midi_in, 133 &rmidi); 134 135 if (ret < 0) 136 return ret; 137 138 strcpy(rmidi->name, device->product_name); 139 140 rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX; 141 rmidi->private_data = device; 142 143 if (device->spec.num_midi_out > 0) { 144 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; 145 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 146 &snd_usb_caiaq_midi_output); 147 } 148 149 if (device->spec.num_midi_in > 0) { 150 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 151 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 152 &snd_usb_caiaq_midi_input); 153 } 154 155 device->rmidi = rmidi; 156 157 return 0; 158 } 159 160 void snd_usb_caiaq_midi_output_done(struct urb* urb) 161 { 162 struct snd_usb_caiaqdev *dev = urb->context; 163 164 dev->midi_out_active = 0; 165 if (urb->status != 0) 166 return; 167 168 if (!dev->midi_out_substream) 169 return; 170 171 snd_usb_caiaq_midi_send(dev, dev->midi_out_substream); 172 } 173 174