Commit | Line | Data |
---|---|---|
705ececd | 1 | /* |
c078a4aa | 2 | * Line 6 Linux USB driver |
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> |
ccddbe4a | 13 | #include <linux/export.h> |
705ececd MG |
14 | #include <sound/core.h> |
15 | #include <sound/control.h> | |
16 | #include <sound/pcm.h> | |
17 | #include <sound/pcm_params.h> | |
18 | ||
705ececd | 19 | #include "capture.h" |
1027f476 | 20 | #include "driver.h" |
705ececd | 21 | #include "playback.h" |
705ececd | 22 | |
075587b7 TI |
23 | /* impulse response volume controls */ |
24 | static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol, | |
25 | struct snd_ctl_elem_info *uinfo) | |
1027f476 | 26 | { |
075587b7 TI |
27 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
28 | uinfo->count = 1; | |
29 | uinfo->value.integer.min = 0; | |
30 | uinfo->value.integer.max = 255; | |
31 | return 0; | |
1027f476 MG |
32 | } |
33 | ||
075587b7 TI |
34 | static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol, |
35 | struct snd_ctl_elem_value *ucontrol) | |
1027f476 | 36 | { |
075587b7 TI |
37 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
38 | ||
39 | ucontrol->value.integer.value[0] = line6pcm->impulse_volume; | |
40 | return 0; | |
1027f476 MG |
41 | } |
42 | ||
075587b7 TI |
43 | static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, |
44 | struct snd_ctl_elem_value *ucontrol) | |
1027f476 | 45 | { |
075587b7 TI |
46 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
47 | int value = ucontrol->value.integer.value[0]; | |
cdf5e551 | 48 | |
075587b7 TI |
49 | if (line6pcm->impulse_volume == value) |
50 | return 0; | |
cdf5e551 | 51 | |
1027f476 | 52 | line6pcm->impulse_volume = value; |
e1a164d7 | 53 | if (value > 0) |
0ca54888 | 54 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); |
1027f476 | 55 | else |
0ca54888 | 56 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); |
075587b7 TI |
57 | return 1; |
58 | } | |
1027f476 | 59 | |
075587b7 TI |
60 | /* impulse response period controls */ |
61 | static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol, | |
62 | struct snd_ctl_elem_info *uinfo) | |
63 | { | |
64 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
65 | uinfo->count = 1; | |
66 | uinfo->value.integer.min = 0; | |
67 | uinfo->value.integer.max = 2000; | |
68 | return 0; | |
1027f476 MG |
69 | } |
70 | ||
075587b7 TI |
71 | static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol, |
72 | struct snd_ctl_elem_value *ucontrol) | |
1027f476 | 73 | { |
075587b7 TI |
74 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
75 | ||
76 | ucontrol->value.integer.value[0] = line6pcm->impulse_period; | |
77 | return 0; | |
1027f476 MG |
78 | } |
79 | ||
075587b7 TI |
80 | static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol, |
81 | struct snd_ctl_elem_value *ucontrol) | |
1027f476 | 82 | { |
075587b7 TI |
83 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
84 | int value = ucontrol->value.integer.value[0]; | |
a3762902 | 85 | |
075587b7 TI |
86 | if (line6pcm->impulse_period == value) |
87 | return 0; | |
a3762902 | 88 | |
075587b7 TI |
89 | line6pcm->impulse_period = value; |
90 | return 1; | |
1027f476 | 91 | } |
1027f476 | 92 | |
6b02a17e MG |
93 | static bool test_flags(unsigned long flags0, unsigned long flags1, |
94 | unsigned long mask) | |
95 | { | |
96 | return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); | |
97 | } | |
98 | ||
0ca54888 | 99 | int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) |
1027f476 | 100 | { |
9f613601 AB |
101 | unsigned long flags_old, flags_new, flags_final; |
102 | int err; | |
103 | ||
104 | do { | |
105 | flags_old = ACCESS_ONCE(line6pcm->flags); | |
106 | flags_new = flags_old | channels; | |
107 | } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); | |
108 | ||
5343ecf4 | 109 | flags_final = 0; |
82a74d4a | 110 | |
1027f476 | 111 | line6pcm->prev_fbuf = NULL; |
e1a164d7 | 112 | |
0ca54888 | 113 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { |
928f25ee | 114 | /* Invoked multiple times in a row so allocate once only */ |
0ca54888 MG |
115 | if (!line6pcm->buffer_in) { |
116 | line6pcm->buffer_in = | |
117 | kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | |
118 | line6pcm->max_packet_size, GFP_KERNEL); | |
0ca54888 | 119 | if (!line6pcm->buffer_in) { |
0ca54888 MG |
120 | err = -ENOMEM; |
121 | goto pcm_acquire_error; | |
122 | } | |
0ca54888 | 123 | } |
5343ecf4 TI |
124 | |
125 | flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; | |
0ca54888 MG |
126 | } |
127 | ||
128 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { | |
1027f476 | 129 | /* |
e1a164d7 MG |
130 | Waiting for completion of active URBs in the stop handler is |
131 | a bug, we therefore report an error if capturing is restarted | |
132 | too soon. | |
133 | */ | |
6aa7f8ef | 134 | if (line6pcm->active_urb_in || line6pcm->unlink_urb_in) { |
0ca54888 | 135 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); |
eab22e40 TI |
136 | err = -EBUSY; |
137 | goto pcm_acquire_error; | |
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 | 150 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { |
928f25ee | 151 | /* Invoked multiple times in a row so allocate once only */ |
0ca54888 MG |
152 | if (!line6pcm->buffer_out) { |
153 | line6pcm->buffer_out = | |
154 | kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | |
155 | line6pcm->max_packet_size, GFP_KERNEL); | |
0ca54888 | 156 | if (!line6pcm->buffer_out) { |
0ca54888 MG |
157 | err = -ENOMEM; |
158 | goto pcm_acquire_error; | |
159 | } | |
0ca54888 | 160 | } |
5343ecf4 TI |
161 | |
162 | flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; | |
0ca54888 | 163 | } |
6b02a17e | 164 | |
0ca54888 MG |
165 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { |
166 | /* | |
167 | See comment above regarding PCM restart. | |
168 | */ | |
6aa7f8ef | 169 | if (line6pcm->active_urb_out || line6pcm->unlink_urb_out) { |
0ca54888 MG |
170 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); |
171 | return -EBUSY; | |
6b02a17e MG |
172 | } |
173 | ||
1027f476 MG |
174 | line6pcm->count_out = 0; |
175 | err = line6_submit_audio_out_all_urbs(line6pcm); | |
e1a164d7 | 176 | |
6b02a17e | 177 | if (err < 0) |
0ca54888 MG |
178 | goto pcm_acquire_error; |
179 | ||
180 | flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; | |
1027f476 | 181 | } |
e1a164d7 | 182 | |
1027f476 | 183 | return 0; |
6b02a17e | 184 | |
0ca54888 MG |
185 | pcm_acquire_error: |
186 | /* | |
187 | If not all requested resources/streams could be obtained, release | |
188 | those which were successfully obtained (if any). | |
189 | */ | |
5343ecf4 | 190 | line6_pcm_release(line6pcm, flags_final); |
6b02a17e | 191 | return err; |
1027f476 | 192 | } |
ccddbe4a | 193 | EXPORT_SYMBOL_GPL(line6_pcm_acquire); |
1027f476 | 194 | |
0ca54888 | 195 | int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) |
1027f476 | 196 | { |
9f613601 AB |
197 | unsigned long flags_old, flags_new; |
198 | ||
199 | do { | |
200 | flags_old = ACCESS_ONCE(line6pcm->flags); | |
201 | flags_new = flags_old & ~channels; | |
202 | } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); | |
1027f476 | 203 | |
0ca54888 | 204 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) |
1027f476 | 205 | line6_unlink_audio_in_urbs(line6pcm); |
6b02a17e | 206 | |
0ca54888 MG |
207 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { |
208 | line6_wait_clear_audio_in_urbs(line6pcm); | |
209 | line6_free_capture_buffer(line6pcm); | |
1027f476 MG |
210 | } |
211 | ||
0ca54888 | 212 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) |
1027f476 | 213 | line6_unlink_audio_out_urbs(line6pcm); |
6b02a17e | 214 | |
0ca54888 MG |
215 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { |
216 | line6_wait_clear_audio_out_urbs(line6pcm); | |
217 | line6_free_playback_buffer(line6pcm); | |
1027f476 | 218 | } |
1027f476 MG |
219 | |
220 | return 0; | |
221 | } | |
ccddbe4a | 222 | EXPORT_SYMBOL_GPL(line6_pcm_release); |
1027f476 | 223 | |
705ececd MG |
224 | /* trigger callback */ |
225 | int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) | |
226 | { | |
227 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | |
705ececd | 228 | struct snd_pcm_substream *s; |
f2a76225 | 229 | int err = 0; |
705ececd | 230 | |
0ca54888 | 231 | clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); |
705ececd | 232 | |
705ececd | 233 | snd_pcm_group_for_each_entry(s, substream) { |
7d70c81c TI |
234 | if (s->pcm->card != substream->pcm->card) |
235 | continue; | |
68dc3dde | 236 | switch (s->stream) { |
705ececd | 237 | case SNDRV_PCM_STREAM_PLAYBACK: |
1027f476 | 238 | err = snd_line6_playback_trigger(line6pcm, cmd); |
705ececd MG |
239 | break; |
240 | ||
241 | case SNDRV_PCM_STREAM_CAPTURE: | |
1027f476 | 242 | err = snd_line6_capture_trigger(line6pcm, cmd); |
705ececd MG |
243 | break; |
244 | ||
245 | default: | |
e1a164d7 MG |
246 | dev_err(line6pcm->line6->ifcdev, |
247 | "Unknown stream direction %d\n", s->stream); | |
f2a76225 TI |
248 | err = -EINVAL; |
249 | break; | |
705ececd | 250 | } |
f2a76225 TI |
251 | if (err < 0) |
252 | break; | |
705ececd MG |
253 | } |
254 | ||
f2a76225 | 255 | return err; |
705ececd MG |
256 | } |
257 | ||
258 | /* control info callback */ | |
1027f476 MG |
259 | static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, |
260 | struct snd_ctl_elem_info *uinfo) | |
68dc3dde | 261 | { |
705ececd MG |
262 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
263 | uinfo->count = 2; | |
264 | uinfo->value.integer.min = 0; | |
265 | uinfo->value.integer.max = 256; | |
266 | return 0; | |
267 | } | |
268 | ||
269 | /* control get callback */ | |
1027f476 MG |
270 | static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, |
271 | struct snd_ctl_elem_value *ucontrol) | |
68dc3dde | 272 | { |
705ececd MG |
273 | int i; |
274 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
275 | ||
68dc3dde | 276 | for (i = 2; i--;) |
1027f476 | 277 | ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; |
705ececd MG |
278 | |
279 | return 0; | |
280 | } | |
281 | ||
282 | /* control put callback */ | |
1027f476 MG |
283 | static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, |
284 | struct snd_ctl_elem_value *ucontrol) | |
68dc3dde | 285 | { |
705ececd MG |
286 | int i, changed = 0; |
287 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
288 | ||
68dc3dde | 289 | for (i = 2; i--;) |
e1a164d7 MG |
290 | if (line6pcm->volume_playback[i] != |
291 | ucontrol->value.integer.value[i]) { | |
292 | line6pcm->volume_playback[i] = | |
293 | ucontrol->value.integer.value[i]; | |
705ececd MG |
294 | changed = 1; |
295 | } | |
296 | ||
297 | return changed; | |
298 | } | |
299 | ||
300 | /* control definition */ | |
075587b7 TI |
301 | static struct snd_kcontrol_new line6_controls[] = { |
302 | { | |
303 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
304 | .name = "PCM Playback Volume", | |
305 | .info = snd_line6_control_playback_info, | |
306 | .get = snd_line6_control_playback_get, | |
307 | .put = snd_line6_control_playback_put | |
308 | }, | |
309 | { | |
310 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
311 | .name = "Impulse Response Volume", | |
312 | .info = snd_line6_impulse_volume_info, | |
313 | .get = snd_line6_impulse_volume_get, | |
314 | .put = snd_line6_impulse_volume_put | |
315 | }, | |
316 | { | |
317 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
318 | .name = "Impulse Response Period", | |
319 | .info = snd_line6_impulse_period_info, | |
320 | .get = snd_line6_impulse_period_get, | |
321 | .put = snd_line6_impulse_period_put | |
322 | }, | |
705ececd MG |
323 | }; |
324 | ||
325 | /* | |
326 | Cleanup the PCM device. | |
327 | */ | |
328 | static void line6_cleanup_pcm(struct snd_pcm *pcm) | |
329 | { | |
330 | int i; | |
331 | struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); | |
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 | } | |
b45a7c56 | 343 | kfree(line6pcm); |
705ececd MG |
344 | } |
345 | ||
346 | /* create a PCM device */ | |
b45a7c56 | 347 | static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) |
705ececd MG |
348 | { |
349 | struct snd_pcm *pcm; | |
350 | int err; | |
351 | ||
b45a7c56 TI |
352 | err = snd_pcm_new(line6->card, (char *)line6->properties->name, |
353 | 0, 1, 1, pcm_ret); | |
68dc3dde | 354 | if (err < 0) |
705ececd | 355 | return err; |
b45a7c56 TI |
356 | pcm = *pcm_ret; |
357 | strcpy(pcm->name, line6->properties->name); | |
705ececd MG |
358 | |
359 | /* set operators */ | |
afb9091d SB |
360 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, |
361 | &snd_line6_playback_ops); | |
e1a164d7 | 362 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); |
705ececd MG |
363 | |
364 | /* pre-allocation of buffers */ | |
68dc3dde | 365 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, |
e1a164d7 MG |
366 | snd_dma_continuous_data |
367 | (GFP_KERNEL), 64 * 1024, | |
368 | 128 * 1024); | |
705ececd MG |
369 | return 0; |
370 | } | |
371 | ||
1027f476 | 372 | /* |
5a475311 | 373 | Sync with PCM stream stops. |
1027f476 MG |
374 | */ |
375 | void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) | |
376 | { | |
1027f476 MG |
377 | line6_unlink_wait_clear_audio_out_urbs(line6pcm); |
378 | line6_unlink_wait_clear_audio_in_urbs(line6pcm); | |
379 | } | |
380 | ||
705ececd MG |
381 | /* |
382 | Create and register the PCM device and mixer entries. | |
383 | Create URBs for playback and capture. | |
384 | */ | |
68dc3dde GKH |
385 | int line6_init_pcm(struct usb_line6 *line6, |
386 | struct line6_pcm_properties *properties) | |
705ececd | 387 | { |
075587b7 | 388 | int i, err; |
16d603d3 CR |
389 | unsigned ep_read = line6->properties->ep_audio_r; |
390 | unsigned ep_write = line6->properties->ep_audio_w; | |
b45a7c56 | 391 | struct snd_pcm *pcm; |
705ececd MG |
392 | struct snd_line6_pcm *line6pcm; |
393 | ||
4cb1a4ae | 394 | if (!(line6->properties->capabilities & LINE6_CAP_PCM)) |
e1a164d7 | 395 | return 0; /* skip PCM initialization and report success */ |
705ececd | 396 | |
b45a7c56 TI |
397 | err = snd_line6_new_pcm(line6, &pcm); |
398 | if (err < 0) | |
399 | return err; | |
705ececd | 400 | |
b45a7c56 TI |
401 | line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); |
402 | if (!line6pcm) | |
705ececd MG |
403 | return -ENOMEM; |
404 | ||
b45a7c56 TI |
405 | line6pcm->pcm = pcm; |
406 | line6pcm->properties = properties; | |
1027f476 MG |
407 | line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; |
408 | line6pcm->volume_monitor = 255; | |
705ececd | 409 | line6pcm->line6 = line6; |
3b08db37 SH |
410 | |
411 | /* Read and write buffers are sized identically, so choose minimum */ | |
412 | line6pcm->max_packet_size = min( | |
413 | usb_maxpacket(line6->usbdev, | |
414 | usb_rcvisocpipe(line6->usbdev, ep_read), 0), | |
415 | usb_maxpacket(line6->usbdev, | |
416 | usb_sndisocpipe(line6->usbdev, ep_write), 1)); | |
417 | ||
705ececd MG |
418 | spin_lock_init(&line6pcm->lock_audio_out); |
419 | spin_lock_init(&line6pcm->lock_audio_in); | |
075587b7 | 420 | line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; |
705ececd | 421 | |
b45a7c56 TI |
422 | line6->line6pcm = line6pcm; |
423 | ||
424 | pcm->private_data = line6pcm; | |
425 | pcm->private_free = line6_cleanup_pcm; | |
426 | ||
1027f476 | 427 | err = line6_create_audio_out_urbs(line6pcm); |
68dc3dde | 428 | if (err < 0) |
705ececd MG |
429 | return err; |
430 | ||
1027f476 | 431 | err = line6_create_audio_in_urbs(line6pcm); |
68dc3dde | 432 | if (err < 0) |
705ececd MG |
433 | return err; |
434 | ||
435 | /* mixer: */ | |
075587b7 TI |
436 | for (i = 0; i < ARRAY_SIZE(line6_controls); i++) { |
437 | err = snd_ctl_add(line6->card, | |
438 | snd_ctl_new1(&line6_controls[i], line6pcm)); | |
439 | if (err < 0) | |
440 | return err; | |
441 | } | |
1027f476 | 442 | |
705ececd MG |
443 | return 0; |
444 | } | |
ccddbe4a | 445 | EXPORT_SYMBOL_GPL(line6_init_pcm); |
705ececd MG |
446 | |
447 | /* prepare pcm callback */ | |
448 | int snd_line6_prepare(struct snd_pcm_substream *substream) | |
449 | { | |
450 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | |
451 | ||
665f3f50 SH |
452 | switch (substream->stream) { |
453 | case SNDRV_PCM_STREAM_PLAYBACK: | |
0ca54888 | 454 | if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) |
6b02a17e MG |
455 | line6_unlink_wait_clear_audio_out_urbs(line6pcm); |
456 | ||
665f3f50 SH |
457 | break; |
458 | ||
459 | case SNDRV_PCM_STREAM_CAPTURE: | |
0ca54888 | 460 | if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) |
6b02a17e MG |
461 | line6_unlink_wait_clear_audio_in_urbs(line6pcm); |
462 | ||
665f3f50 | 463 | break; |
665f3f50 SH |
464 | } |
465 | ||
0ca54888 | 466 | if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { |
1027f476 | 467 | line6pcm->count_out = 0; |
705ececd MG |
468 | line6pcm->pos_out = 0; |
469 | line6pcm->pos_out_done = 0; | |
705ececd | 470 | line6pcm->bytes_out = 0; |
1027f476 | 471 | line6pcm->count_in = 0; |
705ececd MG |
472 | line6pcm->pos_in_done = 0; |
473 | line6pcm->bytes_in = 0; | |
474 | } | |
475 | ||
476 | return 0; | |
477 | } |