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 <linux/gfp.h> 21 #include <sound/rawmidi.h> 22 #include <sound/core.h> 23 #include <sound/pcm.h> 24 25 #include "device.h" 26 #include "midi.h" 27 28 static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream) 29 { 30 return 0; 31 } 32 33 static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream) 34 { 35 return 0; 36 } 37 38 static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) 39 { 40 struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; 41 42 if (!dev) 43 return; 44 45 dev->midi_receive_substream = up ? substream : NULL; 46 } 47 48 49 static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream) 50 { 51 return 0; 52 } 53 54 static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream) 55 { 56 struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; 57 if (dev->midi_out_active) { 58 usb_kill_urb(&dev->midi_out_urb); 59 dev->midi_out_active = 0; 60 } 61 return 0; 62 } 63 64 static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *dev, 65 struct snd_rawmidi_substream *substream) 66 { 67 int len, ret; 68 69 dev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE; 70 dev->midi_out_buf[1] = 0; /* port */ 71 len = snd_rawmidi_transmit(substream, dev->midi_out_buf + 3, 72 EP1_BUFSIZE - 3); 73 74 if (len <= 0) 75 return; 76 77 dev->midi_out_buf[2] = len; 78 dev->midi_out_urb.transfer_buffer_length = len+3; 79 80 ret = usb_submit_urb(&dev->midi_out_urb, GFP_ATOMIC); 81 if (ret < 0) 82 log("snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed," 83 "ret=%d, len=%d\n", 84 substream, ret, len); 85 else 86 dev->midi_out_active = 1; 87 } 88 89 static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up) 90 { 91 struct snd_usb_caiaqdev *dev = substream->rmidi->private_data; 92 93 if (up) { 94 dev->midi_out_substream = substream; 95 if (!dev->midi_out_active) 96 snd_usb_caiaq_midi_send(dev, substream); 97 } else { 98 dev->midi_out_substream = NULL; 99 } 100 } 101 102 103 static struct snd_rawmidi_ops snd_usb_caiaq_midi_output = 104 { 105 .open = snd_usb_caiaq_midi_output_open, 106 .close = snd_usb_caiaq_midi_output_close, 107 .trigger = snd_usb_caiaq_midi_output_trigger, 108 }; 109 110 static struct snd_rawmidi_ops snd_usb_caiaq_midi_input = 111 { 112 .open = snd_usb_caiaq_midi_input_open, 113 .close = snd_usb_caiaq_midi_input_close, 114 .trigger = snd_usb_caiaq_midi_input_trigger, 115 }; 116 117 void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, 118 int port, const char *buf, int len) 119 { 120 if (!dev->midi_receive_substream) 121 return; 122 123 snd_rawmidi_receive(dev->midi_receive_substream, buf, len); 124 } 125 126 int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) 127 { 128 int ret; 129 struct snd_rawmidi *rmidi; 130 131 ret = snd_rawmidi_new(device->chip.card, device->product_name, 0, 132 device->spec.num_midi_out, 133 device->spec.num_midi_in, 134 &rmidi); 135 136 if (ret < 0) 137 return ret; 138 139 strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name)); 140 141 rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX; 142 rmidi->private_data = device; 143 144 if (device->spec.num_midi_out > 0) { 145 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; 146 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, 147 &snd_usb_caiaq_midi_output); 148 } 149 150 if (device->spec.num_midi_in > 0) { 151 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; 152 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, 153 &snd_usb_caiaq_midi_input); 154 } 155 156 device->rmidi = rmidi; 157 158 return 0; 159 } 160 161 void snd_usb_caiaq_midi_output_done(struct urb* urb) 162 { 163 struct snd_usb_caiaqdev *dev = urb->context; 164 165 dev->midi_out_active = 0; 166 if (urb->status != 0) 167 return; 168 169 if (!dev->midi_out_substream) 170 return; 171 172 snd_usb_caiaq_midi_send(dev, dev->midi_out_substream); 173 } 174 175