Commit 523f1dce37434a9a6623bf46e7893e2b4b10ac3c
Committed by
Jaroslav Kysela
1 parent
e24a121aa1
Exists in
master
and in
7 other branches
[ALSA] Add Native Instrument usb audio device support
Add snd-usb-caiaq driver to support caiaq usb-audio devices from Native Instrument: * Native Instruments RigKontrol2 * Native Instruments Kore Controller * Native Instruments Audio Kontrol 1 * Native Instruments Audio 8 DJ Signed-off-by: Daniel Mack <daniel@caiaq.org> Signed-off-by: Karsten Wiese <fzu@wemgehoertderstaat.de> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Showing 12 changed files with 1747 additions and 1 deletions Side-by-side Diff
- Documentation/sound/alsa/ALSA-Configuration.txt
- sound/usb/Kconfig
- sound/usb/Makefile
- sound/usb/caiaq/Makefile
- sound/usb/caiaq/caiaq-audio.c
- sound/usb/caiaq/caiaq-audio.h
- sound/usb/caiaq/caiaq-device.c
- sound/usb/caiaq/caiaq-device.h
- sound/usb/caiaq/caiaq-input.c
- sound/usb/caiaq/caiaq-input.h
- sound/usb/caiaq/caiaq-midi.c
- sound/usb/caiaq/caiaq-midi.h
Documentation/sound/alsa/ALSA-Configuration.txt
... | ... | @@ -1697,6 +1697,17 @@ |
1697 | 1697 | |
1698 | 1698 | This module supports multiple devices, autoprobe and hotplugging. |
1699 | 1699 | |
1700 | + Module snd-usb-caiaq | |
1701 | + -------------------- | |
1702 | + | |
1703 | + Module for caiaq UB audio interfaces, | |
1704 | + * Native Instruments RigKontrol2 | |
1705 | + * Native Instruments Kore Controller | |
1706 | + * Native Instruments Audio Kontrol 1 | |
1707 | + * Native Instruments Audio 8 DJ | |
1708 | + | |
1709 | + This module supports multiple devices, autoprobe and hotplugging. | |
1710 | + | |
1700 | 1711 | Module snd-usb-usx2y |
1701 | 1712 | -------------------- |
1702 | 1713 |
sound/usb/Kconfig
... | ... | @@ -29,5 +29,33 @@ |
29 | 29 | To compile this driver as a module, choose M here: the module |
30 | 30 | will be called snd-usb-usx2y. |
31 | 31 | |
32 | +config SND_USB_CAIAQ | |
33 | + tristate "Native Instruments USB audio devices" | |
34 | + depends on SND && USB | |
35 | + select SND_HWDEP | |
36 | + select SND_RAWMIDI | |
37 | + select SND_PCM | |
38 | + help | |
39 | + Say Y here to include support for caiaq USB audio interfaces, | |
40 | + namely: | |
41 | + | |
42 | + * Native Instruments RigKontrol2 | |
43 | + * Native Instruments Kore Controller | |
44 | + * Native Instruments Audio Kontrol 1 | |
45 | + * Native Instruments Audio 8 DJ | |
46 | + | |
47 | + To compile this driver as a module, choose M here: the module | |
48 | + will be called snd-usb-caiaq. | |
49 | + | |
50 | +config SND_USB_CAIAQ_INPUT | |
51 | + bool "enable input device for controllers" | |
52 | + depends on SND_USB_CAIAQ | |
53 | + help | |
54 | + Say Y here to support input controllers like buttons, knobs, | |
55 | + alpha dials and analog pedals on the following products: | |
56 | + | |
57 | + * Native Instruments RigKontrol2 | |
58 | + * Native Instruments Audio Kontrol 1 | |
59 | + | |
32 | 60 | endmenu |
sound/usb/Makefile
sound/usb/caiaq/Makefile
sound/usb/caiaq/caiaq-audio.c
1 | +/* | |
2 | + * Copyright (c) 2006,2007 Daniel Mack, Karsten Wiese | |
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 <sound/driver.h> | |
20 | +#include <linux/init.h> | |
21 | +#include <linux/module.h> | |
22 | +#include <linux/moduleparam.h> | |
23 | +#include <linux/interrupt.h> | |
24 | +#include <linux/usb.h> | |
25 | +#include <linux/spinlock.h> | |
26 | +#include <sound/core.h> | |
27 | +#include <sound/initval.h> | |
28 | +#include <sound/pcm.h> | |
29 | +#include <sound/rawmidi.h> | |
30 | +#ifdef CONFIG_SND_USB_CAIAQ_INPUT | |
31 | +#include <linux/input.h> | |
32 | +#endif | |
33 | + | |
34 | +#include "caiaq-device.h" | |
35 | +#include "caiaq-audio.h" | |
36 | + | |
37 | +#define N_URBS 32 | |
38 | +#define CLOCK_DRIFT_TOLERANCE 5 | |
39 | +#define FRAMES_PER_URB 8 | |
40 | +#define BYTES_PER_FRAME 512 | |
41 | +#define CHANNELS_PER_STREAM 2 | |
42 | +#define BYTES_PER_SAMPLE 3 | |
43 | +#define BYTES_PER_SAMPLE_USB 4 | |
44 | +#define MAX_BUFFER_SIZE (128*1024) | |
45 | + | |
46 | +#define ENDPOINT_CAPTURE 2 | |
47 | +#define ENDPOINT_PLAYBACK 6 | |
48 | + | |
49 | +#define MAKE_CHECKBYTE(dev,stream,i) \ | |
50 | + (stream << 1) | (~(i / (dev->n_streams * BYTES_PER_SAMPLE_USB)) & 1) | |
51 | + | |
52 | +static struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = { | |
53 | + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | |
54 | + SNDRV_PCM_INFO_BLOCK_TRANSFER), | |
55 | + .formats = SNDRV_PCM_FMTBIT_S24_3BE, | |
56 | + .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | |
57 | + SNDRV_PCM_RATE_96000), | |
58 | + .rate_min = 44100, | |
59 | + .rate_max = 0, /* will overwrite later */ | |
60 | + .channels_min = CHANNELS_PER_STREAM, | |
61 | + .channels_max = CHANNELS_PER_STREAM, | |
62 | + .buffer_bytes_max = MAX_BUFFER_SIZE, | |
63 | + .period_bytes_min = 4096, | |
64 | + .period_bytes_max = MAX_BUFFER_SIZE, | |
65 | + .periods_min = 1, | |
66 | + .periods_max = 1024, | |
67 | +}; | |
68 | + | |
69 | +static void | |
70 | +activate_substream(struct snd_usb_caiaqdev *dev, | |
71 | + struct snd_pcm_substream *sub) | |
72 | +{ | |
73 | + if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
74 | + dev->sub_playback[sub->number] = sub; | |
75 | + else | |
76 | + dev->sub_capture[sub->number] = sub; | |
77 | +} | |
78 | + | |
79 | +static void | |
80 | +deactivate_substream(struct snd_usb_caiaqdev *dev, | |
81 | + struct snd_pcm_substream *sub) | |
82 | +{ | |
83 | + if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
84 | + dev->sub_playback[sub->number] = NULL; | |
85 | + else | |
86 | + dev->sub_capture[sub->number] = NULL; | |
87 | +} | |
88 | + | |
89 | +static int | |
90 | +all_substreams_zero(struct snd_pcm_substream **subs) | |
91 | +{ | |
92 | + int i; | |
93 | + for (i = 0; i < MAX_STREAMS; i++) | |
94 | + if (subs[i] != NULL) | |
95 | + return 0; | |
96 | + return 1; | |
97 | +} | |
98 | + | |
99 | +static int stream_start(struct snd_usb_caiaqdev *dev) | |
100 | +{ | |
101 | + int i, ret; | |
102 | + | |
103 | + debug("stream_start(%p)\n", dev); | |
104 | + spin_lock_irq(&dev->spinlock); | |
105 | + if (dev->streaming) { | |
106 | + spin_unlock_irq(&dev->spinlock); | |
107 | + return -EINVAL; | |
108 | + } | |
109 | + | |
110 | + dev->input_panic = 0; | |
111 | + dev->output_panic = 0; | |
112 | + dev->first_packet = 1; | |
113 | + dev->streaming = 1; | |
114 | + | |
115 | + for (i = 0; i < N_URBS; i++) { | |
116 | + ret = usb_submit_urb(dev->data_urbs_in[i], GFP_ATOMIC); | |
117 | + if (ret) { | |
118 | + log("unable to trigger initial read #%d! (ret = %d)\n", | |
119 | + i, ret); | |
120 | + dev->streaming = 0; | |
121 | + spin_unlock_irq(&dev->spinlock); | |
122 | + return -EPIPE; | |
123 | + } | |
124 | + } | |
125 | + | |
126 | + spin_unlock_irq(&dev->spinlock); | |
127 | + return 0; | |
128 | +} | |
129 | + | |
130 | +static void stream_stop(struct snd_usb_caiaqdev *dev) | |
131 | +{ | |
132 | + int i; | |
133 | + | |
134 | + debug("stream_stop(%p)\n", dev); | |
135 | + if (!dev->streaming) | |
136 | + return; | |
137 | + | |
138 | + dev->streaming = 0; | |
139 | + for (i = 0; i < N_URBS; i++) { | |
140 | + usb_unlink_urb(dev->data_urbs_in[i]); | |
141 | + usb_unlink_urb(dev->data_urbs_out[i]); | |
142 | + } | |
143 | +} | |
144 | + | |
145 | +static int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream) | |
146 | +{ | |
147 | + struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); | |
148 | + debug("snd_usb_caiaq_substream_open(%p)\n", substream); | |
149 | + substream->runtime->hw = dev->pcm_info; | |
150 | + snd_pcm_limit_hw_rates(substream->runtime); | |
151 | + return 0; | |
152 | +} | |
153 | + | |
154 | +static int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream) | |
155 | +{ | |
156 | + struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); | |
157 | + | |
158 | + debug("snd_usb_caiaq_substream_close(%p)\n", substream); | |
159 | + if (all_substreams_zero(dev->sub_playback) && | |
160 | + all_substreams_zero(dev->sub_capture)) { | |
161 | + /* when the last client has stopped streaming, | |
162 | + * all sample rates are allowed again */ | |
163 | + stream_stop(dev); | |
164 | + dev->pcm_info.rates = dev->samplerates; | |
165 | + } | |
166 | + | |
167 | + return 0; | |
168 | +} | |
169 | + | |
170 | +static int snd_usb_caiaq_pcm_hw_params(struct snd_pcm_substream *sub, | |
171 | + struct snd_pcm_hw_params *hw_params) | |
172 | +{ | |
173 | + debug("snd_usb_caiaq_pcm_hw_params(%p)\n", sub); | |
174 | + return snd_pcm_lib_malloc_pages(sub, params_buffer_bytes(hw_params)); | |
175 | +} | |
176 | + | |
177 | +static int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub) | |
178 | +{ | |
179 | + struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | |
180 | + debug("snd_usb_caiaq_pcm_hw_free(%p)\n", sub); | |
181 | + spin_lock_irq(&dev->spinlock); | |
182 | + deactivate_substream(dev, sub); | |
183 | + spin_unlock_irq(&dev->spinlock); | |
184 | + return snd_pcm_lib_free_pages(sub); | |
185 | +} | |
186 | + | |
187 | +/* this should probably go upstream */ | |
188 | +#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 | |
189 | +#error "Change this table" | |
190 | +#endif | |
191 | + | |
192 | +static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | |
193 | + 48000, 64000, 88200, 96000, 176400, 192000 }; | |
194 | + | |
195 | +static int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream) | |
196 | +{ | |
197 | + int bytes_per_sample, bpp, ret, i; | |
198 | + int index = substream->number; | |
199 | + struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(substream); | |
200 | + struct snd_pcm_runtime *runtime = substream->runtime; | |
201 | + | |
202 | + debug("snd_usb_caiaq_pcm_prepare(%p)\n", substream); | |
203 | + | |
204 | + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
205 | + dev->audio_out_buf_pos[index] = BYTES_PER_SAMPLE + 1; | |
206 | + else | |
207 | + dev->audio_in_buf_pos[index] = 0; | |
208 | + | |
209 | + if (dev->streaming) | |
210 | + return 0; | |
211 | + | |
212 | + /* the first client that opens a stream defines the sample rate | |
213 | + * setting for all subsequent calls, until the last client closed. */ | |
214 | + for (i=0; i < ARRAY_SIZE(rates); i++) | |
215 | + if (runtime->rate == rates[i]) | |
216 | + dev->pcm_info.rates = 1 << i; | |
217 | + | |
218 | + snd_pcm_limit_hw_rates(runtime); | |
219 | + | |
220 | + bytes_per_sample = BYTES_PER_SAMPLE; | |
221 | + if (dev->spec.data_alignment == 2) | |
222 | + bytes_per_sample++; | |
223 | + | |
224 | + bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE) | |
225 | + * bytes_per_sample * CHANNELS_PER_STREAM * dev->n_streams; | |
226 | + | |
227 | + ret = snd_usb_caiaq_set_audio_params(dev, runtime->rate, | |
228 | + runtime->sample_bits, bpp); | |
229 | + if (ret) | |
230 | + return ret; | |
231 | + | |
232 | + ret = stream_start(dev); | |
233 | + if (ret) | |
234 | + return ret; | |
235 | + | |
236 | + dev->output_running = 0; | |
237 | + wait_event_timeout(dev->prepare_wait_queue, dev->output_running, HZ); | |
238 | + if (!dev->output_running) { | |
239 | + stream_stop(dev); | |
240 | + return -EPIPE; | |
241 | + } | |
242 | + | |
243 | + return 0; | |
244 | +} | |
245 | + | |
246 | +static int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd) | |
247 | +{ | |
248 | + struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | |
249 | + | |
250 | + switch (cmd) { | |
251 | + case SNDRV_PCM_TRIGGER_START: | |
252 | + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
253 | + spin_lock(&dev->spinlock); | |
254 | + activate_substream(dev, sub); | |
255 | + spin_unlock(&dev->spinlock); | |
256 | + break; | |
257 | + case SNDRV_PCM_TRIGGER_STOP: | |
258 | + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
259 | + spin_lock(&dev->spinlock); | |
260 | + deactivate_substream(dev, sub); | |
261 | + spin_unlock(&dev->spinlock); | |
262 | + break; | |
263 | + default: | |
264 | + return -EINVAL; | |
265 | + } | |
266 | + | |
267 | + return 0; | |
268 | +} | |
269 | + | |
270 | +static snd_pcm_uframes_t | |
271 | +snd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub) | |
272 | +{ | |
273 | + int index = sub->number; | |
274 | + struct snd_usb_caiaqdev *dev = snd_pcm_substream_chip(sub); | |
275 | + | |
276 | + if (dev->input_panic || dev->output_panic) | |
277 | + return SNDRV_PCM_POS_XRUN; | |
278 | + | |
279 | + if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
280 | + return bytes_to_frames(sub->runtime, | |
281 | + dev->audio_out_buf_pos[index]); | |
282 | + else | |
283 | + return bytes_to_frames(sub->runtime, | |
284 | + dev->audio_in_buf_pos[index]); | |
285 | +} | |
286 | + | |
287 | +/* operators for both playback and capture */ | |
288 | +static struct snd_pcm_ops snd_usb_caiaq_ops = { | |
289 | + .open = snd_usb_caiaq_substream_open, | |
290 | + .close = snd_usb_caiaq_substream_close, | |
291 | + .ioctl = snd_pcm_lib_ioctl, | |
292 | + .hw_params = snd_usb_caiaq_pcm_hw_params, | |
293 | + .hw_free = snd_usb_caiaq_pcm_hw_free, | |
294 | + .prepare = snd_usb_caiaq_pcm_prepare, | |
295 | + .trigger = snd_usb_caiaq_pcm_trigger, | |
296 | + .pointer = snd_usb_caiaq_pcm_pointer | |
297 | +}; | |
298 | + | |
299 | +static void check_for_elapsed_periods(struct snd_usb_caiaqdev *dev, | |
300 | + struct snd_pcm_substream **subs) | |
301 | +{ | |
302 | + int stream, pb, *cnt; | |
303 | + struct snd_pcm_substream *sub; | |
304 | + | |
305 | + for (stream = 0; stream < dev->n_streams; stream++) { | |
306 | + sub = subs[stream]; | |
307 | + if (!sub) | |
308 | + continue; | |
309 | + | |
310 | + pb = frames_to_bytes(sub->runtime, | |
311 | + sub->runtime->period_size); | |
312 | + cnt = (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | |
313 | + &dev->period_out_count[stream] : | |
314 | + &dev->period_in_count[stream]; | |
315 | + | |
316 | + if (*cnt >= pb) { | |
317 | + snd_pcm_period_elapsed(sub); | |
318 | + *cnt %= pb; | |
319 | + } | |
320 | + } | |
321 | +} | |
322 | + | |
323 | +static void read_in_urb_mode0(struct snd_usb_caiaqdev *dev, | |
324 | + const struct urb *urb, | |
325 | + const struct usb_iso_packet_descriptor *iso) | |
326 | +{ | |
327 | + unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | |
328 | + struct snd_pcm_substream *sub; | |
329 | + int stream, i; | |
330 | + | |
331 | + if (all_substreams_zero(dev->sub_capture)) | |
332 | + return; | |
333 | + | |
334 | + spin_lock(&dev->spinlock); | |
335 | + | |
336 | + for (i = 0; i < iso->actual_length;) { | |
337 | + for (stream = 0; stream < dev->n_streams; stream++, i++) { | |
338 | + sub = dev->sub_capture[stream]; | |
339 | + if (sub) { | |
340 | + struct snd_pcm_runtime *rt = sub->runtime; | |
341 | + char *audio_buf = rt->dma_area; | |
342 | + int sz = frames_to_bytes(rt, rt->buffer_size); | |
343 | + audio_buf[dev->audio_in_buf_pos[stream]++] | |
344 | + = usb_buf[i]; | |
345 | + dev->period_in_count[stream]++; | |
346 | + if (dev->audio_in_buf_pos[stream] == sz) | |
347 | + dev->audio_in_buf_pos[stream] = 0; | |
348 | + } | |
349 | + } | |
350 | + } | |
351 | + | |
352 | + spin_unlock(&dev->spinlock); | |
353 | +} | |
354 | + | |
355 | +static void read_in_urb_mode2(struct snd_usb_caiaqdev *dev, | |
356 | + const struct urb *urb, | |
357 | + const struct usb_iso_packet_descriptor *iso) | |
358 | +{ | |
359 | + unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | |
360 | + unsigned char check_byte; | |
361 | + struct snd_pcm_substream *sub; | |
362 | + int stream, i; | |
363 | + | |
364 | + spin_lock(&dev->spinlock); | |
365 | + | |
366 | + for (i = 0; i < iso->actual_length;) { | |
367 | + if (i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == 0) { | |
368 | + for (stream = 0; | |
369 | + stream < dev->n_streams; | |
370 | + stream++, i++) { | |
371 | + if (dev->first_packet) | |
372 | + continue; | |
373 | + | |
374 | + check_byte = MAKE_CHECKBYTE(dev, stream, i); | |
375 | + | |
376 | + if ((usb_buf[i] & 0x3f) != check_byte) | |
377 | + dev->input_panic = 1; | |
378 | + | |
379 | + if (usb_buf[i] & 0x80) | |
380 | + dev->output_panic = 1; | |
381 | + } | |
382 | + } | |
383 | + dev->first_packet = 0; | |
384 | + | |
385 | + for (stream = 0; stream < dev->n_streams; stream++, i++) { | |
386 | + sub = dev->sub_capture[stream]; | |
387 | + if (sub) { | |
388 | + struct snd_pcm_runtime *rt = sub->runtime; | |
389 | + char *audio_buf = rt->dma_area; | |
390 | + int sz = frames_to_bytes(rt, rt->buffer_size); | |
391 | + audio_buf[dev->audio_in_buf_pos[stream]++] | |
392 | + = usb_buf[i]; | |
393 | + dev->period_in_count[stream]++; | |
394 | + if (dev->audio_in_buf_pos[stream] == sz) | |
395 | + dev->audio_in_buf_pos[stream] = 0; | |
396 | + } | |
397 | + } | |
398 | + } | |
399 | + | |
400 | + spin_unlock(&dev->spinlock); | |
401 | +} | |
402 | + | |
403 | +static void read_in_urb(struct snd_usb_caiaqdev *dev, | |
404 | + const struct urb *urb, | |
405 | + const struct usb_iso_packet_descriptor *iso) | |
406 | +{ | |
407 | + if (!dev->streaming) | |
408 | + return; | |
409 | + | |
410 | + switch (dev->spec.data_alignment) { | |
411 | + case 0: | |
412 | + read_in_urb_mode0(dev, urb, iso); | |
413 | + break; | |
414 | + case 2: | |
415 | + read_in_urb_mode2(dev, urb, iso); | |
416 | + break; | |
417 | + } | |
418 | + | |
419 | + if (dev->input_panic || dev->output_panic) { | |
420 | + debug("streaming error detected %s %s\n", | |
421 | + dev->input_panic ? "(input)" : "", | |
422 | + dev->output_panic ? "(output)" : ""); | |
423 | + } | |
424 | + | |
425 | + check_for_elapsed_periods(dev, dev->sub_capture); | |
426 | +} | |
427 | + | |
428 | +static void fill_out_urb(struct snd_usb_caiaqdev *dev, | |
429 | + struct urb *urb, | |
430 | + const struct usb_iso_packet_descriptor *iso) | |
431 | +{ | |
432 | + unsigned char *usb_buf = urb->transfer_buffer + iso->offset; | |
433 | + struct snd_pcm_substream *sub; | |
434 | + int stream, i; | |
435 | + | |
436 | + spin_lock(&dev->spinlock); | |
437 | + | |
438 | + for (i = 0; i < iso->length;) { | |
439 | + for (stream = 0; stream < dev->n_streams; stream++) { | |
440 | + sub = dev->sub_playback[stream]; | |
441 | + if (sub) { | |
442 | + struct snd_pcm_runtime *rt = sub->runtime; | |
443 | + char *audio_buf = rt->dma_area; | |
444 | + int sz = frames_to_bytes(rt, rt->buffer_size); | |
445 | + usb_buf[i++] | |
446 | + = audio_buf[dev->audio_out_buf_pos[stream]++]; | |
447 | + dev->audio_out_buf_pos[stream]++; | |
448 | + if (dev->audio_out_buf_pos[stream] == sz) | |
449 | + dev->audio_out_buf_pos[stream] = 0; | |
450 | + } else | |
451 | + usb_buf[i++] = 0; | |
452 | + | |
453 | + /* fill in the check bytes */ | |
454 | + if (dev->spec.data_alignment == 2 && | |
455 | + i % (dev->n_streams * BYTES_PER_SAMPLE_USB) == | |
456 | + (dev->n_streams * CHANNELS_PER_STREAM)) | |
457 | + for (stream = 0; stream < dev->n_streams; stream++, i++) | |
458 | + usb_buf[i] = MAKE_CHECKBYTE(dev, stream, i); | |
459 | + } | |
460 | + } | |
461 | + | |
462 | + spin_unlock(&dev->spinlock); | |
463 | + check_for_elapsed_periods(dev, dev->sub_playback); | |
464 | +} | |
465 | + | |
466 | +static void read_completed(struct urb *urb) | |
467 | +{ | |
468 | + struct snd_usb_caiaq_cb_info *info = urb->context; | |
469 | + struct snd_usb_caiaqdev *dev; | |
470 | + struct urb *out; | |
471 | + int frame, len, send_it = 0, outframe = 0; | |
472 | + | |
473 | + if (urb->status || !info) | |
474 | + return; | |
475 | + | |
476 | + dev = info->dev; | |
477 | + if (!dev->streaming) | |
478 | + return; | |
479 | + | |
480 | + out = dev->data_urbs_out[info->index]; | |
481 | + | |
482 | + /* read the recently received packet and send back one which has | |
483 | + * the same layout */ | |
484 | + for (frame = 0; frame < FRAMES_PER_URB; frame++) { | |
485 | + if (urb->iso_frame_desc[frame].status) | |
486 | + continue; | |
487 | + | |
488 | + len = urb->iso_frame_desc[outframe].actual_length; | |
489 | + out->iso_frame_desc[outframe].length = len; | |
490 | + out->iso_frame_desc[outframe].actual_length = 0; | |
491 | + out->iso_frame_desc[outframe].offset = BYTES_PER_FRAME * frame; | |
492 | + | |
493 | + if (len > 0) { | |
494 | + fill_out_urb(dev, out, &out->iso_frame_desc[outframe]); | |
495 | + read_in_urb(dev, urb, &urb->iso_frame_desc[frame]); | |
496 | + send_it = 1; | |
497 | + } | |
498 | + | |
499 | + outframe++; | |
500 | + } | |
501 | + | |
502 | + if (send_it) { | |
503 | + out->number_of_packets = FRAMES_PER_URB; | |
504 | + out->transfer_flags = URB_ISO_ASAP; | |
505 | + usb_submit_urb(out, GFP_ATOMIC); | |
506 | + } | |
507 | + | |
508 | + /* re-submit inbound urb */ | |
509 | + for (frame = 0; frame < FRAMES_PER_URB; frame++) { | |
510 | + urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame; | |
511 | + urb->iso_frame_desc[frame].length = BYTES_PER_FRAME; | |
512 | + urb->iso_frame_desc[frame].actual_length = 0; | |
513 | + } | |
514 | + | |
515 | + urb->number_of_packets = FRAMES_PER_URB; | |
516 | + urb->transfer_flags = URB_ISO_ASAP; | |
517 | + usb_submit_urb(urb, GFP_ATOMIC); | |
518 | +} | |
519 | + | |
520 | +static void write_completed(struct urb *urb) | |
521 | +{ | |
522 | + struct snd_usb_caiaq_cb_info *info = urb->context; | |
523 | + struct snd_usb_caiaqdev *dev = info->dev; | |
524 | + | |
525 | + if (!dev->output_running) { | |
526 | + dev->output_running = 1; | |
527 | + wake_up(&dev->prepare_wait_queue); | |
528 | + } | |
529 | +} | |
530 | + | |
531 | +static struct urb **alloc_urbs(struct snd_usb_caiaqdev *dev, int dir, int *ret) | |
532 | +{ | |
533 | + int i, frame; | |
534 | + struct urb **urbs; | |
535 | + struct usb_device *usb_dev = dev->chip.dev; | |
536 | + unsigned int pipe; | |
537 | + | |
538 | + pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ? | |
539 | + usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) : | |
540 | + usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE); | |
541 | + | |
542 | + urbs = kmalloc(N_URBS * sizeof(*urbs), GFP_KERNEL); | |
543 | + if (!urbs) { | |
544 | + log("unable to kmalloc() urbs, OOM!?\n"); | |
545 | + *ret = -ENOMEM; | |
546 | + return NULL; | |
547 | + } | |
548 | + | |
549 | + for (i = 0; i < N_URBS; i++) { | |
550 | + urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL); | |
551 | + if (!urbs[i]) { | |
552 | + log("unable to usb_alloc_urb(), OOM!?\n"); | |
553 | + *ret = -ENOMEM; | |
554 | + return urbs; | |
555 | + } | |
556 | + | |
557 | + urbs[i]->transfer_buffer = | |
558 | + kmalloc(FRAMES_PER_URB * BYTES_PER_FRAME, GFP_KERNEL); | |
559 | + if (!urbs[i]->transfer_buffer) { | |
560 | + log("unable to kmalloc() transfer buffer, OOM!?\n"); | |
561 | + *ret = -ENOMEM; | |
562 | + return urbs; | |
563 | + } | |
564 | + | |
565 | + for (frame = 0; frame < FRAMES_PER_URB; frame++) { | |
566 | + struct usb_iso_packet_descriptor *iso = | |
567 | + &urbs[i]->iso_frame_desc[frame]; | |
568 | + | |
569 | + iso->offset = BYTES_PER_FRAME * frame; | |
570 | + iso->length = BYTES_PER_FRAME; | |
571 | + } | |
572 | + | |
573 | + urbs[i]->dev = usb_dev; | |
574 | + urbs[i]->pipe = pipe; | |
575 | + urbs[i]->transfer_buffer_length = FRAMES_PER_URB | |
576 | + * BYTES_PER_FRAME; | |
577 | + urbs[i]->context = &dev->data_cb_info[i]; | |
578 | + urbs[i]->interval = 1; | |
579 | + urbs[i]->transfer_flags = URB_ISO_ASAP; | |
580 | + urbs[i]->number_of_packets = FRAMES_PER_URB; | |
581 | + urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ? | |
582 | + read_completed : write_completed; | |
583 | + } | |
584 | + | |
585 | + *ret = 0; | |
586 | + return urbs; | |
587 | +} | |
588 | + | |
589 | +static void free_urbs(struct urb **urbs) | |
590 | +{ | |
591 | + int i; | |
592 | + | |
593 | + if (!urbs) | |
594 | + return; | |
595 | + | |
596 | + for (i = 0; i < N_URBS; i++) { | |
597 | + if (!urbs[i]) | |
598 | + continue; | |
599 | + | |
600 | + usb_kill_urb(urbs[i]); | |
601 | + kfree(urbs[i]->transfer_buffer); | |
602 | + usb_free_urb(urbs[i]); | |
603 | + } | |
604 | + | |
605 | + kfree(urbs); | |
606 | +} | |
607 | + | |
608 | +int __devinit snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) | |
609 | +{ | |
610 | + int i, ret; | |
611 | + | |
612 | + dev->n_audio_in = max(dev->spec.num_analog_audio_in, | |
613 | + dev->spec.num_digital_audio_in) / | |
614 | + CHANNELS_PER_STREAM; | |
615 | + dev->n_audio_out = max(dev->spec.num_analog_audio_out, | |
616 | + dev->spec.num_digital_audio_out) / | |
617 | + CHANNELS_PER_STREAM; | |
618 | + dev->n_streams = max(dev->n_audio_in, dev->n_audio_out); | |
619 | + | |
620 | + debug("dev->n_audio_in = %d\n", dev->n_audio_in); | |
621 | + debug("dev->n_audio_out = %d\n", dev->n_audio_out); | |
622 | + debug("dev->n_streams = %d\n", dev->n_streams); | |
623 | + | |
624 | + if (dev->n_streams > MAX_STREAMS) { | |
625 | + log("unable to initialize device, too many streams.\n"); | |
626 | + return -EINVAL; | |
627 | + } | |
628 | + | |
629 | + ret = snd_pcm_new(dev->chip.card, dev->product_name, 0, | |
630 | + dev->n_audio_out, dev->n_audio_in, &dev->pcm); | |
631 | + | |
632 | + if (ret < 0) { | |
633 | + log("snd_pcm_new() returned %d\n", ret); | |
634 | + return ret; | |
635 | + } | |
636 | + | |
637 | + dev->pcm->private_data = dev; | |
638 | + strcpy(dev->pcm->name, dev->product_name); | |
639 | + | |
640 | + memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); | |
641 | + memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); | |
642 | + | |
643 | + memcpy(&dev->pcm_info, &snd_usb_caiaq_pcm_hardware, | |
644 | + sizeof(snd_usb_caiaq_pcm_hardware)); | |
645 | + | |
646 | + /* setup samplerates */ | |
647 | + dev->samplerates = dev->pcm_info.rates; | |
648 | + switch (dev->chip.usb_id) { | |
649 | + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | |
650 | + dev->samplerates |= SNDRV_PCM_RATE_88200; | |
651 | + dev->samplerates |= SNDRV_PCM_RATE_192000; | |
652 | + break; | |
653 | + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): | |
654 | + dev->samplerates |= SNDRV_PCM_RATE_88200; | |
655 | + break; | |
656 | + } | |
657 | + | |
658 | + snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, | |
659 | + &snd_usb_caiaq_ops); | |
660 | + snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, | |
661 | + &snd_usb_caiaq_ops); | |
662 | + | |
663 | + snd_pcm_lib_preallocate_pages_for_all(dev->pcm, | |
664 | + SNDRV_DMA_TYPE_CONTINUOUS, | |
665 | + snd_dma_continuous_data(GFP_KERNEL), | |
666 | + MAX_BUFFER_SIZE, MAX_BUFFER_SIZE); | |
667 | + | |
668 | + dev->data_cb_info = | |
669 | + kmalloc(sizeof(struct snd_usb_caiaq_cb_info) * N_URBS, | |
670 | + GFP_KERNEL); | |
671 | + | |
672 | + if (!dev->data_cb_info) | |
673 | + return -ENOMEM; | |
674 | + | |
675 | + for (i = 0; i < N_URBS; i++) { | |
676 | + dev->data_cb_info[i].dev = dev; | |
677 | + dev->data_cb_info[i].index = i; | |
678 | + } | |
679 | + | |
680 | + dev->data_urbs_in = alloc_urbs(dev, SNDRV_PCM_STREAM_CAPTURE, &ret); | |
681 | + if (ret < 0) { | |
682 | + kfree(dev->data_cb_info); | |
683 | + free_urbs(dev->data_urbs_in); | |
684 | + return ret; | |
685 | + } | |
686 | + | |
687 | + dev->data_urbs_out = alloc_urbs(dev, SNDRV_PCM_STREAM_PLAYBACK, &ret); | |
688 | + if (ret < 0) { | |
689 | + kfree(dev->data_cb_info); | |
690 | + free_urbs(dev->data_urbs_in); | |
691 | + free_urbs(dev->data_urbs_out); | |
692 | + return ret; | |
693 | + } | |
694 | + | |
695 | + return 0; | |
696 | +} | |
697 | + | |
698 | +void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *dev) | |
699 | +{ | |
700 | + debug("snd_usb_caiaq_audio_free (%p)\n", dev); | |
701 | + stream_stop(dev); | |
702 | + free_urbs(dev->data_urbs_in); | |
703 | + free_urbs(dev->data_urbs_out); | |
704 | + kfree(dev->data_cb_info); | |
705 | +} |
sound/usb/caiaq/caiaq-audio.h
sound/usb/caiaq/caiaq-device.c
1 | +/* | |
2 | + * caiaq.c: ALSA driver for caiaq/NativeInstruments devices | |
3 | + * | |
4 | + * Copyright (c) 2007 Daniel Mack <daniel@caiaq.de> | |
5 | + * Karsten Wiese <fzu@wemgehoertderstaat.de> | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or modify | |
8 | + * it under the terms of the GNU General Public License as published by | |
9 | + * the Free Software Foundation; either version 2 of the License, or | |
10 | + * (at your option) any later version. | |
11 | + * | |
12 | + * This program is distributed in the hope that it will be useful, | |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | + * GNU General Public License for more details. | |
16 | + * | |
17 | + * You should have received a copy of the GNU General Public License | |
18 | + * along with this program; if not, write to the Free Software | |
19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | +*/ | |
21 | + | |
22 | +#include <linux/init.h> | |
23 | +#include <linux/module.h> | |
24 | +#include <linux/moduleparam.h> | |
25 | +#include <linux/interrupt.h> | |
26 | +#include <linux/usb.h> | |
27 | +#include <linux/input.h> | |
28 | +#include <linux/spinlock.h> | |
29 | +#include <sound/driver.h> | |
30 | +#include <sound/core.h> | |
31 | +#include <sound/initval.h> | |
32 | +#include <sound/pcm.h> | |
33 | +#include <sound/rawmidi.h> | |
34 | + | |
35 | +#include "caiaq-device.h" | |
36 | +#include "caiaq-audio.h" | |
37 | +#include "caiaq-midi.h" | |
38 | + | |
39 | +#ifdef CONFIG_SND_USB_CAIAQ_INPUT | |
40 | +#include "caiaq-input.h" | |
41 | +#endif | |
42 | + | |
43 | +MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | |
44 | +MODULE_DESCRIPTION("caiaq USB audio, version 1.1.0"); | |
45 | +MODULE_LICENSE("GPL"); | |
46 | +MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," | |
47 | + "{Native Instruments, Kore Controller}," | |
48 | + "{Native Instruments, Audio Kontrol 1}" | |
49 | + "{Native Instruments, Audio 8 DJ}}"); | |
50 | + | |
51 | +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ | |
52 | +static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ | |
53 | +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | |
54 | +static int snd_card_used[SNDRV_CARDS]; | |
55 | + | |
56 | +module_param_array(index, int, NULL, 0444); | |
57 | +MODULE_PARM_DESC(index, "Index value for the caiaq sound device"); | |
58 | +module_param_array(id, charp, NULL, 0444); | |
59 | +MODULE_PARM_DESC(id, "ID string for the caiaq soundcard."); | |
60 | +module_param_array(enable, bool, NULL, 0444); | |
61 | +MODULE_PARM_DESC(enable, "Enable the caiaq soundcard."); | |
62 | + | |
63 | +enum { | |
64 | + SAMPLERATE_44100 = 0, | |
65 | + SAMPLERATE_48000 = 1, | |
66 | + SAMPLERATE_96000 = 2, | |
67 | + SAMPLERATE_192000 = 3, | |
68 | + SAMPLERATE_88200 = 4, | |
69 | + SAMPLERATE_INVALID = 0xff | |
70 | +}; | |
71 | + | |
72 | +enum { | |
73 | + DEPTH_NONE = 0, | |
74 | + DEPTH_16 = 1, | |
75 | + DEPTH_24 = 2, | |
76 | + DEPTH_32 = 3 | |
77 | +}; | |
78 | + | |
79 | +static struct usb_device_id snd_usb_id_table[] = { | |
80 | + { | |
81 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | |
82 | + .idVendor = USB_VID_NATIVEINSTRUMENTS, | |
83 | + .idProduct = USB_PID_RIGKONTROL2 | |
84 | + }, | |
85 | + { | |
86 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | |
87 | + .idVendor = USB_VID_NATIVEINSTRUMENTS, | |
88 | + .idProduct = USB_PID_KORECONTROLLER | |
89 | + }, | |
90 | + { | |
91 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | |
92 | + .idVendor = USB_VID_NATIVEINSTRUMENTS, | |
93 | + .idProduct = USB_PID_AK1 | |
94 | + }, | |
95 | + { | |
96 | + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, | |
97 | + .idVendor = USB_VID_NATIVEINSTRUMENTS, | |
98 | + .idProduct = USB_PID_AUDIO8DJ | |
99 | + }, | |
100 | + { /* terminator */ } | |
101 | +}; | |
102 | + | |
103 | +static void usb_ep1_command_reply_dispatch (struct urb* urb) | |
104 | +{ | |
105 | + int ret; | |
106 | + struct snd_usb_caiaqdev *dev = urb->context; | |
107 | + unsigned char *buf = urb->transfer_buffer; | |
108 | + | |
109 | + if (urb->status || !dev) { | |
110 | + log("received EP1 urb->status = %i\n", urb->status); | |
111 | + return; | |
112 | + } | |
113 | + | |
114 | + switch(buf[0]) { | |
115 | + case EP1_CMD_GET_DEVICE_INFO: | |
116 | + memcpy(&dev->spec, buf+1, sizeof(struct caiaq_device_spec)); | |
117 | + dev->spec.fw_version = le16_to_cpu(dev->spec.fw_version); | |
118 | + debug("device spec (firmware %d): audio: %d in, %d out, " | |
119 | + "MIDI: %d in, %d out, data alignment %d\n", | |
120 | + dev->spec.fw_version, | |
121 | + dev->spec.num_analog_audio_in, | |
122 | + dev->spec.num_analog_audio_out, | |
123 | + dev->spec.num_midi_in, | |
124 | + dev->spec.num_midi_out, | |
125 | + dev->spec.data_alignment); | |
126 | + | |
127 | + dev->spec_received++; | |
128 | + wake_up(&dev->ep1_wait_queue); | |
129 | + break; | |
130 | + case EP1_CMD_AUDIO_PARAMS: | |
131 | + dev->audio_parm_answer = buf[1]; | |
132 | + wake_up(&dev->ep1_wait_queue); | |
133 | + break; | |
134 | + case EP1_CMD_MIDI_READ: | |
135 | + snd_usb_caiaq_midi_handle_input(dev, buf[1], buf + 3, buf[2]); | |
136 | + break; | |
137 | + | |
138 | +#ifdef CONFIG_SND_USB_CAIAQ_INPUT | |
139 | + case EP1_CMD_READ_ERP: | |
140 | + case EP1_CMD_READ_ANALOG: | |
141 | + case EP1_CMD_READ_IO: | |
142 | + snd_usb_caiaq_input_dispatch(dev, buf, urb->actual_length); | |
143 | + break; | |
144 | +#endif | |
145 | + } | |
146 | + | |
147 | + dev->ep1_in_urb.actual_length = 0; | |
148 | + ret = usb_submit_urb(&dev->ep1_in_urb, GFP_ATOMIC); | |
149 | + if (ret < 0) | |
150 | + log("unable to submit urb. OOM!?\n"); | |
151 | +} | |
152 | + | |
153 | +static int send_command (struct snd_usb_caiaqdev *dev, | |
154 | + unsigned char command, | |
155 | + const unsigned char *buffer, | |
156 | + int len) | |
157 | +{ | |
158 | + int actual_len; | |
159 | + struct usb_device *usb_dev = dev->chip.dev; | |
160 | + | |
161 | + if (!usb_dev) | |
162 | + return -EIO; | |
163 | + | |
164 | + if (len > EP1_BUFSIZE - 1) | |
165 | + len = EP1_BUFSIZE - 1; | |
166 | + | |
167 | + if (buffer && len > 0) | |
168 | + memcpy(dev->ep1_out_buf+1, buffer, len); | |
169 | + | |
170 | + dev->ep1_out_buf[0] = command; | |
171 | + return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1), | |
172 | + dev->ep1_out_buf, len+1, &actual_len, 200); | |
173 | +} | |
174 | + | |
175 | +int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, | |
176 | + int rate, int depth, int bpp) | |
177 | +{ | |
178 | + int ret; | |
179 | + char tmp[5]; | |
180 | + | |
181 | + switch (rate) { | |
182 | + case 44100: tmp[0] = SAMPLERATE_44100; break; | |
183 | + case 48000: tmp[0] = SAMPLERATE_48000; break; | |
184 | + case 88200: tmp[0] = SAMPLERATE_88200; break; | |
185 | + case 96000: tmp[0] = SAMPLERATE_96000; break; | |
186 | + case 192000: tmp[0] = SAMPLERATE_192000; break; | |
187 | + default: return -EINVAL; | |
188 | + } | |
189 | + | |
190 | + switch (depth) { | |
191 | + case 16: tmp[1] = DEPTH_16; break; | |
192 | + case 24: tmp[1] = DEPTH_24; break; | |
193 | + default: return -EINVAL; | |
194 | + } | |
195 | + | |
196 | + tmp[2] = bpp & 0xff; | |
197 | + tmp[3] = bpp >> 8; | |
198 | + tmp[4] = 1; /* packets per microframe */ | |
199 | + | |
200 | + debug("setting audio params: %d Hz, %d bits, %d bpp\n", | |
201 | + rate, depth, bpp); | |
202 | + | |
203 | + dev->audio_parm_answer = -1; | |
204 | + ret = send_command(dev, EP1_CMD_AUDIO_PARAMS, tmp, sizeof(tmp)); | |
205 | + | |
206 | + if (ret) | |
207 | + return ret; | |
208 | + | |
209 | + if (!wait_event_timeout(dev->ep1_wait_queue, | |
210 | + dev->audio_parm_answer >= 0, HZ)) | |
211 | + return -EPIPE; | |
212 | + | |
213 | + if (dev->audio_parm_answer != 1) | |
214 | + debug("unable to set the device's audio params\n"); | |
215 | + | |
216 | + return dev->audio_parm_answer == 1 ? 0 : -EINVAL; | |
217 | +} | |
218 | + | |
219 | +int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, | |
220 | + int digital, int analog, int erp) | |
221 | +{ | |
222 | + char tmp[3] = { digital, analog, erp }; | |
223 | + return send_command(dev, EP1_CMD_AUTO_MSG, tmp, sizeof(tmp)); | |
224 | +} | |
225 | + | |
226 | +static void setup_card(struct snd_usb_caiaqdev *dev) | |
227 | +{ | |
228 | + int ret; | |
229 | + char val[3]; | |
230 | + | |
231 | + /* device-specific startup specials */ | |
232 | + switch (dev->chip.usb_id) { | |
233 | + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): | |
234 | + /* RigKontrol2 - display centered dash ('-') */ | |
235 | + val[0] = 0x00; | |
236 | + val[1] = 0x00; | |
237 | + val[2] = 0x01; | |
238 | + send_command(dev, EP1_CMD_WRITE_IO, val, 3); | |
239 | + break; | |
240 | + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | |
241 | + /* Audio Kontrol 1 - make USB-LED stop blinking */ | |
242 | + val[0] = 0x00; | |
243 | + send_command(dev, EP1_CMD_WRITE_IO, val, 1); | |
244 | + break; | |
245 | + } | |
246 | + | |
247 | + ret = snd_usb_caiaq_audio_init(dev); | |
248 | + if (ret < 0) | |
249 | + log("Unable to set up audio system (ret=%d)\n", ret); | |
250 | + | |
251 | + ret = snd_usb_caiaq_midi_init(dev); | |
252 | + if (ret < 0) | |
253 | + log("Unable to set up MIDI system (ret=%d)\n", ret); | |
254 | + | |
255 | +#ifdef CONFIG_SND_USB_CAIAQ_INPUT | |
256 | + ret = snd_usb_caiaq_input_init(dev); | |
257 | + if (ret < 0) | |
258 | + log("Unable to set up input system (ret=%d)\n", ret); | |
259 | +#endif | |
260 | + | |
261 | + /* finally, register the card and all its sub-instances */ | |
262 | + ret = snd_card_register(dev->chip.card); | |
263 | + if (ret < 0) { | |
264 | + log("snd_card_register() returned %d\n", ret); | |
265 | + snd_card_free(dev->chip.card); | |
266 | + } | |
267 | +} | |
268 | + | |
269 | +static struct snd_card* create_card(struct usb_device* usb_dev) | |
270 | +{ | |
271 | + int devnum; | |
272 | + struct snd_card *card; | |
273 | + struct snd_usb_caiaqdev *dev; | |
274 | + | |
275 | + for (devnum = 0; devnum < SNDRV_CARDS; devnum++) | |
276 | + if (enable[devnum] && !snd_card_used[devnum]) | |
277 | + break; | |
278 | + | |
279 | + if (devnum >= SNDRV_CARDS) | |
280 | + return NULL; | |
281 | + | |
282 | + card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, | |
283 | + sizeof(struct snd_usb_caiaqdev)); | |
284 | + if (!card) | |
285 | + return NULL; | |
286 | + | |
287 | + dev = caiaqdev(card); | |
288 | + dev->chip.dev = usb_dev; | |
289 | + dev->chip.card = card; | |
290 | + dev->chip.usb_id = USB_ID(usb_dev->descriptor.idVendor, | |
291 | + usb_dev->descriptor.idProduct); | |
292 | + spin_lock_init(&dev->spinlock); | |
293 | + snd_card_set_dev(card, &usb_dev->dev); | |
294 | + | |
295 | + return card; | |
296 | +} | |
297 | + | |
298 | +static int init_card(struct snd_usb_caiaqdev *dev) | |
299 | +{ | |
300 | + char *c; | |
301 | + struct usb_device *usb_dev = dev->chip.dev; | |
302 | + struct snd_card *card = dev->chip.card; | |
303 | + int err, len; | |
304 | + | |
305 | + if (usb_set_interface(usb_dev, 0, 1) != 0) { | |
306 | + log("can't set alt interface.\n"); | |
307 | + return -EIO; | |
308 | + } | |
309 | + | |
310 | + usb_init_urb(&dev->ep1_in_urb); | |
311 | + usb_init_urb(&dev->midi_out_urb); | |
312 | + | |
313 | + usb_fill_bulk_urb(&dev->ep1_in_urb, usb_dev, | |
314 | + usb_rcvbulkpipe(usb_dev, 0x1), | |
315 | + dev->ep1_in_buf, EP1_BUFSIZE, | |
316 | + usb_ep1_command_reply_dispatch, dev); | |
317 | + | |
318 | + usb_fill_bulk_urb(&dev->midi_out_urb, usb_dev, | |
319 | + usb_sndbulkpipe(usb_dev, 0x1), | |
320 | + dev->midi_out_buf, EP1_BUFSIZE, | |
321 | + snd_usb_caiaq_midi_output_done, dev); | |
322 | + | |
323 | + init_waitqueue_head(&dev->ep1_wait_queue); | |
324 | + init_waitqueue_head(&dev->prepare_wait_queue); | |
325 | + | |
326 | + if (usb_submit_urb(&dev->ep1_in_urb, GFP_KERNEL) != 0) | |
327 | + return -EIO; | |
328 | + | |
329 | + err = send_command(dev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); | |
330 | + if (err) | |
331 | + return err; | |
332 | + | |
333 | + if (!wait_event_timeout(dev->ep1_wait_queue, dev->spec_received, HZ)) | |
334 | + return -ENODEV; | |
335 | + | |
336 | + usb_string(usb_dev, usb_dev->descriptor.iManufacturer, | |
337 | + dev->vendor_name, CAIAQ_USB_STR_LEN); | |
338 | + | |
339 | + usb_string(usb_dev, usb_dev->descriptor.iProduct, | |
340 | + dev->product_name, CAIAQ_USB_STR_LEN); | |
341 | + | |
342 | + usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, | |
343 | + dev->serial, CAIAQ_USB_STR_LEN); | |
344 | + | |
345 | + /* terminate serial string at first white space occurence */ | |
346 | + c = strchr(dev->serial, ' '); | |
347 | + if (c) | |
348 | + *c = '\0'; | |
349 | + | |
350 | + strcpy(card->driver, MODNAME); | |
351 | + strcpy(card->shortname, dev->product_name); | |
352 | + | |
353 | + len = snprintf(card->longname, sizeof(card->longname), | |
354 | + "%s %s (serial %s, ", | |
355 | + dev->vendor_name, dev->product_name, dev->serial); | |
356 | + | |
357 | + if (len < sizeof(card->longname) - 2) | |
358 | + len += usb_make_path(usb_dev, card->longname + len, | |
359 | + sizeof(card->longname) - len); | |
360 | + | |
361 | + card->longname[len++] = ')'; | |
362 | + card->longname[len] = '\0'; | |
363 | + setup_card(dev); | |
364 | + return 0; | |
365 | +} | |
366 | + | |
367 | +static int snd_probe(struct usb_interface *intf, | |
368 | + const struct usb_device_id *id) | |
369 | +{ | |
370 | + int ret; | |
371 | + struct snd_card *card; | |
372 | + struct usb_device *device = interface_to_usbdev(intf); | |
373 | + | |
374 | + card = create_card(device); | |
375 | + | |
376 | + if (!card) | |
377 | + return -ENOMEM; | |
378 | + | |
379 | + dev_set_drvdata(&intf->dev, card); | |
380 | + ret = init_card(caiaqdev(card)); | |
381 | + if (ret < 0) { | |
382 | + log("unable to init card! (ret=%d)\n", ret); | |
383 | + snd_card_free(card); | |
384 | + return ret; | |
385 | + } | |
386 | + | |
387 | + return 0; | |
388 | +} | |
389 | + | |
390 | +static void snd_disconnect(struct usb_interface *intf) | |
391 | +{ | |
392 | + struct snd_usb_caiaqdev *dev; | |
393 | + struct snd_card *card = dev_get_drvdata(&intf->dev); | |
394 | + | |
395 | + debug("snd_disconnect(%p)\n", intf); | |
396 | + | |
397 | + if (!card) | |
398 | + return; | |
399 | + | |
400 | + dev = caiaqdev(card); | |
401 | + snd_card_disconnect(card); | |
402 | + | |
403 | +#ifdef CONFIG_SND_USB_CAIAQ_INPUT | |
404 | + snd_usb_caiaq_input_free(dev); | |
405 | +#endif | |
406 | + snd_usb_caiaq_audio_free(dev); | |
407 | + | |
408 | + usb_kill_urb(&dev->ep1_in_urb); | |
409 | + usb_kill_urb(&dev->midi_out_urb); | |
410 | + | |
411 | + snd_card_free(card); | |
412 | + usb_reset_device(interface_to_usbdev(intf)); | |
413 | +} | |
414 | + | |
415 | + | |
416 | +MODULE_DEVICE_TABLE(usb, snd_usb_id_table); | |
417 | +static struct usb_driver snd_usb_driver = { | |
418 | + .name = MODNAME, | |
419 | + .probe = snd_probe, | |
420 | + .disconnect = snd_disconnect, | |
421 | + .id_table = snd_usb_id_table, | |
422 | +}; | |
423 | + | |
424 | +static int __init snd_module_init(void) | |
425 | +{ | |
426 | + return usb_register(&snd_usb_driver); | |
427 | +} | |
428 | + | |
429 | +static void __exit snd_module_exit(void) | |
430 | +{ | |
431 | + usb_deregister(&snd_usb_driver); | |
432 | +} | |
433 | + | |
434 | +module_init(snd_module_init) | |
435 | +module_exit(snd_module_exit) |
sound/usb/caiaq/caiaq-device.h
1 | +#ifndef CAIAQ_DEVICE_H | |
2 | +#define CAIAQ_DEVICE_H | |
3 | + | |
4 | +#include "../usbaudio.h" | |
5 | + | |
6 | +#define USB_VID_NATIVEINSTRUMENTS 0x17cc | |
7 | + | |
8 | +#define USB_PID_RIGKONTROL2 0x1969 | |
9 | +#define USB_PID_KORECONTROLLER 0x4711 | |
10 | +#define USB_PID_AK1 0x0815 | |
11 | +#define USB_PID_AUDIO8DJ 0x1978 | |
12 | + | |
13 | +#define EP1_BUFSIZE 64 | |
14 | +#define CAIAQ_USB_STR_LEN 0xff | |
15 | +#define MAX_STREAMS 32 | |
16 | + | |
17 | +//#define SND_USB_CAIAQ_DEBUG | |
18 | + | |
19 | +#define MODNAME "snd-usb-caiaq" | |
20 | +#define log(x...) snd_printk(KERN_WARNING MODNAME" log: " x) | |
21 | + | |
22 | +#ifdef SND_USB_CAIAQ_DEBUG | |
23 | +#define debug(x...) snd_printk(KERN_WARNING MODNAME " debug: " x) | |
24 | +#else | |
25 | +#define debug(x...) do { } while(0) | |
26 | +#endif | |
27 | + | |
28 | +#define EP1_CMD_GET_DEVICE_INFO 0x1 | |
29 | +#define EP1_CMD_READ_ERP 0x2 | |
30 | +#define EP1_CMD_READ_ANALOG 0x3 | |
31 | +#define EP1_CMD_READ_IO 0x4 | |
32 | +#define EP1_CMD_WRITE_IO 0x5 | |
33 | +#define EP1_CMD_MIDI_READ 0x6 | |
34 | +#define EP1_CMD_MIDI_WRITE 0x7 | |
35 | +#define EP1_CMD_AUDIO_PARAMS 0x9 | |
36 | +#define EP1_CMD_AUTO_MSG 0xb | |
37 | + | |
38 | +struct caiaq_device_spec { | |
39 | + unsigned short fw_version; | |
40 | + unsigned char hw_subtype; | |
41 | + unsigned char num_erp; | |
42 | + unsigned char num_analog_in; | |
43 | + unsigned char num_digital_in; | |
44 | + unsigned char num_digital_out; | |
45 | + unsigned char num_analog_audio_out; | |
46 | + unsigned char num_analog_audio_in; | |
47 | + unsigned char num_digital_audio_out; | |
48 | + unsigned char num_digital_audio_in; | |
49 | + unsigned char num_midi_out; | |
50 | + unsigned char num_midi_in; | |
51 | + unsigned char data_alignment; | |
52 | +} __attribute__ ((packed)); | |
53 | + | |
54 | +struct snd_usb_caiaq_cb_info; | |
55 | + | |
56 | +struct snd_usb_caiaqdev { | |
57 | + struct snd_usb_audio chip; | |
58 | + | |
59 | + struct urb ep1_in_urb; | |
60 | + struct urb midi_out_urb; | |
61 | + struct urb **data_urbs_in; | |
62 | + struct urb **data_urbs_out; | |
63 | + struct snd_usb_caiaq_cb_info *data_cb_info; | |
64 | + | |
65 | + unsigned char ep1_in_buf[EP1_BUFSIZE]; | |
66 | + unsigned char ep1_out_buf[EP1_BUFSIZE]; | |
67 | + unsigned char midi_out_buf[EP1_BUFSIZE]; | |
68 | + | |
69 | + struct caiaq_device_spec spec; | |
70 | + spinlock_t spinlock; | |
71 | + wait_queue_head_t ep1_wait_queue; | |
72 | + wait_queue_head_t prepare_wait_queue; | |
73 | + int spec_received, audio_parm_answer; | |
74 | + | |
75 | + char vendor_name[CAIAQ_USB_STR_LEN]; | |
76 | + char product_name[CAIAQ_USB_STR_LEN]; | |
77 | + char serial[CAIAQ_USB_STR_LEN]; | |
78 | + | |
79 | + int n_streams, n_audio_in, n_audio_out; | |
80 | + int streaming, first_packet, output_running; | |
81 | + int audio_in_buf_pos[MAX_STREAMS]; | |
82 | + int audio_out_buf_pos[MAX_STREAMS]; | |
83 | + int period_in_count[MAX_STREAMS]; | |
84 | + int period_out_count[MAX_STREAMS]; | |
85 | + int input_panic, output_panic; | |
86 | + char *audio_in_buf, *audio_out_buf; | |
87 | + unsigned int samplerates; | |
88 | + | |
89 | + struct snd_pcm_substream *sub_playback[MAX_STREAMS]; | |
90 | + struct snd_pcm_substream *sub_capture[MAX_STREAMS]; | |
91 | + | |
92 | + /* Linux input */ | |
93 | +#ifdef CONFIG_SND_USB_CAIAQ_INPUT | |
94 | + struct input_dev *input_dev; | |
95 | +#endif | |
96 | + | |
97 | + /* ALSA */ | |
98 | + struct snd_pcm *pcm; | |
99 | + struct snd_pcm_hardware pcm_info; | |
100 | + struct snd_rawmidi *rmidi; | |
101 | + struct snd_rawmidi_substream *midi_receive_substream; | |
102 | + struct snd_rawmidi_substream *midi_out_substream; | |
103 | +}; | |
104 | + | |
105 | +struct snd_usb_caiaq_cb_info { | |
106 | + struct snd_usb_caiaqdev *dev; | |
107 | + int index; | |
108 | +}; | |
109 | + | |
110 | +#define caiaqdev(c) ((struct snd_usb_caiaqdev*)(c)->private_data) | |
111 | + | |
112 | +int snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *dev, int rate, int depth, int bbp); | |
113 | +int snd_usb_caiaq_set_auto_msg (struct snd_usb_caiaqdev *dev, int digital, int analog, int erp); | |
114 | + | |
115 | + | |
116 | +#endif /* CAIAQ_DEVICE_H */ |
sound/usb/caiaq/caiaq-input.c
1 | +/* | |
2 | + * Copyright (c) 2006,2007 Daniel Mack, Tim Ruetz | |
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/input.h> | |
23 | +#include <linux/usb.h> | |
24 | +#include <linux/spinlock.h> | |
25 | +#include <sound/driver.h> | |
26 | +#include <sound/core.h> | |
27 | +#include <sound/rawmidi.h> | |
28 | +#include <sound/pcm.h> | |
29 | +#include "caiaq-device.h" | |
30 | +#include "caiaq-input.h" | |
31 | + | |
32 | +#ifdef CONFIG_SND_USB_CAIAQ_INPUT | |
33 | + | |
34 | +static unsigned char keycode_ak1[] = { KEY_C, KEY_B, KEY_A }; | |
35 | +static unsigned char keycode_rk2[] = { KEY_1, KEY_2, KEY_3, KEY_4, | |
36 | + KEY_5, KEY_6, KEY_7 }; | |
37 | + | |
38 | +#define DEG90 (range/2) | |
39 | +#define DEG180 (range) | |
40 | +#define DEG270 (DEG90 + DEG180) | |
41 | +#define DEG360 (DEG180 * 2) | |
42 | +#define HIGH_PEAK (268) | |
43 | +#define LOW_PEAK (-7) | |
44 | + | |
45 | +/* some of these devices have endless rotation potentiometers | |
46 | + * built in which use two tapers, 90 degrees phase shifted. | |
47 | + * this algorithm decodes them to one single value, ranging | |
48 | + * from 0 to 999 */ | |
49 | +static unsigned int decode_erp(unsigned char a, unsigned char b) | |
50 | +{ | |
51 | + int weight_a, weight_b; | |
52 | + int pos_a, pos_b; | |
53 | + int ret; | |
54 | + int range = HIGH_PEAK - LOW_PEAK; | |
55 | + int mid_value = (HIGH_PEAK + LOW_PEAK) / 2; | |
56 | + | |
57 | + weight_b = abs(mid_value-a) - (range/2 - 100)/2; | |
58 | + | |
59 | + if (weight_b < 0) | |
60 | + weight_b = 0; | |
61 | + | |
62 | + if (weight_b > 100) | |
63 | + weight_b = 100; | |
64 | + | |
65 | + weight_a = 100 - weight_b; | |
66 | + | |
67 | + if (a < mid_value) { | |
68 | + /* 0..90 and 270..360 degrees */ | |
69 | + pos_b = b - LOW_PEAK + DEG270; | |
70 | + if (pos_b >= DEG360) | |
71 | + pos_b -= DEG360; | |
72 | + } else | |
73 | + /* 90..270 degrees */ | |
74 | + pos_b = HIGH_PEAK - b + DEG90; | |
75 | + | |
76 | + | |
77 | + if (b > mid_value) | |
78 | + /* 0..180 degrees */ | |
79 | + pos_a = a - LOW_PEAK; | |
80 | + else | |
81 | + /* 180..360 degrees */ | |
82 | + pos_a = HIGH_PEAK - a + DEG180; | |
83 | + | |
84 | + /* interpolate both slider values, depending on weight factors */ | |
85 | + /* 0..99 x DEG360 */ | |
86 | + ret = pos_a * weight_a + pos_b * weight_b; | |
87 | + | |
88 | + /* normalize to 0..999 */ | |
89 | + ret *= 10; | |
90 | + ret /= DEG360; | |
91 | + | |
92 | + if (ret < 0) | |
93 | + ret += 1000; | |
94 | + | |
95 | + if (ret >= 1000) | |
96 | + ret -= 1000; | |
97 | + | |
98 | + return ret; | |
99 | +} | |
100 | + | |
101 | +#undef DEG90 | |
102 | +#undef DEG180 | |
103 | +#undef DEG270 | |
104 | +#undef DEG360 | |
105 | +#undef HIGH_PEAK | |
106 | +#undef LOW_PEAK | |
107 | + | |
108 | + | |
109 | +static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, | |
110 | + const char *buf, unsigned int len) | |
111 | +{ | |
112 | + switch(dev->input_dev->id.product) { | |
113 | + case USB_PID_RIGKONTROL2: | |
114 | + input_report_abs(dev->input_dev, ABS_X, (buf[4] << 8) |buf[5]); | |
115 | + input_report_abs(dev->input_dev, ABS_Y, (buf[0] << 8) |buf[1]); | |
116 | + input_report_abs(dev->input_dev, ABS_Z, (buf[2] << 8) |buf[3]); | |
117 | + input_sync(dev->input_dev); | |
118 | + break; | |
119 | + } | |
120 | +} | |
121 | + | |
122 | +static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, | |
123 | + const char *buf, unsigned int len) | |
124 | +{ | |
125 | + int i; | |
126 | + | |
127 | + switch(dev->input_dev->id.product) { | |
128 | + case USB_PID_AK1: | |
129 | + i = decode_erp(buf[0], buf[1]); | |
130 | + input_report_abs(dev->input_dev, ABS_X, i); | |
131 | + input_sync(dev->input_dev); | |
132 | + break; | |
133 | + } | |
134 | +} | |
135 | + | |
136 | +static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, | |
137 | + char *buf, unsigned int len) | |
138 | +{ | |
139 | + int i; | |
140 | + unsigned char *keycode = dev->input_dev->keycode; | |
141 | + | |
142 | + if (!keycode) | |
143 | + return; | |
144 | + | |
145 | + if (dev->input_dev->id.product == USB_PID_RIGKONTROL2) | |
146 | + for (i=0; i<len; i++) | |
147 | + buf[i] = ~buf[i]; | |
148 | + | |
149 | + for (i=0; (i<dev->input_dev->keycodemax) && (i < len); i++) | |
150 | + input_report_key(dev->input_dev, keycode[i], | |
151 | + buf[i/8] & (1 << (i%8))); | |
152 | + | |
153 | + input_sync(dev->input_dev); | |
154 | +} | |
155 | + | |
156 | +void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, | |
157 | + char *buf, | |
158 | + unsigned int len) | |
159 | +{ | |
160 | + if (!dev->input_dev || (len < 1)) | |
161 | + return; | |
162 | + | |
163 | + switch (buf[0]) { | |
164 | + case EP1_CMD_READ_ANALOG: | |
165 | + snd_caiaq_input_read_analog(dev, buf+1, len-1); | |
166 | + break; | |
167 | + case EP1_CMD_READ_ERP: | |
168 | + snd_caiaq_input_read_erp(dev, buf+1, len-1); | |
169 | + break; | |
170 | + case EP1_CMD_READ_IO: | |
171 | + snd_caiaq_input_read_io(dev, buf+1, len-1); | |
172 | + break; | |
173 | + } | |
174 | +} | |
175 | + | |
176 | +int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) | |
177 | +{ | |
178 | + struct usb_device *usb_dev = dev->chip.dev; | |
179 | + struct input_dev *input; | |
180 | + int i, ret; | |
181 | + | |
182 | + input = input_allocate_device(); | |
183 | + if (!input) | |
184 | + return -ENOMEM; | |
185 | + | |
186 | + input->name = dev->product_name; | |
187 | + input->id.bustype = BUS_USB; | |
188 | + input->id.vendor = usb_dev->descriptor.idVendor; | |
189 | + input->id.product = usb_dev->descriptor.idProduct; | |
190 | + input->id.version = usb_dev->descriptor.bcdDevice; | |
191 | + | |
192 | + switch (dev->chip.usb_id) { | |
193 | + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): | |
194 | + input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | |
195 | + input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_Z); | |
196 | + input->keycode = keycode_rk2; | |
197 | + input->keycodesize = sizeof(char); | |
198 | + input->keycodemax = ARRAY_SIZE(keycode_rk2); | |
199 | + for (i=0; i<ARRAY_SIZE(keycode_rk2); i++) | |
200 | + set_bit(keycode_rk2[i], input->keybit); | |
201 | + | |
202 | + input_set_abs_params(input, ABS_X, 0, 4096, 0, 10); | |
203 | + input_set_abs_params(input, ABS_Y, 0, 4096, 0, 10); | |
204 | + input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); | |
205 | + snd_usb_caiaq_set_auto_msg(dev, 1, 10, 0); | |
206 | + break; | |
207 | + case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): | |
208 | + input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | |
209 | + input->absbit[0] = BIT(ABS_X); | |
210 | + input->keycode = keycode_ak1; | |
211 | + input->keycodesize = sizeof(char); | |
212 | + input->keycodemax = ARRAY_SIZE(keycode_ak1); | |
213 | + for (i=0; i<ARRAY_SIZE(keycode_ak1); i++) | |
214 | + set_bit(keycode_ak1[i], input->keybit); | |
215 | + | |
216 | + input_set_abs_params(input, ABS_X, 0, 999, 0, 10); | |
217 | + snd_usb_caiaq_set_auto_msg(dev, 1, 0, 5); | |
218 | + break; | |
219 | + default: | |
220 | + /* no input methods supported on this device */ | |
221 | + input_free_device(input); | |
222 | + return 0; | |
223 | + } | |
224 | + | |
225 | + ret = input_register_device(input); | |
226 | + if (ret < 0) { | |
227 | + input_free_device(input); | |
228 | + return ret; | |
229 | + } | |
230 | + | |
231 | + dev->input_dev = input; | |
232 | + return 0; | |
233 | +} | |
234 | + | |
235 | +void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) | |
236 | +{ | |
237 | + if (!dev || !dev->input_dev) | |
238 | + return; | |
239 | + | |
240 | + input_unregister_device(dev->input_dev); | |
241 | + input_free_device(dev->input_dev); | |
242 | + dev->input_dev = NULL; | |
243 | +} | |
244 | + | |
245 | +#endif /* CONFIG_SND_USB_CAIAQ_INPUT */ |
sound/usb/caiaq/caiaq-input.h
sound/usb/caiaq/caiaq-midi.c
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 | + | |
35 | +static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream) | |
36 | +{ | |
37 | + return 0; | |
38 | +} | |
39 | + | |
40 | +static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream) | |
41 | +{ | |
42 | + return 0; | |
43 | +} | |
44 | + | |
45 | +static 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 | + | |
56 | +static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream) | |
57 | +{ | |
58 | + return 0; | |
59 | +} | |
60 | + | |
61 | +static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream) | |
62 | +{ | |
63 | + return 0; | |
64 | +} | |
65 | + | |
66 | +static 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 | + | |
87 | +static 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 | + | |
104 | +static 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 | + | |
111 | +static 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 | + | |
118 | +void 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 | + | |
127 | +int __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 | + | |
162 | +void 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 | +} |
sound/usb/caiaq/caiaq-midi.h
1 | +#ifndef CAIAQ_MIDI_H | |
2 | +#define CAIAQ_MIDI_H | |
3 | + | |
4 | +int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *dev); | |
5 | +void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, int port, const char *buf, int len); | |
6 | +void snd_usb_caiaq_midi_output_done(struct urb* urb); | |
7 | + | |
8 | +#endif /* CAIAQ_MIDI_H */ |