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 28static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream) 29{ 30 return 0; 31} 32 33static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream) 34{ 35 return 0; 36} 37 38static 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 49static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream) 50{ 51 return 0; 52} 53 54static 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 64static 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 89static 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 103static 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 110static 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 117void 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 126int 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 strcpy(rmidi->name, device->product_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 161void 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