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