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