Commit | Line | Data |
---|---|---|
705ececd | 1 | /* |
e1a164d7 | 2 | * Line6 Linux USB driver - 0.9.1beta |
705ececd | 3 | * |
1027f476 | 4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
705ececd MG |
5 | * |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License as | |
8 | * published by the Free Software Foundation, version 2. | |
9 | * | |
10 | */ | |
11 | ||
5a0e3ad6 | 12 | #include <linux/slab.h> |
705ececd MG |
13 | #include <sound/core.h> |
14 | #include <sound/control.h> | |
15 | #include <sound/pcm.h> | |
16 | #include <sound/pcm_params.h> | |
17 | ||
18 | #include "audio.h" | |
19 | #include "capture.h" | |
1027f476 | 20 | #include "driver.h" |
705ececd MG |
21 | #include "playback.h" |
22 | #include "pod.h" | |
23 | ||
1027f476 MG |
24 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE |
25 | ||
e1a164d7 | 26 | static struct snd_line6_pcm *dev2pcm(struct device *dev) |
1027f476 MG |
27 | { |
28 | struct usb_interface *interface = to_usb_interface(dev); | |
29 | struct usb_line6 *line6 = usb_get_intfdata(interface); | |
30 | struct snd_line6_pcm *line6pcm = line6->line6pcm; | |
31 | return line6pcm; | |
32 | } | |
33 | ||
34 | /* | |
35 | "read" request on "impulse_volume" special file. | |
36 | */ | |
37 | static ssize_t pcm_get_impulse_volume(struct device *dev, | |
e1a164d7 | 38 | struct device_attribute *attr, char *buf) |
1027f476 MG |
39 | { |
40 | return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume); | |
41 | } | |
42 | ||
43 | /* | |
44 | "write" request on "impulse_volume" special file. | |
45 | */ | |
46 | static ssize_t pcm_set_impulse_volume(struct device *dev, | |
47 | struct device_attribute *attr, | |
48 | const char *buf, size_t count) | |
49 | { | |
50 | struct snd_line6_pcm *line6pcm = dev2pcm(dev); | |
cdf5e551 JT |
51 | int value; |
52 | int rv; | |
53 | ||
54 | rv = kstrtoint(buf, 10, &value); | |
55 | if (rv < 0) | |
56 | return rv; | |
57 | ||
1027f476 MG |
58 | line6pcm->impulse_volume = value; |
59 | ||
e1a164d7 | 60 | if (value > 0) |
0ca54888 | 61 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); |
1027f476 | 62 | else |
0ca54888 | 63 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); |
1027f476 MG |
64 | |
65 | return count; | |
66 | } | |
67 | ||
68 | /* | |
69 | "read" request on "impulse_period" special file. | |
70 | */ | |
71 | static ssize_t pcm_get_impulse_period(struct device *dev, | |
e1a164d7 | 72 | struct device_attribute *attr, char *buf) |
1027f476 MG |
73 | { |
74 | return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period); | |
75 | } | |
76 | ||
77 | /* | |
78 | "write" request on "impulse_period" special file. | |
79 | */ | |
80 | static ssize_t pcm_set_impulse_period(struct device *dev, | |
81 | struct device_attribute *attr, | |
82 | const char *buf, size_t count) | |
83 | { | |
84 | dev2pcm(dev)->impulse_period = simple_strtoul(buf, NULL, 10); | |
85 | return count; | |
86 | } | |
87 | ||
a3a972a0 | 88 | static DEVICE_ATTR(impulse_volume, S_IWUSR | S_IRUGO, pcm_get_impulse_volume, |
e1a164d7 | 89 | pcm_set_impulse_volume); |
a3a972a0 | 90 | static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period, |
e1a164d7 | 91 | pcm_set_impulse_period); |
1027f476 MG |
92 | |
93 | #endif | |
94 | ||
6b02a17e MG |
95 | static bool test_flags(unsigned long flags0, unsigned long flags1, |
96 | unsigned long mask) | |
97 | { | |
98 | return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); | |
99 | } | |
100 | ||
0ca54888 | 101 | int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) |
1027f476 | 102 | { |
e1a164d7 MG |
103 | unsigned long flags_old = |
104 | __sync_fetch_and_or(&line6pcm->flags, channels); | |
1027f476 | 105 | unsigned long flags_new = flags_old | channels; |
0ca54888 | 106 | unsigned long flags_final = flags_old; |
1027f476 | 107 | int err = 0; |
82a74d4a | 108 | |
1027f476 | 109 | line6pcm->prev_fbuf = NULL; |
e1a164d7 | 110 | |
0ca54888 MG |
111 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { |
112 | /* We may be invoked multiple times in a row so allocate once only */ | |
113 | if (!line6pcm->buffer_in) { | |
114 | line6pcm->buffer_in = | |
115 | kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | |
116 | line6pcm->max_packet_size, GFP_KERNEL); | |
117 | ||
118 | if (!line6pcm->buffer_in) { | |
119 | dev_err(line6pcm->line6->ifcdev, | |
120 | "cannot malloc capture buffer\n"); | |
121 | err = -ENOMEM; | |
122 | goto pcm_acquire_error; | |
123 | } | |
124 | ||
125 | flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; | |
126 | } | |
127 | } | |
128 | ||
129 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { | |
1027f476 | 130 | /* |
e1a164d7 MG |
131 | Waiting for completion of active URBs in the stop handler is |
132 | a bug, we therefore report an error if capturing is restarted | |
133 | too soon. | |
134 | */ | |
0ca54888 MG |
135 | if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { |
136 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); | |
1027f476 | 137 | return -EBUSY; |
6b02a17e MG |
138 | } |
139 | ||
1027f476 MG |
140 | line6pcm->count_in = 0; |
141 | line6pcm->prev_fsize = 0; | |
142 | err = line6_submit_audio_in_all_urbs(line6pcm); | |
e1a164d7 | 143 | |
6b02a17e | 144 | if (err < 0) |
0ca54888 MG |
145 | goto pcm_acquire_error; |
146 | ||
147 | flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; | |
1027f476 | 148 | } |
e1a164d7 | 149 | |
0ca54888 MG |
150 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { |
151 | /* We may be invoked multiple times in a row so allocate once only */ | |
152 | if (!line6pcm->buffer_out) { | |
153 | line6pcm->buffer_out = | |
154 | kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | |
155 | line6pcm->max_packet_size, GFP_KERNEL); | |
156 | ||
157 | if (!line6pcm->buffer_out) { | |
158 | dev_err(line6pcm->line6->ifcdev, | |
159 | "cannot malloc playback buffer\n"); | |
160 | err = -ENOMEM; | |
161 | goto pcm_acquire_error; | |
162 | } | |
1027f476 | 163 | |
0ca54888 MG |
164 | flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; |
165 | } | |
166 | } | |
6b02a17e | 167 | |
0ca54888 MG |
168 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { |
169 | /* | |
170 | See comment above regarding PCM restart. | |
171 | */ | |
172 | if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) { | |
173 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); | |
174 | return -EBUSY; | |
6b02a17e MG |
175 | } |
176 | ||
1027f476 MG |
177 | line6pcm->count_out = 0; |
178 | err = line6_submit_audio_out_all_urbs(line6pcm); | |
e1a164d7 | 179 | |
6b02a17e | 180 | if (err < 0) |
0ca54888 MG |
181 | goto pcm_acquire_error; |
182 | ||
183 | flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; | |
1027f476 | 184 | } |
e1a164d7 | 185 | |
1027f476 | 186 | return 0; |
6b02a17e | 187 | |
0ca54888 MG |
188 | pcm_acquire_error: |
189 | /* | |
190 | If not all requested resources/streams could be obtained, release | |
191 | those which were successfully obtained (if any). | |
192 | */ | |
193 | line6_pcm_release(line6pcm, flags_final & channels); | |
6b02a17e | 194 | return err; |
1027f476 MG |
195 | } |
196 | ||
0ca54888 | 197 | int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) |
1027f476 | 198 | { |
e1a164d7 MG |
199 | unsigned long flags_old = |
200 | __sync_fetch_and_and(&line6pcm->flags, ~channels); | |
1027f476 MG |
201 | unsigned long flags_new = flags_old & ~channels; |
202 | ||
0ca54888 | 203 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) |
1027f476 | 204 | line6_unlink_audio_in_urbs(line6pcm); |
6b02a17e | 205 | |
0ca54888 MG |
206 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { |
207 | line6_wait_clear_audio_in_urbs(line6pcm); | |
208 | line6_free_capture_buffer(line6pcm); | |
1027f476 MG |
209 | } |
210 | ||
0ca54888 | 211 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) |
1027f476 | 212 | line6_unlink_audio_out_urbs(line6pcm); |
6b02a17e | 213 | |
0ca54888 MG |
214 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { |
215 | line6_wait_clear_audio_out_urbs(line6pcm); | |
216 | line6_free_playback_buffer(line6pcm); | |
1027f476 | 217 | } |
1027f476 MG |
218 | |
219 | return 0; | |
220 | } | |
221 | ||
705ececd MG |
222 | /* trigger callback */ |
223 | int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) | |
224 | { | |
225 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | |
705ececd MG |
226 | struct snd_pcm_substream *s; |
227 | int err; | |
228 | unsigned long flags; | |
229 | ||
230 | spin_lock_irqsave(&line6pcm->lock_trigger, flags); | |
0ca54888 | 231 | clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); |
705ececd | 232 | |
705ececd | 233 | snd_pcm_group_for_each_entry(s, substream) { |
68dc3dde | 234 | switch (s->stream) { |
705ececd | 235 | case SNDRV_PCM_STREAM_PLAYBACK: |
1027f476 | 236 | err = snd_line6_playback_trigger(line6pcm, cmd); |
705ececd | 237 | |
68dc3dde GKH |
238 | if (err < 0) { |
239 | spin_unlock_irqrestore(&line6pcm->lock_trigger, | |
240 | flags); | |
705ececd MG |
241 | return err; |
242 | } | |
243 | ||
244 | break; | |
245 | ||
246 | case SNDRV_PCM_STREAM_CAPTURE: | |
1027f476 | 247 | err = snd_line6_capture_trigger(line6pcm, cmd); |
705ececd | 248 | |
68dc3dde GKH |
249 | if (err < 0) { |
250 | spin_unlock_irqrestore(&line6pcm->lock_trigger, | |
251 | flags); | |
705ececd MG |
252 | return err; |
253 | } | |
254 | ||
255 | break; | |
256 | ||
257 | default: | |
e1a164d7 MG |
258 | dev_err(line6pcm->line6->ifcdev, |
259 | "Unknown stream direction %d\n", s->stream); | |
705ececd MG |
260 | } |
261 | } | |
262 | ||
263 | spin_unlock_irqrestore(&line6pcm->lock_trigger, flags); | |
264 | return 0; | |
265 | } | |
266 | ||
267 | /* control info callback */ | |
1027f476 MG |
268 | static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, |
269 | struct snd_ctl_elem_info *uinfo) | |
68dc3dde | 270 | { |
705ececd MG |
271 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
272 | uinfo->count = 2; | |
273 | uinfo->value.integer.min = 0; | |
274 | uinfo->value.integer.max = 256; | |
275 | return 0; | |
276 | } | |
277 | ||
278 | /* control get callback */ | |
1027f476 MG |
279 | static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, |
280 | struct snd_ctl_elem_value *ucontrol) | |
68dc3dde | 281 | { |
705ececd MG |
282 | int i; |
283 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
284 | ||
68dc3dde | 285 | for (i = 2; i--;) |
1027f476 | 286 | ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; |
705ececd MG |
287 | |
288 | return 0; | |
289 | } | |
290 | ||
291 | /* control put callback */ | |
1027f476 MG |
292 | static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, |
293 | struct snd_ctl_elem_value *ucontrol) | |
68dc3dde | 294 | { |
705ececd MG |
295 | int i, changed = 0; |
296 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
297 | ||
68dc3dde | 298 | for (i = 2; i--;) |
e1a164d7 MG |
299 | if (line6pcm->volume_playback[i] != |
300 | ucontrol->value.integer.value[i]) { | |
301 | line6pcm->volume_playback[i] = | |
302 | ucontrol->value.integer.value[i]; | |
705ececd MG |
303 | changed = 1; |
304 | } | |
305 | ||
306 | return changed; | |
307 | } | |
308 | ||
309 | /* control definition */ | |
1027f476 | 310 | static struct snd_kcontrol_new line6_control_playback = { |
705ececd MG |
311 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
312 | .name = "PCM Playback Volume", | |
313 | .index = 0, | |
314 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | |
1027f476 MG |
315 | .info = snd_line6_control_playback_info, |
316 | .get = snd_line6_control_playback_get, | |
317 | .put = snd_line6_control_playback_put | |
705ececd MG |
318 | }; |
319 | ||
320 | /* | |
321 | Cleanup the PCM device. | |
322 | */ | |
323 | static void line6_cleanup_pcm(struct snd_pcm *pcm) | |
324 | { | |
325 | int i; | |
326 | struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); | |
327 | ||
1027f476 MG |
328 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE |
329 | device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume); | |
330 | device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period); | |
331 | #endif | |
332 | ||
68dc3dde GKH |
333 | for (i = LINE6_ISO_BUFFERS; i--;) { |
334 | if (line6pcm->urb_audio_out[i]) { | |
705ececd MG |
335 | usb_kill_urb(line6pcm->urb_audio_out[i]); |
336 | usb_free_urb(line6pcm->urb_audio_out[i]); | |
337 | } | |
68dc3dde | 338 | if (line6pcm->urb_audio_in[i]) { |
705ececd MG |
339 | usb_kill_urb(line6pcm->urb_audio_in[i]); |
340 | usb_free_urb(line6pcm->urb_audio_in[i]); | |
341 | } | |
342 | } | |
343 | } | |
344 | ||
345 | /* create a PCM device */ | |
346 | static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm) | |
347 | { | |
348 | struct snd_pcm *pcm; | |
349 | int err; | |
350 | ||
68dc3dde | 351 | err = snd_pcm_new(line6pcm->line6->card, |
e1a164d7 MG |
352 | (char *)line6pcm->line6->properties->name, |
353 | 0, 1, 1, &pcm); | |
68dc3dde | 354 | if (err < 0) |
705ececd MG |
355 | return err; |
356 | ||
357 | pcm->private_data = line6pcm; | |
358 | pcm->private_free = line6_cleanup_pcm; | |
359 | line6pcm->pcm = pcm; | |
360 | strcpy(pcm->name, line6pcm->line6->properties->name); | |
361 | ||
362 | /* set operators */ | |
afb9091d SB |
363 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, |
364 | &snd_line6_playback_ops); | |
e1a164d7 | 365 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); |
705ececd MG |
366 | |
367 | /* pre-allocation of buffers */ | |
68dc3dde | 368 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, |
e1a164d7 MG |
369 | snd_dma_continuous_data |
370 | (GFP_KERNEL), 64 * 1024, | |
371 | 128 * 1024); | |
705ececd MG |
372 | |
373 | return 0; | |
374 | } | |
375 | ||
376 | /* PCM device destructor */ | |
377 | static int snd_line6_pcm_free(struct snd_device *device) | |
378 | { | |
379 | return 0; | |
380 | } | |
381 | ||
1027f476 MG |
382 | /* |
383 | Stop substream if still running. | |
384 | */ | |
385 | static void pcm_disconnect_substream(struct snd_pcm_substream *substream) | |
386 | { | |
027360c5 | 387 | if (substream->runtime && snd_pcm_running(substream)) |
1027f476 | 388 | snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); |
1027f476 MG |
389 | } |
390 | ||
391 | /* | |
392 | Stop PCM stream. | |
393 | */ | |
394 | void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) | |
395 | { | |
e1a164d7 MG |
396 | pcm_disconnect_substream(get_substream |
397 | (line6pcm, SNDRV_PCM_STREAM_CAPTURE)); | |
398 | pcm_disconnect_substream(get_substream | |
399 | (line6pcm, SNDRV_PCM_STREAM_PLAYBACK)); | |
1027f476 MG |
400 | line6_unlink_wait_clear_audio_out_urbs(line6pcm); |
401 | line6_unlink_wait_clear_audio_in_urbs(line6pcm); | |
402 | } | |
403 | ||
705ececd MG |
404 | /* |
405 | Create and register the PCM device and mixer entries. | |
406 | Create URBs for playback and capture. | |
407 | */ | |
68dc3dde GKH |
408 | int line6_init_pcm(struct usb_line6 *line6, |
409 | struct line6_pcm_properties *properties) | |
705ececd MG |
410 | { |
411 | static struct snd_device_ops pcm_ops = { | |
412 | .dev_free = snd_line6_pcm_free, | |
413 | }; | |
414 | ||
415 | int err; | |
416 | int ep_read = 0, ep_write = 0; | |
417 | struct snd_line6_pcm *line6pcm; | |
418 | ||
68dc3dde | 419 | if (!(line6->properties->capabilities & LINE6_BIT_PCM)) |
e1a164d7 | 420 | return 0; /* skip PCM initialization and report success */ |
705ececd MG |
421 | |
422 | /* initialize PCM subsystem based on product id: */ | |
68dc3dde | 423 | switch (line6->product) { |
705ececd | 424 | case LINE6_DEVID_BASSPODXT: |
68dc3dde GKH |
425 | case LINE6_DEVID_BASSPODXTLIVE: |
426 | case LINE6_DEVID_BASSPODXTPRO: | |
427 | case LINE6_DEVID_PODXT: | |
428 | case LINE6_DEVID_PODXTLIVE: | |
429 | case LINE6_DEVID_PODXTPRO: | |
16dc1040 | 430 | case LINE6_DEVID_PODHD300: |
e1a164d7 | 431 | ep_read = 0x82; |
705ececd MG |
432 | ep_write = 0x01; |
433 | break; | |
434 | ||
4c6fb5fc | 435 | case LINE6_DEVID_PODHD500: |
68dc3dde GKH |
436 | case LINE6_DEVID_PODX3: |
437 | case LINE6_DEVID_PODX3LIVE: | |
e1a164d7 | 438 | ep_read = 0x86; |
705ececd MG |
439 | ep_write = 0x02; |
440 | break; | |
441 | ||
68dc3dde | 442 | case LINE6_DEVID_POCKETPOD: |
e1a164d7 | 443 | ep_read = 0x82; |
705ececd MG |
444 | ep_write = 0x02; |
445 | break; | |
446 | ||
68dc3dde | 447 | case LINE6_DEVID_GUITARPORT: |
1027f476 MG |
448 | case LINE6_DEVID_PODSTUDIO_GX: |
449 | case LINE6_DEVID_PODSTUDIO_UX1: | |
450 | case LINE6_DEVID_PODSTUDIO_UX2: | |
705ececd | 451 | case LINE6_DEVID_TONEPORT_GX: |
1027f476 MG |
452 | case LINE6_DEVID_TONEPORT_UX1: |
453 | case LINE6_DEVID_TONEPORT_UX2: | |
e1a164d7 | 454 | ep_read = 0x82; |
705ececd MG |
455 | ep_write = 0x01; |
456 | break; | |
457 | ||
1027f476 | 458 | /* this is for interface_number == 1: |
e1a164d7 MG |
459 | case LINE6_DEVID_TONEPORT_UX2: |
460 | case LINE6_DEVID_PODSTUDIO_UX2: | |
461 | ep_read = 0x87; | |
462 | ep_write = 0x00; | |
463 | break; | |
464 | */ | |
705ececd MG |
465 | |
466 | default: | |
467 | MISSING_CASE; | |
468 | } | |
469 | ||
470 | line6pcm = kzalloc(sizeof(struct snd_line6_pcm), GFP_KERNEL); | |
471 | ||
68dc3dde | 472 | if (line6pcm == NULL) |
705ececd MG |
473 | return -ENOMEM; |
474 | ||
1027f476 MG |
475 | line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; |
476 | line6pcm->volume_monitor = 255; | |
705ececd MG |
477 | line6pcm->line6 = line6; |
478 | line6pcm->ep_audio_read = ep_read; | |
479 | line6pcm->ep_audio_write = ep_write; | |
3b08db37 SH |
480 | |
481 | /* Read and write buffers are sized identically, so choose minimum */ | |
482 | line6pcm->max_packet_size = min( | |
483 | usb_maxpacket(line6->usbdev, | |
484 | usb_rcvisocpipe(line6->usbdev, ep_read), 0), | |
485 | usb_maxpacket(line6->usbdev, | |
486 | usb_sndisocpipe(line6->usbdev, ep_write), 1)); | |
487 | ||
705ececd MG |
488 | line6pcm->properties = properties; |
489 | line6->line6pcm = line6pcm; | |
490 | ||
491 | /* PCM device: */ | |
68dc3dde GKH |
492 | err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops); |
493 | if (err < 0) | |
705ececd MG |
494 | return err; |
495 | ||
496 | snd_card_set_dev(line6->card, line6->ifcdev); | |
497 | ||
68dc3dde GKH |
498 | err = snd_line6_new_pcm(line6pcm); |
499 | if (err < 0) | |
705ececd MG |
500 | return err; |
501 | ||
502 | spin_lock_init(&line6pcm->lock_audio_out); | |
503 | spin_lock_init(&line6pcm->lock_audio_in); | |
504 | spin_lock_init(&line6pcm->lock_trigger); | |
505 | ||
1027f476 | 506 | err = line6_create_audio_out_urbs(line6pcm); |
68dc3dde | 507 | if (err < 0) |
705ececd MG |
508 | return err; |
509 | ||
1027f476 | 510 | err = line6_create_audio_in_urbs(line6pcm); |
68dc3dde | 511 | if (err < 0) |
705ececd MG |
512 | return err; |
513 | ||
514 | /* mixer: */ | |
e1a164d7 MG |
515 | err = |
516 | snd_ctl_add(line6->card, | |
517 | snd_ctl_new1(&line6_control_playback, line6pcm)); | |
1027f476 MG |
518 | if (err < 0) |
519 | return err; | |
520 | ||
521 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | |
522 | /* impulse response test: */ | |
523 | err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume); | |
68dc3dde | 524 | if (err < 0) |
705ececd MG |
525 | return err; |
526 | ||
1027f476 MG |
527 | err = device_create_file(line6->ifcdev, &dev_attr_impulse_period); |
528 | if (err < 0) | |
529 | return err; | |
530 | ||
531 | line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; | |
532 | #endif | |
533 | ||
705ececd MG |
534 | return 0; |
535 | } | |
536 | ||
537 | /* prepare pcm callback */ | |
538 | int snd_line6_prepare(struct snd_pcm_substream *substream) | |
539 | { | |
540 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | |
541 | ||
665f3f50 SH |
542 | switch (substream->stream) { |
543 | case SNDRV_PCM_STREAM_PLAYBACK: | |
0ca54888 | 544 | if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) |
6b02a17e MG |
545 | line6_unlink_wait_clear_audio_out_urbs(line6pcm); |
546 | ||
665f3f50 SH |
547 | break; |
548 | ||
549 | case SNDRV_PCM_STREAM_CAPTURE: | |
0ca54888 | 550 | if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) |
6b02a17e MG |
551 | line6_unlink_wait_clear_audio_in_urbs(line6pcm); |
552 | ||
665f3f50 SH |
553 | break; |
554 | ||
555 | default: | |
556 | MISSING_CASE; | |
557 | } | |
558 | ||
0ca54888 | 559 | if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { |
1027f476 | 560 | line6pcm->count_out = 0; |
705ececd MG |
561 | line6pcm->pos_out = 0; |
562 | line6pcm->pos_out_done = 0; | |
705ececd | 563 | line6pcm->bytes_out = 0; |
1027f476 | 564 | line6pcm->count_in = 0; |
705ececd MG |
565 | line6pcm->pos_in_done = 0; |
566 | line6pcm->bytes_in = 0; | |
567 | } | |
568 | ||
569 | return 0; | |
570 | } |