| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 1 | /* | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 2 | *   Copyright (c) 2006-2008 Daniel Mack, Karsten Wiese | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 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 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 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/spinlock.h> | 
|  | 25 | #include <sound/core.h> | 
|  | 26 | #include <sound/initval.h> | 
|  | 27 | #include <sound/pcm.h> | 
|  | 28 | #include <sound/rawmidi.h> | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 29 | #include <linux/input.h> | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 30 |  | 
|  | 31 | #include "caiaq-device.h" | 
|  | 32 | #include "caiaq-audio.h" | 
|  | 33 |  | 
|  | 34 | #define N_URBS			32 | 
|  | 35 | #define CLOCK_DRIFT_TOLERANCE	5 | 
|  | 36 | #define FRAMES_PER_URB		8 | 
|  | 37 | #define BYTES_PER_FRAME		512 | 
|  | 38 | #define CHANNELS_PER_STREAM	2 | 
|  | 39 | #define BYTES_PER_SAMPLE	3 | 
|  | 40 | #define BYTES_PER_SAMPLE_USB	4 | 
|  | 41 | #define MAX_BUFFER_SIZE		(128*1024) | 
| Daniel Mack | 6e9fc6b | 2008-04-14 15:40:31 +0200 | [diff] [blame] | 42 | #define MAX_ENDPOINT_SIZE	512 | 
|  | 43 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 44 | #define ENDPOINT_CAPTURE	2 | 
|  | 45 | #define ENDPOINT_PLAYBACK	6 | 
|  | 46 |  | 
|  | 47 | #define MAKE_CHECKBYTE(dev,stream,i) \ | 
|  | 48 | (stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1) | 
|  | 49 |  | 
|  | 50 | static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = { | 
|  | 51 | .info 		= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 
|  | 52 | SNDRV_PCM_INFO_BLOCK_TRANSFER), | 
|  | 53 | .formats 	= SNDRV_PCM_FMTBIT_S24_3BE, | 
|  | 54 | .rates 		= (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | 
|  | 55 | SNDRV_PCM_RATE_96000), | 
|  | 56 | .rate_min	= 44100, | 
|  | 57 | .rate_max	= 0, /* will overwrite later */ | 
|  | 58 | .channels_min	= CHANNELS_PER_STREAM, | 
|  | 59 | .channels_max	= CHANNELS_PER_STREAM, | 
|  | 60 | .buffer_bytes_max = MAX_BUFFER_SIZE, | 
| Daniel Mack | 09189ac | 2008-01-24 18:46:42 +0100 | [diff] [blame] | 61 | .period_bytes_min = 128, | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 62 | .period_bytes_max = MAX_BUFFER_SIZE, | 
|  | 63 | .periods_min	= 1, | 
|  | 64 | .periods_max	= 1024, | 
|  | 65 | }; | 
|  | 66 |  | 
|  | 67 | static void | 
|  | 68 | activate_substream(struct snd_usb_caiaqdev *dev, | 
|  | 69 | struct snd_pcm_substream *sub) | 
|  | 70 | { | 
|  | 71 | if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | 
|  | 72 | dev->sub_playback[sub->number] = sub; | 
|  | 73 | else | 
|  | 74 | dev->sub_capture[sub->number] = sub; | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | static void | 
|  | 78 | deactivate_substream(struct snd_usb_caiaqdev *dev, | 
|  | 79 | struct snd_pcm_substream *sub) | 
|  | 80 | { | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 81 | unsigned long flags; | 
|  | 82 | spin_lock_irqsave(&dev->spinlock, flags); | 
|  | 83 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 84 | if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | 
|  | 85 | dev->sub_playback[sub->number] = NULL; | 
|  | 86 | else | 
|  | 87 | dev->sub_capture[sub->number] = NULL; | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 88 |  | 
|  | 89 | spin_unlock_irqrestore(&dev->spinlock, flags); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 90 | } | 
|  | 91 |  | 
|  | 92 | static int | 
|  | 93 | all_substreams_zero(struct snd_pcm_substream **subs) | 
|  | 94 | { | 
|  | 95 | int i; | 
|  | 96 | for (i = 0; i < MAX_STREAMS; i++) | 
|  | 97 | if (subs[i] != NULL) | 
|  | 98 | return 0; | 
|  | 99 | return 1; | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | static int stream_start(struct snd_usb_caiaqdev *dev) | 
|  | 103 | { | 
|  | 104 | int i, ret; | 
|  | 105 |  | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 106 | debug("%s(%p)\n", __func__, dev); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 107 |  | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 108 | if (dev->streaming) | 
|  | 109 | return -EINVAL; | 
|  | 110 |  | 
|  | 111 | memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); | 
|  | 112 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 113 | dev->input_panic = 0; | 
|  | 114 | dev->output_panic = 0; | 
|  | 115 | dev->first_packet = 1; | 
|  | 116 | dev->streaming = 1; | 
|  | 117 |  | 
|  | 118 | for (i = 0; i < N_URBS; i++) { | 
|  | 119 | ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC); | 
|  | 120 | if (ret) { | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 121 | log("unable to trigger read #%d! (ret %d)\n", i, ret); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 122 | dev->streaming = 0; | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 123 | return -EPIPE; | 
|  | 124 | } | 
|  | 125 | } | 
|  | 126 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 127 | return 0; | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | static void stream_stop(struct snd_usb_caiaqdev *dev) | 
|  | 131 | { | 
|  | 132 | int i; | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 133 |  | 
|  | 134 | debug("%s(%p)\n", __func__, dev); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 135 | if (!dev->streaming) | 
|  | 136 | return; | 
|  | 137 |  | 
|  | 138 | dev->streaming = 0; | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 139 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 140 | for (i = 0; i < N_URBS; i++) { | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 141 | usb_kill_urb(dev->data_urbs_in[i]); | 
|  | 142 | usb_kill_urb(dev->data_urbs_out[i]); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 143 | } | 
|  | 144 | } | 
|  | 145 |  | 
|  | 146 | static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) | 
|  | 147 | { | 
|  | 148 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 149 | debug("%s(%p)\n", __func__, substream); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 150 | substream->runtime->hw = dev->pcm_info; | 
|  | 151 | snd_pcm_limit_hw_rates(substream->runtime); | 
|  | 152 | return 0; | 
|  | 153 | } | 
|  | 154 |  | 
|  | 155 | static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) | 
|  | 156 | { | 
|  | 157 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); | 
|  | 158 |  | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 159 | debug("%s(%p)\n", __func__, substream); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 160 | if (all_substreams_zero(dev->sub_playback) && | 
|  | 161 | all_substreams_zero(dev->sub_capture)) { | 
|  | 162 | /* when the last client has stopped streaming, | 
|  | 163 | * all sample rates are allowed again */ | 
|  | 164 | stream_stop(dev); | 
|  | 165 | dev->pcm_info.rates = dev->samplerates; | 
|  | 166 | } | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 167 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 168 | return 0; | 
|  | 169 | } | 
|  | 170 |  | 
|  | 171 | static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, | 
|  | 172 | struct snd_pcm_hw_params *hw_params) | 
|  | 173 | { | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 174 | debug("%s(%p)\n", __func__, sub); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 175 | return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); | 
|  | 176 | } | 
|  | 177 |  | 
|  | 178 | static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) | 
|  | 179 | { | 
|  | 180 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 181 | debug("%s(%p)\n", __func__, sub); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 182 | deactivate_substream(dev, sub); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 183 | return snd_pcm_lib_free_pages(sub); | 
|  | 184 | } | 
|  | 185 |  | 
|  | 186 | /* this should probably go upstream */ | 
|  | 187 | #if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 | 
|  | 188 | #error "Change this table" | 
|  | 189 | #endif | 
|  | 190 |  | 
|  | 191 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | 
|  | 192 | 48000, 64000, 88200, 96000, 176400, 192000 }; | 
|  | 193 |  | 
|  | 194 | static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | 
|  | 195 | { | 
|  | 196 | int bytes_per_sample, bpp, ret, i; | 
|  | 197 | int index = substream->number; | 
|  | 198 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); | 
|  | 199 | struct snd_pcm_runtime *runtime = substream->runtime; | 
|  | 200 |  | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 201 | debug("%s(%p)\n", __func__, substream); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 202 |  | 
|  | 203 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 
|  | 204 | dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; | 
|  | 205 | else | 
| Daniel Mack | 6849d49 | 2008-04-14 15:39:47 +0200 | [diff] [blame] | 206 | dev->audio_in_buf_pos[index] = BYTES_PER_SAMPLE; | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 207 |  | 
|  | 208 | if (dev->streaming) | 
|  | 209 | return 0; | 
|  | 210 |  | 
|  | 211 | /* the first client that opens a stream defines the sample rate | 
|  | 212 | * setting for all subsequent calls, until the last client closed. */ | 
|  | 213 | for (i=0; i < ARRAY_SIZE(rates); i++) | 
|  | 214 | if (runtime->rate == rates[i]) | 
|  | 215 | dev->pcm_info.rates = 1 << i; | 
|  | 216 |  | 
|  | 217 | snd_pcm_limit_hw_rates(runtime); | 
|  | 218 |  | 
|  | 219 | bytes_per_sample = BYTES_PER_SAMPLE; | 
|  | 220 | if (dev->spec.data_alignment == 2) | 
|  | 221 | bytes_per_sample++; | 
|  | 222 |  | 
|  | 223 | bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) | 
|  | 224 | * bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams; | 
| Daniel Mack | 6e9fc6b | 2008-04-14 15:40:31 +0200 | [diff] [blame] | 225 |  | 
|  | 226 | if (bpp > MAX_ENDPOINT_SIZE) | 
|  | 227 | bpp = MAX_ENDPOINT_SIZE; | 
|  | 228 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 229 | ret = snd_usb_caiaq_set_audio_params(dev, runtime->rate, | 
|  | 230 | runtime->sample_bits, bpp); | 
|  | 231 | if (ret) | 
|  | 232 | return ret; | 
|  | 233 |  | 
|  | 234 | ret = stream_start(dev); | 
|  | 235 | if (ret) | 
|  | 236 | return ret; | 
|  | 237 |  | 
|  | 238 | dev->output_running = 0; | 
|  | 239 | wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ); | 
|  | 240 | if (!dev->output_running) { | 
|  | 241 | stream_stop(dev); | 
|  | 242 | return -EPIPE; | 
|  | 243 | } | 
|  | 244 |  | 
|  | 245 | return 0; | 
|  | 246 | } | 
|  | 247 |  | 
|  | 248 | static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) | 
|  | 249 | { | 
|  | 250 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | 
|  | 251 |  | 
|  | 252 | switch (cmd) { | 
|  | 253 | case SNDRV_PCM_TRIGGER_START: | 
|  | 254 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 255 | activate_substream(dev, sub); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 256 | break; | 
|  | 257 | case SNDRV_PCM_TRIGGER_STOP: | 
|  | 258 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 259 | deactivate_substream(dev, sub); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 260 | break; | 
|  | 261 | default: | 
|  | 262 | return -EINVAL; | 
|  | 263 | } | 
|  | 264 |  | 
|  | 265 | return 0; | 
|  | 266 | } | 
|  | 267 |  | 
|  | 268 | static snd_pcm_uframes_t | 
|  | 269 | snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub) | 
|  | 270 | { | 
|  | 271 | int index = sub->number; | 
|  | 272 | struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | 
|  | 273 |  | 
|  | 274 | if (dev->input_panic || dev->output_panic) | 
|  | 275 | return SNDRV_PCM_POS_XRUN; | 
|  | 276 |  | 
|  | 277 | if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | 
|  | 278 | return bytes_to_frames(sub->runtime, | 
|  | 279 | dev->audio_out_buf_pos[index]); | 
|  | 280 | else | 
|  | 281 | return bytes_to_frames(sub->runtime, | 
|  | 282 | dev->audio_in_buf_pos[index]); | 
|  | 283 | } | 
|  | 284 |  | 
|  | 285 | /* operators for both playback and capture */ | 
|  | 286 | static struct snd_pcm_ops snd_usb_caiaq_ops = { | 
|  | 287 | .open =		snd_usb_caiaq_substream_open, | 
|  | 288 | .close =	snd_usb_caiaq_substream_close, | 
|  | 289 | .ioctl =	snd_pcm_lib_ioctl, | 
|  | 290 | .hw_params =	snd_usb_caiaq_pcm_hw_params, | 
|  | 291 | .hw_free =	snd_usb_caiaq_pcm_hw_free, | 
|  | 292 | .prepare =	snd_usb_caiaq_pcm_prepare, | 
|  | 293 | .trigger =	snd_usb_caiaq_pcm_trigger, | 
|  | 294 | .pointer =	snd_usb_caiaq_pcm_pointer | 
|  | 295 | }; | 
|  | 296 |  | 
|  | 297 | static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev, | 
|  | 298 | struct snd_pcm_substream **subs) | 
|  | 299 | { | 
|  | 300 | int stream, pb, *cnt; | 
|  | 301 | struct snd_pcm_substream *sub; | 
|  | 302 |  | 
|  | 303 | for (stream = 0; stream < dev->n_streams; stream++) { | 
|  | 304 | sub = subs[stream]; | 
|  | 305 | if (!sub) | 
|  | 306 | continue; | 
|  | 307 |  | 
|  | 308 | pb = frames_to_bytes(sub->runtime, | 
|  | 309 | sub->runtime->period_size); | 
|  | 310 | cnt = (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | 
|  | 311 | &dev->period_out_count[stream] : | 
|  | 312 | &dev->period_in_count[stream]; | 
|  | 313 |  | 
|  | 314 | if (*cnt >= pb) { | 
|  | 315 | snd_pcm_period_elapsed(sub); | 
|  | 316 | *cnt %= pb; | 
|  | 317 | } | 
|  | 318 | } | 
|  | 319 | } | 
|  | 320 |  | 
|  | 321 | static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev, | 
|  | 322 | const struct urb *urb, | 
|  | 323 | const struct usb_iso_packet_descriptor *iso) | 
|  | 324 | { | 
|  | 325 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 
|  | 326 | struct snd_pcm_substream *sub; | 
|  | 327 | int stream, i; | 
|  | 328 |  | 
|  | 329 | if (all_substreams_zero(dev->sub_capture)) | 
|  | 330 | return; | 
|  | 331 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 332 | for (i = 0; i < iso->actual_length;) { | 
|  | 333 | for (stream = 0; stream < dev->n_streams; stream++, i++) { | 
|  | 334 | sub = dev->sub_capture[stream]; | 
|  | 335 | if (sub) { | 
|  | 336 | struct snd_pcm_runtime *rt = sub->runtime; | 
|  | 337 | char *audio_buf = rt->dma_area; | 
|  | 338 | int sz = frames_to_bytes(rt, rt->buffer_size); | 
|  | 339 | audio_buf[dev->audio_in_buf_pos[stream]++] | 
|  | 340 | = usb_buf[i]; | 
|  | 341 | dev->period_in_count[stream]++; | 
|  | 342 | if (dev->audio_in_buf_pos[stream] == sz) | 
|  | 343 | dev->audio_in_buf_pos[stream] = 0; | 
|  | 344 | } | 
|  | 345 | } | 
|  | 346 | } | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 347 | } | 
|  | 348 |  | 
|  | 349 | static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, | 
|  | 350 | const struct urb *urb, | 
|  | 351 | const struct usb_iso_packet_descriptor *iso) | 
|  | 352 | { | 
|  | 353 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 
|  | 354 | unsigned char check_byte; | 
|  | 355 | struct snd_pcm_substream *sub; | 
|  | 356 | int stream, i; | 
|  | 357 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 358 | for (i = 0; i < iso->actual_length;) { | 
|  | 359 | if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) { | 
|  | 360 | for (stream = 0; | 
|  | 361 | stream < dev->n_streams; | 
|  | 362 | stream++, i++) { | 
|  | 363 | if (dev->first_packet) | 
|  | 364 | continue; | 
|  | 365 |  | 
|  | 366 | check_byte = MAKE_CHECKBYTE(dev, stream, i); | 
|  | 367 |  | 
|  | 368 | if ((usb_buf[i] & 0x3f) != check_byte) | 
|  | 369 | dev->input_panic = 1; | 
|  | 370 |  | 
|  | 371 | if (usb_buf[i] & 0x80) | 
|  | 372 | dev->output_panic = 1; | 
|  | 373 | } | 
|  | 374 | } | 
|  | 375 | dev->first_packet = 0; | 
|  | 376 |  | 
|  | 377 | for (stream = 0; stream < dev->n_streams; stream++, i++) { | 
|  | 378 | sub = dev->sub_capture[stream]; | 
|  | 379 | if (sub) { | 
|  | 380 | struct snd_pcm_runtime *rt = sub->runtime; | 
|  | 381 | char *audio_buf = rt->dma_area; | 
|  | 382 | int sz = frames_to_bytes(rt, rt->buffer_size); | 
| Karsten Wiese | a971c3d | 2007-03-29 17:02:45 +0200 | [diff] [blame] | 383 | audio_buf[dev->audio_in_buf_pos[stream]++] = | 
|  | 384 | usb_buf[i]; | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 385 | dev->period_in_count[stream]++; | 
|  | 386 | if (dev->audio_in_buf_pos[stream] == sz) | 
|  | 387 | dev->audio_in_buf_pos[stream] = 0; | 
|  | 388 | } | 
|  | 389 | } | 
|  | 390 | } | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 391 | } | 
|  | 392 |  | 
|  | 393 | static void read_in_urb(struct snd_usb_caiaqdev *dev, | 
|  | 394 | const struct urb *urb, | 
|  | 395 | const struct usb_iso_packet_descriptor *iso) | 
|  | 396 | { | 
|  | 397 | if (!dev->streaming) | 
|  | 398 | return; | 
|  | 399 |  | 
|  | 400 | switch (dev->spec.data_alignment) { | 
|  | 401 | case 0: | 
|  | 402 | read_in_urb_mode0(dev, urb, iso); | 
|  | 403 | break; | 
|  | 404 | case 2: | 
|  | 405 | read_in_urb_mode2(dev, urb, iso); | 
|  | 406 | break; | 
|  | 407 | } | 
|  | 408 |  | 
|  | 409 | if (dev->input_panic || dev->output_panic) { | 
|  | 410 | debug("streaming error detected %s %s\n", | 
|  | 411 | dev->input_panic ? "(input)" : "", | 
|  | 412 | dev->output_panic ? "(output)" : ""); | 
|  | 413 | } | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 414 | } | 
|  | 415 |  | 
|  | 416 | static void fill_out_urb(struct snd_usb_caiaqdev *dev, | 
|  | 417 | struct urb *urb, | 
|  | 418 | const struct usb_iso_packet_descriptor *iso) | 
|  | 419 | { | 
|  | 420 | unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | 
|  | 421 | struct snd_pcm_substream *sub; | 
|  | 422 | int stream, i; | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 423 |  | 
|  | 424 | for (i = 0; i < iso->length;) { | 
| Karsten Wiese | a971c3d | 2007-03-29 17:02:45 +0200 | [diff] [blame] | 425 | for (stream = 0; stream < dev->n_streams; stream++, i++) { | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 426 | sub = dev->sub_playback[stream]; | 
|  | 427 | if (sub) { | 
|  | 428 | struct snd_pcm_runtime *rt = sub->runtime; | 
|  | 429 | char *audio_buf = rt->dma_area; | 
|  | 430 | int sz = frames_to_bytes(rt, rt->buffer_size); | 
| Karsten Wiese | a971c3d | 2007-03-29 17:02:45 +0200 | [diff] [blame] | 431 | usb_buf[i] = | 
|  | 432 | audio_buf[dev->audio_out_buf_pos[stream]]; | 
|  | 433 | dev->period_out_count[stream]++; | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 434 | dev->audio_out_buf_pos[stream]++; | 
|  | 435 | if (dev->audio_out_buf_pos[stream] == sz) | 
|  | 436 | dev->audio_out_buf_pos[stream] = 0; | 
|  | 437 | } else | 
| Karsten Wiese | a971c3d | 2007-03-29 17:02:45 +0200 | [diff] [blame] | 438 | usb_buf[i] = 0; | 
|  | 439 | } | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 440 |  | 
|  | 441 | /* fill in the check bytes */ | 
|  | 442 | if (dev->spec.data_alignment == 2 && | 
|  | 443 | i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == | 
|  | 444 | (dev->n_streams * CHANNELS_PER_STREAM)) | 
|  | 445 | for (stream = 0; stream < dev->n_streams; stream++, i++) | 
|  | 446 | usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 447 | } | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 448 | } | 
|  | 449 |  | 
|  | 450 | static void read_completed(struct urb *urb) | 
|  | 451 | { | 
|  | 452 | struct snd_usb_caiaq_cb_info *info = urb->context; | 
|  | 453 | struct snd_usb_caiaqdev *dev; | 
|  | 454 | struct urb *out; | 
|  | 455 | int frame, len, send_it = 0, outframe = 0; | 
|  | 456 |  | 
|  | 457 | if (urb->status || !info) | 
|  | 458 | return; | 
|  | 459 |  | 
|  | 460 | dev = info->dev; | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 461 |  | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 462 | if (!dev->streaming) | 
|  | 463 | return; | 
|  | 464 |  | 
|  | 465 | out = dev->data_urbs_out[info->index]; | 
|  | 466 |  | 
|  | 467 | /* read the recently received packet and send back one which has | 
|  | 468 | * the same layout */ | 
|  | 469 | for (frame = 0; frame < FRAMES_PER_URB; frame++) { | 
|  | 470 | if (urb->iso_frame_desc[frame].status) | 
|  | 471 | continue; | 
|  | 472 |  | 
|  | 473 | len = urb->iso_frame_desc[outframe].actual_length; | 
|  | 474 | out->iso_frame_desc[outframe].length = len; | 
|  | 475 | out->iso_frame_desc[outframe].actual_length = 0; | 
|  | 476 | out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; | 
|  | 477 |  | 
|  | 478 | if (len > 0) { | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 479 | spin_lock(&dev->spinlock); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 480 | fill_out_urb(dev, out, &out->iso_frame_desc[outframe]); | 
|  | 481 | read_in_urb(dev, urb, &urb->iso_frame_desc[frame]); | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 482 | spin_unlock(&dev->spinlock); | 
|  | 483 | check_for_elapsed_periods(dev, dev->sub_playback); | 
|  | 484 | check_for_elapsed_periods(dev, dev->sub_capture); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 485 | send_it = 1; | 
|  | 486 | } | 
|  | 487 |  | 
|  | 488 | outframe++; | 
|  | 489 | } | 
|  | 490 |  | 
|  | 491 | if (send_it) { | 
|  | 492 | out->number_of_packets = FRAMES_PER_URB; | 
|  | 493 | out->transfer_flags = URB_ISO_ASAP; | 
|  | 494 | usb_submit_urb(out, GFP_ATOMIC); | 
|  | 495 | } | 
|  | 496 |  | 
|  | 497 | /* re-submit inbound urb */ | 
|  | 498 | for (frame = 0; frame < FRAMES_PER_URB; frame++) { | 
|  | 499 | urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; | 
|  | 500 | urb->iso_frame_desc[frame].length = BYTES_PER_FRAME; | 
|  | 501 | urb->iso_frame_desc[frame].actual_length = 0; | 
|  | 502 | } | 
|  | 503 |  | 
|  | 504 | urb->number_of_packets = FRAMES_PER_URB; | 
|  | 505 | urb->transfer_flags = URB_ISO_ASAP; | 
|  | 506 | usb_submit_urb(urb, GFP_ATOMIC); | 
|  | 507 | } | 
|  | 508 |  | 
|  | 509 | static void write_completed(struct urb *urb) | 
|  | 510 | { | 
|  | 511 | struct snd_usb_caiaq_cb_info *info = urb->context; | 
|  | 512 | struct snd_usb_caiaqdev *dev = info->dev; | 
|  | 513 |  | 
|  | 514 | if (!dev->output_running) { | 
|  | 515 | dev->output_running = 1; | 
|  | 516 | wake_up(&dev->prepare_wait_queue); | 
|  | 517 | } | 
|  | 518 | } | 
|  | 519 |  | 
|  | 520 | static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) | 
|  | 521 | { | 
|  | 522 | int i, frame; | 
|  | 523 | struct urb **urbs; | 
|  | 524 | struct usb_device *usb_dev = dev->chip.dev; | 
|  | 525 | unsigned int pipe; | 
|  | 526 |  | 
|  | 527 | pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? | 
|  | 528 | usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) : | 
|  | 529 | usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE); | 
|  | 530 |  | 
|  | 531 | urbs = kmalloc(N_URBS * sizeof(*urbs), GFP_KERNEL); | 
|  | 532 | if (!urbs) { | 
|  | 533 | log("unable to kmalloc() urbs, OOM!?\n"); | 
|  | 534 | *ret = -ENOMEM; | 
|  | 535 | return NULL; | 
|  | 536 | } | 
|  | 537 |  | 
|  | 538 | for (i = 0; i < N_URBS; i++) { | 
|  | 539 | urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL); | 
|  | 540 | if (!urbs[i]) { | 
|  | 541 | log("unable to usb_alloc_urb(), OOM!?\n"); | 
|  | 542 | *ret = -ENOMEM; | 
|  | 543 | return urbs; | 
|  | 544 | } | 
|  | 545 |  | 
|  | 546 | urbs[i]->transfer_buffer = | 
|  | 547 | kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL); | 
|  | 548 | if (!urbs[i]->transfer_buffer) { | 
|  | 549 | log("unable to kmalloc() transfer buffer, OOM!?\n"); | 
|  | 550 | *ret = -ENOMEM; | 
|  | 551 | return urbs; | 
|  | 552 | } | 
|  | 553 |  | 
|  | 554 | for (frame = 0; frame < FRAMES_PER_URB; frame++) { | 
|  | 555 | struct usb_iso_packet_descriptor *iso = | 
|  | 556 | &urbs[i]->iso_frame_desc[frame]; | 
|  | 557 |  | 
|  | 558 | iso->offset = BYTES_PER_FRAME * frame; | 
|  | 559 | iso->length = BYTES_PER_FRAME; | 
|  | 560 | } | 
|  | 561 |  | 
|  | 562 | urbs[i]->dev = usb_dev; | 
|  | 563 | urbs[i]->pipe = pipe; | 
|  | 564 | urbs[i]->transfer_buffer_length = FRAMES_PER_URB | 
|  | 565 | * BYTES_PER_FRAME; | 
|  | 566 | urbs[i]->context = &dev->data_cb_info[i]; | 
|  | 567 | urbs[i]->interval = 1; | 
|  | 568 | urbs[i]->transfer_flags = URB_ISO_ASAP; | 
|  | 569 | urbs[i]->number_of_packets = FRAMES_PER_URB; | 
|  | 570 | urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ? | 
|  | 571 | read_completed : write_completed; | 
|  | 572 | } | 
|  | 573 |  | 
|  | 574 | *ret = 0; | 
|  | 575 | return urbs; | 
|  | 576 | } | 
|  | 577 |  | 
|  | 578 | static void free_urbs(struct urb **urbs) | 
|  | 579 | { | 
|  | 580 | int i; | 
|  | 581 |  | 
|  | 582 | if (!urbs) | 
|  | 583 | return; | 
|  | 584 |  | 
|  | 585 | for (i = 0; i < N_URBS; i++) { | 
|  | 586 | if (!urbs[i]) | 
|  | 587 | continue; | 
|  | 588 |  | 
|  | 589 | usb_kill_urb(urbs[i]); | 
|  | 590 | kfree(urbs[i]->transfer_buffer); | 
|  | 591 | usb_free_urb(urbs[i]); | 
|  | 592 | } | 
|  | 593 |  | 
|  | 594 | kfree(urbs); | 
|  | 595 | } | 
|  | 596 |  | 
| Randy Dunlap | 599c3e7 | 2008-01-16 14:56:04 +0100 | [diff] [blame] | 597 | int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 598 | { | 
|  | 599 | int i, ret; | 
|  | 600 |  | 
|  | 601 | dev->n_audio_in  = max(dev->spec.num_analog_audio_in, | 
|  | 602 | dev->spec.num_digital_audio_in) / | 
|  | 603 | CHANNELS_PER_STREAM; | 
|  | 604 | dev->n_audio_out = max(dev->spec.num_analog_audio_out, | 
|  | 605 | dev->spec.num_digital_audio_out) / | 
|  | 606 | CHANNELS_PER_STREAM; | 
|  | 607 | dev->n_streams = max(dev->n_audio_in, dev->n_audio_out); | 
|  | 608 |  | 
|  | 609 | debug("dev->n_audio_in = %d\n", dev->n_audio_in); | 
|  | 610 | debug("dev->n_audio_out = %d\n", dev->n_audio_out); | 
|  | 611 | debug("dev->n_streams = %d\n", dev->n_streams); | 
|  | 612 |  | 
|  | 613 | if (dev->n_streams > MAX_STREAMS) { | 
|  | 614 | log("unable to initialize device, too many streams.\n"); | 
|  | 615 | return -EINVAL; | 
|  | 616 | } | 
|  | 617 |  | 
|  | 618 | ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, | 
|  | 619 | dev->n_audio_out, dev->n_audio_in, &dev->pcm); | 
|  | 620 |  | 
|  | 621 | if (ret < 0) { | 
|  | 622 | log("snd_pcm_new() returned %d\n", ret); | 
|  | 623 | return ret; | 
|  | 624 | } | 
|  | 625 |  | 
|  | 626 | dev->pcm->private_data = dev; | 
|  | 627 | strcpy(dev->pcm->name, dev->product_name); | 
|  | 628 |  | 
|  | 629 | memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); | 
|  | 630 | memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); | 
|  | 631 |  | 
|  | 632 | memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware, | 
|  | 633 | sizeof(snd_usb_caiaq_pcm_hardware)); | 
|  | 634 |  | 
|  | 635 | /* setup samplerates */ | 
|  | 636 | dev->samplerates = dev->pcm_info.rates; | 
|  | 637 | switch (dev->chip.usb_id) { | 
|  | 638 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | 
| Daniel Mack | ad1e34b | 2007-09-17 14:45:14 +0200 | [diff] [blame] | 639 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): | 
| Daniel Mack | f3e9d5d | 2008-05-08 15:42:15 +0200 | [diff] [blame] | 640 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO): | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 641 | dev->samplerates |= SNDRV_PCM_RATE_88200; | 
|  | 642 | dev->samplerates |= SNDRV_PCM_RATE_192000; | 
|  | 643 | break; | 
|  | 644 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): | 
|  | 645 | dev->samplerates |= SNDRV_PCM_RATE_88200; | 
|  | 646 | break; | 
|  | 647 | } | 
|  | 648 |  | 
|  | 649 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, | 
|  | 650 | &snd_usb_caiaq_ops); | 
|  | 651 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, | 
|  | 652 | &snd_usb_caiaq_ops); | 
|  | 653 |  | 
|  | 654 | snd_pcm_lib_preallocate_pages_for_all(dev->pcm, | 
|  | 655 | SNDRV_DMA_TYPE_CONTINUOUS, | 
|  | 656 | snd_dma_continuous_data(GFP_KERNEL), | 
|  | 657 | MAX_BUFFER_SIZE, MAX_BUFFER_SIZE); | 
|  | 658 |  | 
|  | 659 | dev->data_cb_info = | 
|  | 660 | kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, | 
|  | 661 | GFP_KERNEL); | 
|  | 662 |  | 
|  | 663 | if (!dev->data_cb_info) | 
|  | 664 | return -ENOMEM; | 
|  | 665 |  | 
|  | 666 | for (i = 0; i < N_URBS; i++) { | 
|  | 667 | dev->data_cb_info[i].dev = dev; | 
|  | 668 | dev->data_cb_info[i].index = i; | 
|  | 669 | } | 
|  | 670 |  | 
|  | 671 | dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret); | 
|  | 672 | if (ret < 0) { | 
|  | 673 | kfree(dev->data_cb_info); | 
|  | 674 | free_urbs(dev->data_urbs_in); | 
|  | 675 | return ret; | 
|  | 676 | } | 
|  | 677 |  | 
|  | 678 | dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret); | 
|  | 679 | if (ret < 0) { | 
|  | 680 | kfree(dev->data_cb_info); | 
|  | 681 | free_urbs(dev->data_urbs_in); | 
|  | 682 | free_urbs(dev->data_urbs_out); | 
|  | 683 | return ret; | 
|  | 684 | } | 
|  | 685 |  | 
|  | 686 | return 0; | 
|  | 687 | } | 
|  | 688 |  | 
|  | 689 | void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev) | 
|  | 690 | { | 
| Daniel Mack | 8d04884 | 2008-04-14 15:39:14 +0200 | [diff] [blame] | 691 | debug("%s(%p)\n", __func__, dev); | 
| Daniel Mack | 523f1dc | 2007-03-26 19:11:24 +0200 | [diff] [blame] | 692 | stream_stop(dev); | 
|  | 693 | free_urbs(dev->data_urbs_in); | 
|  | 694 | free_urbs(dev->data_urbs_out); | 
|  | 695 | kfree(dev->data_cb_info); | 
|  | 696 | } | 
|  | 697 |  |