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