aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMarkus Grabner <grabner@icg.tugraz.at>2011-12-09 20:12:32 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-12-09 22:26:09 -0500
commit6b02a17ee5cd5d200dbe4a285a4e750f70884967 (patch)
tree4f8a0f63d324ddbb284911a47303282ef0ef0c08 /drivers
parent665f3f506b1c2684d6f78d6d03c038d1712e561d (diff)
staging: line6: fixed ALSA/PCM interaction
The PCM subsystem in the Line6 driver is mainly used for PCM playback and capture by ALSA, but also has other tasks, most notably providing a low-latency software monitor for devices which don't support hardware monitoring (e.g., the TonePort series). This patch makes ALSA "play nicely" with the other components, i.e., prevents it from resetting the isochronous USB transfer while other PCM tasks (software monitoring) are running. Signed-off-by: Markus Grabner <grabner@icg.tugraz.at> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/line6/capture.c46
-rw-r--r--drivers/staging/line6/capture.h2
-rw-r--r--drivers/staging/line6/pcm.c65
-rw-r--r--drivers/staging/line6/playback.c46
-rw-r--r--drivers/staging/line6/playback.h2
-rw-r--r--drivers/staging/line6/revision.h2
6 files changed, 118 insertions, 45 deletions
diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c
index 8f59ff3e7a17..127f95247749 100644
--- a/drivers/staging/line6/capture.c
+++ b/drivers/staging/line6/capture.c
@@ -193,6 +193,31 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
193 } 193 }
194} 194}
195 195
196int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm)
197{
198 /* We may be invoked multiple times in a row so allocate once only */
199 if (line6pcm->buffer_in)
200 return 0;
201
202 line6pcm->buffer_in =
203 kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
204 line6pcm->max_packet_size, GFP_KERNEL);
205
206 if (!line6pcm->buffer_in) {
207 dev_err(line6pcm->line6->ifcdev,
208 "cannot malloc capture buffer\n");
209 return -ENOMEM;
210 }
211
212 return 0;
213}
214
215void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
216{
217 kfree(line6pcm->buffer_in);
218 line6pcm->buffer_in = NULL;
219}
220
196/* 221/*
197 * Callback for completed capture URB. 222 * Callback for completed capture URB.
198 */ 223 */
@@ -316,16 +341,11 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
316 } 341 }
317 /* -- [FD] end */ 342 /* -- [FD] end */
318 343
319 /* We may be invoked multiple times in a row so allocate once only */ 344 if ((line6pcm->flags & MASK_CAPTURE) == 0) {
320 if (!line6pcm->buffer_in) 345 ret = line6_alloc_capture_buffer(line6pcm);
321 line6pcm->buffer_in =
322 kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
323 line6pcm->max_packet_size, GFP_KERNEL);
324 346
325 if (!line6pcm->buffer_in) { 347 if (ret < 0)
326 dev_err(line6pcm->line6->ifcdev, 348 return ret;
327 "cannot malloc capture buffer\n");
328 return -ENOMEM;
329 } 349 }
330 350
331 ret = snd_pcm_lib_malloc_pages(substream, 351 ret = snd_pcm_lib_malloc_pages(substream,
@@ -342,9 +362,11 @@ static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
342{ 362{
343 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); 363 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
344 364
345 line6_unlink_wait_clear_audio_in_urbs(line6pcm); 365 if ((line6pcm->flags & MASK_CAPTURE) == 0) {
346 kfree(line6pcm->buffer_in); 366 line6_unlink_wait_clear_audio_in_urbs(line6pcm);
347 line6pcm->buffer_in = NULL; 367 line6_free_capture_buffer(line6pcm);
368 }
369
348 return snd_pcm_lib_free_pages(substream); 370 return snd_pcm_lib_free_pages(substream);
349} 371}
350 372
diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h
index a7509fbbb954..366cbaa7c88d 100644
--- a/drivers/staging/line6/capture.h
+++ b/drivers/staging/line6/capture.h
@@ -19,11 +19,13 @@
19 19
20extern struct snd_pcm_ops snd_line6_capture_ops; 20extern struct snd_pcm_ops snd_line6_capture_ops;
21 21
22extern int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm);
22extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, 23extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
23 int fsize); 24 int fsize);
24extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, 25extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
25 int length); 26 int length);
26extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); 27extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
28extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm);
27extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); 29extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
28extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm); 30extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
29extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm 31extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index 68727b2dfb8f..37675e66da81 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -86,17 +86,22 @@ static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period,
86 86
87#endif 87#endif
88 88
89static bool test_flags(unsigned long flags0, unsigned long flags1,
90 unsigned long mask)
91{
92 return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
93}
94
89int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) 95int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels)
90{ 96{
91 unsigned long flags_old = 97 unsigned long flags_old =
92 __sync_fetch_and_or(&line6pcm->flags, channels); 98 __sync_fetch_and_or(&line6pcm->flags, channels);
93 unsigned long flags_new = flags_old | channels; 99 unsigned long flags_new = flags_old | channels;
94 int err = 0; 100 int err = 0;
95 101
96 line6pcm->prev_fbuf = NULL; 102 line6pcm->prev_fbuf = NULL;
97 103
98 if (((flags_old & MASK_CAPTURE) == 0) && 104 if (test_flags(flags_old, flags_new, MASK_CAPTURE)) {
99 ((flags_new & MASK_CAPTURE) != 0)) {
100 /* 105 /*
101 Waiting for completion of active URBs in the stop handler is 106 Waiting for completion of active URBs in the stop handler is
102 a bug, we therefore report an error if capturing is restarted 107 a bug, we therefore report an error if capturing is restarted
@@ -105,34 +110,47 @@ int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels)
105 if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) 110 if (line6pcm->active_urb_in | line6pcm->unlink_urb_in)
106 return -EBUSY; 111 return -EBUSY;
107 112
113 if (!(flags_new & MASK_PCM_ALSA_CAPTURE)) {
114 err = line6_alloc_capture_buffer(line6pcm);
115
116 if (err < 0)
117 goto pcm_start_error;
118 }
119
108 line6pcm->count_in = 0; 120 line6pcm->count_in = 0;
109 line6pcm->prev_fsize = 0; 121 line6pcm->prev_fsize = 0;
110 err = line6_submit_audio_in_all_urbs(line6pcm); 122 err = line6_submit_audio_in_all_urbs(line6pcm);
111 123
112 if (err < 0) { 124 if (err < 0)
113 __sync_fetch_and_and(&line6pcm->flags, ~channels); 125 goto pcm_start_error;
114 return err;
115 }
116 } 126 }
117 127
118 if (((flags_old & MASK_PLAYBACK) == 0) && 128 if (test_flags(flags_old, flags_new, MASK_PLAYBACK)) {
119 ((flags_new & MASK_PLAYBACK) != 0)) {
120 /* 129 /*
121 See comment above regarding PCM restart. 130 See comment above regarding PCM restart.
122 */ 131 */
123 if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) 132 if (line6pcm->active_urb_out | line6pcm->unlink_urb_out)
124 return -EBUSY; 133 return -EBUSY;
125 134
135 if (!(flags_new & MASK_PCM_ALSA_PLAYBACK)) {
136 err = line6_alloc_playback_buffer(line6pcm);
137
138 if (err < 0)
139 goto pcm_start_error;
140 }
141
126 line6pcm->count_out = 0; 142 line6pcm->count_out = 0;
127 err = line6_submit_audio_out_all_urbs(line6pcm); 143 err = line6_submit_audio_out_all_urbs(line6pcm);
128 144
129 if (err < 0) { 145 if (err < 0)
130 __sync_fetch_and_and(&line6pcm->flags, ~channels); 146 goto pcm_start_error;
131 return err;
132 }
133 } 147 }
134 148
135 return 0; 149 return 0;
150
151pcm_start_error:
152 __sync_fetch_and_and(&line6pcm->flags, ~channels);
153 return err;
136} 154}
137 155
138int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels) 156int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels)
@@ -141,14 +159,18 @@ int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels)
141 __sync_fetch_and_and(&line6pcm->flags, ~channels); 159 __sync_fetch_and_and(&line6pcm->flags, ~channels);
142 unsigned long flags_new = flags_old & ~channels; 160 unsigned long flags_new = flags_old & ~channels;
143 161
144 if (((flags_old & MASK_CAPTURE) != 0) && 162 if (test_flags(flags_new, flags_old, MASK_CAPTURE)) {
145 ((flags_new & MASK_CAPTURE) == 0)) {
146 line6_unlink_audio_in_urbs(line6pcm); 163 line6_unlink_audio_in_urbs(line6pcm);
164
165 if (!(flags_old & MASK_PCM_ALSA_CAPTURE))
166 line6_free_capture_buffer(line6pcm);
147 } 167 }
148 168
149 if (((flags_old & MASK_PLAYBACK) != 0) && 169 if (test_flags(flags_new, flags_old, MASK_PLAYBACK)) {
150 ((flags_new & MASK_PLAYBACK) == 0)) {
151 line6_unlink_audio_out_urbs(line6pcm); 170 line6_unlink_audio_out_urbs(line6pcm);
171
172 if (!(flags_old & MASK_PCM_ALSA_PLAYBACK))
173 line6_free_playback_buffer(line6pcm);
152 } 174 }
153 175
154 return 0; 176 return 0;
@@ -476,18 +498,21 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)
476 498
477 switch (substream->stream) { 499 switch (substream->stream) {
478 case SNDRV_PCM_STREAM_PLAYBACK: 500 case SNDRV_PCM_STREAM_PLAYBACK:
479 line6_unlink_wait_clear_audio_out_urbs(line6pcm); 501 if ((line6pcm->flags & MASK_PLAYBACK) == 0)
502 line6_unlink_wait_clear_audio_out_urbs(line6pcm);
503
480 break; 504 break;
481 505
482 case SNDRV_PCM_STREAM_CAPTURE: 506 case SNDRV_PCM_STREAM_CAPTURE:
483 line6_unlink_wait_clear_audio_in_urbs(line6pcm); 507 if ((line6pcm->flags & MASK_CAPTURE) == 0)
508 line6_unlink_wait_clear_audio_in_urbs(line6pcm);
509
484 break; 510 break;
485 511
486 default: 512 default:
487 MISSING_CASE; 513 MISSING_CASE;
488 } 514 }
489 515
490
491 if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) { 516 if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) {
492 line6pcm->count_out = 0; 517 line6pcm->count_out = 0;
493 line6pcm->pos_out = 0; 518 line6pcm->pos_out = 0;
diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c
index 9a51b92c0948..4152db2328b7 100644
--- a/drivers/staging/line6/playback.c
+++ b/drivers/staging/line6/playback.c
@@ -351,6 +351,31 @@ void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
351 wait_clear_audio_out_urbs(line6pcm); 351 wait_clear_audio_out_urbs(line6pcm);
352} 352}
353 353
354int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm)
355{
356 /* We may be invoked multiple times in a row so allocate once only */
357 if (line6pcm->buffer_out)
358 return 0;
359
360 line6pcm->buffer_out =
361 kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
362 line6pcm->max_packet_size, GFP_KERNEL);
363
364 if (!line6pcm->buffer_out) {
365 dev_err(line6pcm->line6->ifcdev,
366 "cannot malloc playback buffer\n");
367 return -ENOMEM;
368 }
369
370 return 0;
371}
372
373void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
374{
375 kfree(line6pcm->buffer_out);
376 line6pcm->buffer_out = NULL;
377}
378
354/* 379/*
355 Callback for completed playback URB. 380 Callback for completed playback URB.
356*/ 381*/
@@ -459,16 +484,11 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream,
459 } 484 }
460 /* -- [FD] end */ 485 /* -- [FD] end */
461 486
462 /* We may be invoked multiple times in a row so allocate once only */ 487 if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
463 if (!line6pcm->buffer_out) 488 ret = line6_alloc_playback_buffer(line6pcm);
464 line6pcm->buffer_out =
465 kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
466 line6pcm->max_packet_size, GFP_KERNEL);
467 489
468 if (!line6pcm->buffer_out) { 490 if (ret < 0)
469 dev_err(line6pcm->line6->ifcdev, 491 return ret;
470 "cannot malloc playback buffer\n");
471 return -ENOMEM;
472 } 492 }
473 493
474 ret = snd_pcm_lib_malloc_pages(substream, 494 ret = snd_pcm_lib_malloc_pages(substream,
@@ -485,9 +505,11 @@ static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
485{ 505{
486 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); 506 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
487 507
488 line6_unlink_wait_clear_audio_out_urbs(line6pcm); 508 if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
489 kfree(line6pcm->buffer_out); 509 line6_unlink_wait_clear_audio_out_urbs(line6pcm);
490 line6pcm->buffer_out = NULL; 510 line6_free_playback_buffer(line6pcm);
511 }
512
491 return snd_pcm_lib_free_pages(substream); 513 return snd_pcm_lib_free_pages(substream);
492} 514}
493 515
diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h
index f2fc8c0526e3..02487ff24538 100644
--- a/drivers/staging/line6/playback.h
+++ b/drivers/staging/line6/playback.h
@@ -29,7 +29,9 @@
29 29
30extern struct snd_pcm_ops snd_line6_playback_ops; 30extern struct snd_pcm_ops snd_line6_playback_ops;
31 31
32extern int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm);
32extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); 33extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
34extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
33extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); 35extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
34extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm); 36extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
35extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm 37extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
diff --git a/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h
index 350d0dfff8f8..b4eee2b73831 100644
--- a/drivers/staging/line6/revision.h
+++ b/drivers/staging/line6/revision.h
@@ -1,4 +1,4 @@
1#ifndef DRIVER_REVISION 1#ifndef DRIVER_REVISION
2/* current subversion revision */ 2/* current subversion revision */
3#define DRIVER_REVISION " (revision 690)" 3#define DRIVER_REVISION " (904)"
4#endif 4#endif