diff options
-rw-r--r-- | sound/usb/line6/capture.c | 88 | ||||
-rw-r--r-- | sound/usb/line6/capture.h | 1 | ||||
-rw-r--r-- | sound/usb/line6/pcm.c | 333 | ||||
-rw-r--r-- | sound/usb/line6/pcm.h | 144 | ||||
-rw-r--r-- | sound/usb/line6/playback.c | 104 | ||||
-rw-r--r-- | sound/usb/line6/playback.h | 1 | ||||
-rw-r--r-- | sound/usb/line6/toneport.c | 6 |
7 files changed, 252 insertions, 425 deletions
diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c index 21342a9dddd7..7b8186b6c0e4 100644 --- a/sound/usb/line6/capture.c +++ b/sound/usb/line6/capture.c | |||
@@ -67,20 +67,18 @@ static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) | |||
67 | 67 | ||
68 | /* | 68 | /* |
69 | Submit all currently available capture URBs. | 69 | Submit all currently available capture URBs. |
70 | must be called in line6pcm->in.lock context | ||
70 | */ | 71 | */ |
71 | int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) | 72 | int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) |
72 | { | 73 | { |
73 | unsigned long flags; | ||
74 | int ret = 0, i; | 74 | int ret = 0, i; |
75 | 75 | ||
76 | spin_lock_irqsave(&line6pcm->in.lock, flags); | ||
77 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | 76 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { |
78 | ret = submit_audio_in_urb(line6pcm); | 77 | ret = submit_audio_in_urb(line6pcm); |
79 | if (ret < 0) | 78 | if (ret < 0) |
80 | break; | 79 | break; |
81 | } | 80 | } |
82 | 81 | ||
83 | spin_unlock_irqrestore(&line6pcm->in.lock, flags); | ||
84 | return ret; | 82 | return ret; |
85 | } | 83 | } |
86 | 84 | ||
@@ -187,10 +185,10 @@ static void audio_in_callback(struct urb *urb) | |||
187 | line6pcm->prev_fbuf = fbuf; | 185 | line6pcm->prev_fbuf = fbuf; |
188 | line6pcm->prev_fsize = fsize; | 186 | line6pcm->prev_fsize = fsize; |
189 | 187 | ||
190 | if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) | 188 | if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && |
191 | if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, | 189 | test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) && |
192 | &line6pcm->flags) && (fsize > 0)) | 190 | fsize > 0) |
193 | line6_capture_copy(line6pcm, fbuf, fsize); | 191 | line6_capture_copy(line6pcm, fbuf, fsize); |
194 | } | 192 | } |
195 | 193 | ||
196 | clear_bit(index, &line6pcm->in.active_urbs); | 194 | clear_bit(index, &line6pcm->in.active_urbs); |
@@ -201,10 +199,9 @@ static void audio_in_callback(struct urb *urb) | |||
201 | if (!shutdown) { | 199 | if (!shutdown) { |
202 | submit_audio_in_urb(line6pcm); | 200 | submit_audio_in_urb(line6pcm); |
203 | 201 | ||
204 | if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) | 202 | if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && |
205 | if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, | 203 | test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) |
206 | &line6pcm->flags)) | 204 | line6_capture_check_period(line6pcm, length); |
207 | line6_capture_check_period(line6pcm, length); | ||
208 | } | 205 | } |
209 | 206 | ||
210 | spin_unlock_irqrestore(&line6pcm->in.lock, flags); | 207 | spin_unlock_irqrestore(&line6pcm->in.lock, flags); |
@@ -234,71 +231,6 @@ static int snd_line6_capture_close(struct snd_pcm_substream *substream) | |||
234 | return 0; | 231 | return 0; |
235 | } | 232 | } |
236 | 233 | ||
237 | /* hw_params capture callback */ | ||
238 | static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, | ||
239 | struct snd_pcm_hw_params *hw_params) | ||
240 | { | ||
241 | int ret; | ||
242 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
243 | |||
244 | ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); | ||
245 | |||
246 | if (ret < 0) | ||
247 | return ret; | ||
248 | |||
249 | ret = snd_pcm_lib_malloc_pages(substream, | ||
250 | params_buffer_bytes(hw_params)); | ||
251 | if (ret < 0) { | ||
252 | line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | line6pcm->in.period = params_period_bytes(hw_params); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* hw_free capture callback */ | ||
261 | static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) | ||
262 | { | ||
263 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
264 | |||
265 | line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); | ||
266 | return snd_pcm_lib_free_pages(substream); | ||
267 | } | ||
268 | |||
269 | /* trigger callback */ | ||
270 | int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) | ||
271 | { | ||
272 | int err; | ||
273 | |||
274 | switch (cmd) { | ||
275 | case SNDRV_PCM_TRIGGER_START: | ||
276 | case SNDRV_PCM_TRIGGER_RESUME: | ||
277 | err = line6_pcm_acquire(line6pcm, | ||
278 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); | ||
279 | |||
280 | if (err < 0) | ||
281 | return err; | ||
282 | |||
283 | break; | ||
284 | |||
285 | case SNDRV_PCM_TRIGGER_STOP: | ||
286 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
287 | err = line6_pcm_release(line6pcm, | ||
288 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); | ||
289 | |||
290 | if (err < 0) | ||
291 | return err; | ||
292 | |||
293 | break; | ||
294 | |||
295 | default: | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* capture pointer callback */ | 234 | /* capture pointer callback */ |
303 | static snd_pcm_uframes_t | 235 | static snd_pcm_uframes_t |
304 | snd_line6_capture_pointer(struct snd_pcm_substream *substream) | 236 | snd_line6_capture_pointer(struct snd_pcm_substream *substream) |
@@ -313,8 +245,8 @@ struct snd_pcm_ops snd_line6_capture_ops = { | |||
313 | .open = snd_line6_capture_open, | 245 | .open = snd_line6_capture_open, |
314 | .close = snd_line6_capture_close, | 246 | .close = snd_line6_capture_close, |
315 | .ioctl = snd_pcm_lib_ioctl, | 247 | .ioctl = snd_pcm_lib_ioctl, |
316 | .hw_params = snd_line6_capture_hw_params, | 248 | .hw_params = snd_line6_hw_params, |
317 | .hw_free = snd_line6_capture_hw_free, | 249 | .hw_free = snd_line6_hw_free, |
318 | .prepare = snd_line6_prepare, | 250 | .prepare = snd_line6_prepare, |
319 | .trigger = snd_line6_trigger, | 251 | .trigger = snd_line6_trigger, |
320 | .pointer = snd_line6_capture_pointer, | 252 | .pointer = snd_line6_capture_pointer, |
diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h index db062e7200a6..890b21bff18c 100644 --- a/sound/usb/line6/capture.h +++ b/sound/usb/line6/capture.h | |||
@@ -25,6 +25,5 @@ extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, | |||
25 | int length); | 25 | int length); |
26 | extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); | 26 | extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); |
27 | extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); | 27 | extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); |
28 | extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd); | ||
29 | 28 | ||
30 | #endif | 29 | #endif |
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c index dedbe24cbf60..470fc1049d54 100644 --- a/sound/usb/line6/pcm.c +++ b/sound/usb/line6/pcm.c | |||
@@ -51,9 +51,9 @@ static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, | |||
51 | 51 | ||
52 | line6pcm->impulse_volume = value; | 52 | line6pcm->impulse_volume = value; |
53 | if (value > 0) | 53 | if (value > 0) |
54 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); | 54 | line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); |
55 | else | 55 | else |
56 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); | 56 | line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); |
57 | return 1; | 57 | return 1; |
58 | } | 58 | } |
59 | 59 | ||
@@ -132,176 +132,226 @@ static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, | |||
132 | "timeout: still %d active urbs..\n", alive); | 132 | "timeout: still %d active urbs..\n", alive); |
133 | } | 133 | } |
134 | 134 | ||
135 | static int line6_alloc_stream_buffer(struct snd_line6_pcm *line6pcm, | 135 | static inline struct line6_pcm_stream * |
136 | struct line6_pcm_stream *pcms) | 136 | get_stream(struct snd_line6_pcm *line6pcm, int direction) |
137 | { | 137 | { |
138 | /* Invoked multiple times in a row so allocate once only */ | 138 | return (direction == SNDRV_PCM_STREAM_PLAYBACK) ? |
139 | if (pcms->buffer) | 139 | &line6pcm->out : &line6pcm->in; |
140 | return 0; | ||
141 | |||
142 | pcms->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | ||
143 | line6pcm->max_packet_size, GFP_KERNEL); | ||
144 | if (!pcms->buffer) | ||
145 | return -ENOMEM; | ||
146 | return 0; | ||
147 | } | 140 | } |
148 | 141 | ||
149 | static void line6_free_stream_buffer(struct snd_line6_pcm *line6pcm, | 142 | /* allocate a buffer if not opened yet; |
150 | struct line6_pcm_stream *pcms) | 143 | * call this in line6pcm.state_change mutex |
144 | */ | ||
145 | static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm, | ||
146 | struct line6_pcm_stream *pstr, int type) | ||
151 | { | 147 | { |
152 | kfree(pcms->buffer); | 148 | /* Invoked multiple times in a row so allocate once only */ |
153 | pcms->buffer = NULL; | 149 | if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) { |
150 | pstr->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | ||
151 | line6pcm->max_packet_size, GFP_KERNEL); | ||
152 | if (!pstr->buffer) | ||
153 | return -ENOMEM; | ||
154 | } | ||
155 | return 0; | ||
154 | } | 156 | } |
155 | 157 | ||
156 | static bool test_flags(unsigned long flags0, unsigned long flags1, | 158 | /* free a buffer if all streams are closed; |
157 | unsigned long mask) | 159 | * call this in line6pcm.state_change mutex |
160 | */ | ||
161 | static void line6_buffer_release(struct snd_line6_pcm *line6pcm, | ||
162 | struct line6_pcm_stream *pstr, int type) | ||
158 | { | 163 | { |
159 | return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); | 164 | |
165 | clear_bit(type, &pstr->opened); | ||
166 | if (!pstr->opened) { | ||
167 | line6_wait_clear_audio_urbs(line6pcm, pstr); | ||
168 | kfree(pstr->buffer); | ||
169 | pstr->buffer = NULL; | ||
170 | } | ||
160 | } | 171 | } |
161 | 172 | ||
162 | int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) | 173 | /* start a PCM stream */ |
174 | static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, | ||
175 | int type) | ||
163 | { | 176 | { |
164 | unsigned long flags_old, flags_new, flags_final; | 177 | unsigned long flags; |
165 | int err; | 178 | struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); |
166 | 179 | int ret = 0; | |
167 | do { | 180 | |
168 | flags_old = ACCESS_ONCE(line6pcm->flags); | 181 | spin_lock_irqsave(&pstr->lock, flags); |
169 | flags_new = flags_old | channels; | 182 | if (!test_and_set_bit(type, &pstr->running)) { |
170 | } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); | 183 | if (pstr->active_urbs || pstr->unlink_urbs) { |
171 | 184 | ret = -EBUSY; | |
172 | flags_final = 0; | 185 | goto error; |
186 | } | ||
173 | 187 | ||
174 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { | 188 | pstr->count = 0; |
175 | err = line6_alloc_stream_buffer(line6pcm, &line6pcm->in); | 189 | /* Submit all currently available URBs */ |
176 | if (err < 0) | 190 | if (direction == SNDRV_PCM_STREAM_PLAYBACK) |
177 | goto pcm_acquire_error; | 191 | ret = line6_submit_audio_out_all_urbs(line6pcm); |
178 | flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; | 192 | else |
193 | ret = line6_submit_audio_in_all_urbs(line6pcm); | ||
179 | } | 194 | } |
195 | error: | ||
196 | if (ret < 0) | ||
197 | clear_bit(type, &pstr->running); | ||
198 | spin_unlock_irqrestore(&pstr->lock, flags); | ||
199 | return ret; | ||
200 | } | ||
180 | 201 | ||
181 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { | 202 | /* stop a PCM stream; this doesn't sync with the unlinked URBs */ |
182 | /* | 203 | static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction, |
183 | Waiting for completion of active URBs in the stop handler is | 204 | int type) |
184 | a bug, we therefore report an error if capturing is restarted | 205 | { |
185 | too soon. | 206 | unsigned long flags; |
186 | */ | 207 | struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); |
187 | if (line6pcm->in.active_urbs || line6pcm->in.unlink_urbs) { | 208 | |
188 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); | 209 | spin_lock_irqsave(&pstr->lock, flags); |
189 | err = -EBUSY; | 210 | clear_bit(type, &pstr->running); |
190 | goto pcm_acquire_error; | 211 | if (!pstr->running) { |
212 | line6_unlink_audio_urbs(line6pcm, pstr); | ||
213 | if (direction == SNDRV_PCM_STREAM_CAPTURE) { | ||
214 | line6pcm->prev_fbuf = NULL; | ||
215 | line6pcm->prev_fsize = 0; | ||
191 | } | 216 | } |
217 | } | ||
218 | spin_unlock_irqrestore(&pstr->lock, flags); | ||
219 | } | ||
192 | 220 | ||
193 | line6pcm->in.count = 0; | 221 | /* common PCM trigger callback */ |
194 | err = line6_submit_audio_in_all_urbs(line6pcm); | 222 | int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) |
223 | { | ||
224 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
225 | struct snd_pcm_substream *s; | ||
226 | int err; | ||
195 | 227 | ||
196 | if (err < 0) | 228 | clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags); |
197 | goto pcm_acquire_error; | ||
198 | 229 | ||
199 | flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; | 230 | snd_pcm_group_for_each_entry(s, substream) { |
200 | } | 231 | if (s->pcm->card != substream->pcm->card) |
232 | continue; | ||
201 | 233 | ||
202 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { | 234 | switch (cmd) { |
203 | err = line6_alloc_stream_buffer(line6pcm, &line6pcm->out); | 235 | case SNDRV_PCM_TRIGGER_START: |
204 | if (err < 0) | 236 | case SNDRV_PCM_TRIGGER_RESUME: |
205 | goto pcm_acquire_error; | 237 | err = line6_stream_start(line6pcm, s->stream, |
206 | flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; | 238 | LINE6_STREAM_PCM); |
207 | } | 239 | if (err < 0) |
240 | return err; | ||
241 | break; | ||
208 | 242 | ||
209 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { | 243 | case SNDRV_PCM_TRIGGER_STOP: |
210 | /* | 244 | case SNDRV_PCM_TRIGGER_SUSPEND: |
211 | See comment above regarding PCM restart. | 245 | line6_stream_stop(line6pcm, s->stream, |
212 | */ | 246 | LINE6_STREAM_PCM); |
213 | if (line6pcm->out.active_urbs || line6pcm->out.unlink_urbs) { | 247 | break; |
214 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); | ||
215 | return -EBUSY; | ||
216 | } | ||
217 | 248 | ||
218 | line6pcm->out.count = 0; | 249 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
219 | err = line6_submit_audio_out_all_urbs(line6pcm); | 250 | if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) |
251 | return -EINVAL; | ||
252 | set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); | ||
253 | break; | ||
220 | 254 | ||
221 | if (err < 0) | 255 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
222 | goto pcm_acquire_error; | 256 | if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) |
257 | return -EINVAL; | ||
258 | clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); | ||
259 | break; | ||
223 | 260 | ||
224 | flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; | 261 | default: |
262 | return -EINVAL; | ||
263 | } | ||
225 | } | 264 | } |
226 | 265 | ||
227 | return 0; | 266 | return 0; |
228 | |||
229 | pcm_acquire_error: | ||
230 | /* | ||
231 | If not all requested resources/streams could be obtained, release | ||
232 | those which were successfully obtained (if any). | ||
233 | */ | ||
234 | line6_pcm_release(line6pcm, flags_final); | ||
235 | return err; | ||
236 | } | 267 | } |
237 | EXPORT_SYMBOL_GPL(line6_pcm_acquire); | ||
238 | 268 | ||
239 | int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) | 269 | /* Acquire and start duplex streams: |
270 | * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR | ||
271 | */ | ||
272 | int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type) | ||
240 | { | 273 | { |
241 | unsigned long flags_old, flags_new; | 274 | struct line6_pcm_stream *pstr; |
242 | 275 | int ret = 0, dir; | |
243 | do { | 276 | |
244 | flags_old = ACCESS_ONCE(line6pcm->flags); | 277 | mutex_lock(&line6pcm->state_mutex); |
245 | flags_new = flags_old & ~channels; | 278 | for (dir = 0; dir < 2; dir++) { |
246 | } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); | 279 | pstr = get_stream(line6pcm, dir); |
247 | 280 | ret = line6_buffer_acquire(line6pcm, pstr, type); | |
248 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) { | 281 | if (ret < 0) |
249 | line6_unlink_audio_urbs(line6pcm, &line6pcm->in); | 282 | goto error; |
250 | line6pcm->prev_fbuf = NULL; | 283 | if (!pstr->running) |
251 | line6pcm->prev_fsize = 0; | 284 | line6_wait_clear_audio_urbs(line6pcm, pstr); |
252 | } | 285 | } |
253 | 286 | for (dir = 0; dir < 2; dir++) { | |
254 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { | 287 | ret = line6_stream_start(line6pcm, dir, type); |
255 | line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); | 288 | if (ret < 0) |
256 | line6_free_stream_buffer(line6pcm, &line6pcm->in); | 289 | goto error; |
257 | } | 290 | } |
291 | error: | ||
292 | mutex_unlock(&line6pcm->state_mutex); | ||
293 | if (ret < 0) | ||
294 | line6_pcm_release(line6pcm, type); | ||
295 | return ret; | ||
296 | } | ||
297 | EXPORT_SYMBOL_GPL(line6_pcm_acquire); | ||
258 | 298 | ||
259 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) | 299 | /* Stop and release duplex streams */ |
260 | line6_unlink_audio_urbs(line6pcm, &line6pcm->out); | 300 | void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) |
261 | 301 | { | |
262 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { | 302 | struct line6_pcm_stream *pstr; |
263 | line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); | 303 | int dir; |
264 | line6_free_stream_buffer(line6pcm, &line6pcm->out); | 304 | |
305 | mutex_lock(&line6pcm->state_mutex); | ||
306 | for (dir = 0; dir < 2; dir++) | ||
307 | line6_stream_stop(line6pcm, dir, type); | ||
308 | for (dir = 0; dir < 2; dir++) { | ||
309 | pstr = get_stream(line6pcm, dir); | ||
310 | line6_buffer_release(line6pcm, pstr, type); | ||
265 | } | 311 | } |
266 | 312 | mutex_unlock(&line6pcm->state_mutex); | |
267 | return 0; | ||
268 | } | 313 | } |
269 | EXPORT_SYMBOL_GPL(line6_pcm_release); | 314 | EXPORT_SYMBOL_GPL(line6_pcm_release); |
270 | 315 | ||
271 | /* trigger callback */ | 316 | /* common PCM hw_params callback */ |
272 | int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) | 317 | int snd_line6_hw_params(struct snd_pcm_substream *substream, |
318 | struct snd_pcm_hw_params *hw_params) | ||
273 | { | 319 | { |
320 | int ret; | ||
274 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 321 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
275 | struct snd_pcm_substream *s; | 322 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); |
276 | int err = 0; | 323 | |
277 | 324 | mutex_lock(&line6pcm->state_mutex); | |
278 | clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); | 325 | ret = line6_buffer_acquire(line6pcm, pstr, LINE6_STREAM_PCM); |
279 | 326 | if (ret < 0) | |
280 | snd_pcm_group_for_each_entry(s, substream) { | 327 | goto error; |
281 | if (s->pcm->card != substream->pcm->card) | 328 | |
282 | continue; | 329 | ret = snd_pcm_lib_malloc_pages(substream, |
283 | switch (s->stream) { | 330 | params_buffer_bytes(hw_params)); |
284 | case SNDRV_PCM_STREAM_PLAYBACK: | 331 | if (ret < 0) { |
285 | err = snd_line6_playback_trigger(line6pcm, cmd); | 332 | line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); |
286 | break; | 333 | goto error; |
334 | } | ||
287 | 335 | ||
288 | case SNDRV_PCM_STREAM_CAPTURE: | 336 | pstr->period = params_period_bytes(hw_params); |
289 | err = snd_line6_capture_trigger(line6pcm, cmd); | 337 | error: |
290 | break; | 338 | mutex_unlock(&line6pcm->state_mutex); |
339 | return ret; | ||
340 | } | ||
291 | 341 | ||
292 | default: | 342 | /* common PCM hw_free callback */ |
293 | dev_err(line6pcm->line6->ifcdev, | 343 | int snd_line6_hw_free(struct snd_pcm_substream *substream) |
294 | "Unknown stream direction %d\n", s->stream); | 344 | { |
295 | err = -EINVAL; | 345 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
296 | break; | 346 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); |
297 | } | ||
298 | if (err < 0) | ||
299 | break; | ||
300 | } | ||
301 | 347 | ||
302 | return err; | 348 | mutex_lock(&line6pcm->state_mutex); |
349 | line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); | ||
350 | mutex_unlock(&line6pcm->state_mutex); | ||
351 | return snd_pcm_lib_free_pages(substream); | ||
303 | } | 352 | } |
304 | 353 | ||
354 | |||
305 | /* control info callback */ | 355 | /* control info callback */ |
306 | static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, | 356 | static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, |
307 | struct snd_ctl_elem_info *uinfo) | 357 | struct snd_ctl_elem_info *uinfo) |
@@ -454,6 +504,7 @@ int line6_init_pcm(struct usb_line6 *line6, | |||
454 | if (!line6pcm) | 504 | if (!line6pcm) |
455 | return -ENOMEM; | 505 | return -ENOMEM; |
456 | 506 | ||
507 | mutex_init(&line6pcm->state_mutex); | ||
457 | line6pcm->pcm = pcm; | 508 | line6pcm->pcm = pcm; |
458 | line6pcm->properties = properties; | 509 | line6pcm->properties = properties; |
459 | line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; | 510 | line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; |
@@ -500,24 +551,13 @@ EXPORT_SYMBOL_GPL(line6_init_pcm); | |||
500 | int snd_line6_prepare(struct snd_pcm_substream *substream) | 551 | int snd_line6_prepare(struct snd_pcm_substream *substream) |
501 | { | 552 | { |
502 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 553 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
554 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | ||
503 | 555 | ||
504 | switch (substream->stream) { | 556 | mutex_lock(&line6pcm->state_mutex); |
505 | case SNDRV_PCM_STREAM_PLAYBACK: | 557 | if (!pstr->running) |
506 | if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) { | 558 | line6_wait_clear_audio_urbs(line6pcm, pstr); |
507 | line6_unlink_audio_urbs(line6pcm, &line6pcm->out); | ||
508 | line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); | ||
509 | } | ||
510 | break; | ||
511 | |||
512 | case SNDRV_PCM_STREAM_CAPTURE: | ||
513 | if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) { | ||
514 | line6_unlink_audio_urbs(line6pcm, &line6pcm->in); | ||
515 | line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); | ||
516 | } | ||
517 | break; | ||
518 | } | ||
519 | 559 | ||
520 | if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { | 560 | if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) { |
521 | line6pcm->out.count = 0; | 561 | line6pcm->out.count = 0; |
522 | line6pcm->out.pos = 0; | 562 | line6pcm->out.pos = 0; |
523 | line6pcm->out.pos_done = 0; | 563 | line6pcm->out.pos_done = 0; |
@@ -527,5 +567,6 @@ int snd_line6_prepare(struct snd_pcm_substream *substream) | |||
527 | line6pcm->in.bytes = 0; | 567 | line6pcm->in.bytes = 0; |
528 | } | 568 | } |
529 | 569 | ||
570 | mutex_unlock(&line6pcm->state_mutex); | ||
530 | return 0; | 571 | return 0; |
531 | } | 572 | } |
diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h index 4c74f4e85074..66f603dfa34e 100644 --- a/sound/usb/line6/pcm.h +++ b/sound/usb/line6/pcm.h | |||
@@ -54,109 +54,33 @@ | |||
54 | However, from the device's point of view, there is just a single | 54 | However, from the device's point of view, there is just a single |
55 | capture and playback stream, which must be shared between these | 55 | capture and playback stream, which must be shared between these |
56 | subsystems. It is therefore necessary to maintain the state of the | 56 | subsystems. It is therefore necessary to maintain the state of the |
57 | subsystems with respect to PCM usage. We define several constants of | 57 | subsystems with respect to PCM usage. |
58 | the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the | 58 | |
59 | following meanings: | 59 | We define two bit flags, "opened" and "running", for each playback |
60 | *) <subsystem> is one of | 60 | or capture stream. Both can contain the bit flag corresponding to |
61 | -) ALSA: PCM playback and capture via ALSA | 61 | LINE6_STREAM_* type, |
62 | -) MONITOR: software monitoring | 62 | LINE6_STREAM_PCM = ALSA PCM playback or capture |
63 | -) IMPULSE: optional impulse response measurement | 63 | LINE6_STREAM_MONITOR = software monitoring |
64 | *) <direction> is one of | 64 | IMPULSE = optional impulse response measurement |
65 | -) PLAYBACK: audio output (from host to device) | 65 | The opened flag indicates whether the buffer is allocated while |
66 | -) CAPTURE: audio input (from device to host) | 66 | the running flag indicates whether the stream is running. |
67 | *) <resource> is one of | 67 | |
68 | -) BUFFER: buffer required by PCM data stream | 68 | For monitor or impulse operations, the driver needs to call |
69 | -) STREAM: actual PCM data stream | 69 | snd_line6_duplex_acquire() or snd_line6_duplex_release() with the |
70 | 70 | appropriate LINE6_STREAM_* flag. | |
71 | The subsystems call line6_pcm_acquire() to acquire the (shared) | ||
72 | resources needed for a particular operation (e.g., allocate the buffer | ||
73 | for ALSA playback or start the capture stream for software monitoring). | ||
74 | When a resource is no longer needed, it is released by calling | ||
75 | line6_pcm_release(). Buffer allocation and stream startup are handled | ||
76 | separately to allow the ALSA kernel driver to perform them at | ||
77 | appropriate places (since the callback which starts a PCM stream is not | ||
78 | allowed to sleep). | ||
79 | */ | 71 | */ |
72 | |||
73 | /* stream types */ | ||
74 | enum { | ||
75 | LINE6_STREAM_PCM, | ||
76 | LINE6_STREAM_MONITOR, | ||
77 | LINE6_STREAM_IMPULSE, | ||
78 | }; | ||
79 | |||
80 | /* misc bit flags for PCM operation */ | ||
80 | enum { | 81 | enum { |
81 | /* individual bit indices: */ | 82 | LINE6_FLAG_PAUSE_PLAYBACK, |
82 | LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER, | 83 | LINE6_FLAG_PREPARED, |
83 | LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, | ||
84 | LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER, | ||
85 | LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, | ||
86 | LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER, | ||
87 | LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM, | ||
88 | LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER, | ||
89 | LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM, | ||
90 | LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER, | ||
91 | LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM, | ||
92 | LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER, | ||
93 | LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM, | ||
94 | LINE6_INDEX_PAUSE_PLAYBACK, | ||
95 | LINE6_INDEX_PREPARED, | ||
96 | |||
97 | #define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x | ||
98 | |||
99 | /* individual bit masks: */ | ||
100 | LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER), | ||
101 | LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM), | ||
102 | LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER), | ||
103 | LINE6_BIT(PCM_ALSA_CAPTURE_STREAM), | ||
104 | LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER), | ||
105 | LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM), | ||
106 | LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER), | ||
107 | LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM), | ||
108 | LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER), | ||
109 | LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM), | ||
110 | LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER), | ||
111 | LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM), | ||
112 | LINE6_BIT(PAUSE_PLAYBACK), | ||
113 | LINE6_BIT(PREPARED), | ||
114 | |||
115 | /* combined bit masks (by operation): */ | ||
116 | LINE6_BITS_PCM_ALSA_BUFFER = | ||
117 | LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | | ||
118 | LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER, | ||
119 | |||
120 | LINE6_BITS_PCM_ALSA_STREAM = | ||
121 | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | | ||
122 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM, | ||
123 | |||
124 | LINE6_BITS_PCM_MONITOR = | ||
125 | LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER | | ||
126 | LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM | | ||
127 | LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER | | ||
128 | LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, | ||
129 | |||
130 | LINE6_BITS_PCM_IMPULSE = | ||
131 | LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | | ||
132 | LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | | ||
133 | LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | | ||
134 | LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM, | ||
135 | |||
136 | /* combined bit masks (by direction): */ | ||
137 | LINE6_BITS_PLAYBACK_BUFFER = | ||
138 | LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | | ||
139 | LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | | ||
140 | LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER, | ||
141 | |||
142 | LINE6_BITS_PLAYBACK_STREAM = | ||
143 | LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | | ||
144 | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | | ||
145 | LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM, | ||
146 | |||
147 | LINE6_BITS_CAPTURE_BUFFER = | ||
148 | LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | | ||
149 | LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | | ||
150 | LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER, | ||
151 | |||
152 | LINE6_BITS_CAPTURE_STREAM = | ||
153 | LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM | | ||
154 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM | | ||
155 | LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, | ||
156 | |||
157 | LINE6_BITS_STREAM = | ||
158 | LINE6_BITS_PLAYBACK_STREAM | | ||
159 | LINE6_BITS_CAPTURE_STREAM | ||
160 | }; | 84 | }; |
161 | 85 | ||
162 | struct line6_pcm_properties { | 86 | struct line6_pcm_properties { |
@@ -205,6 +129,12 @@ struct line6_pcm_stream { | |||
205 | */ | 129 | */ |
206 | spinlock_t lock; | 130 | spinlock_t lock; |
207 | 131 | ||
132 | /* Bit flags for operational stream types */ | ||
133 | unsigned long opened; | ||
134 | |||
135 | /* Bit flags for running stream types */ | ||
136 | unsigned long running; | ||
137 | |||
208 | int last_frame; | 138 | int last_frame; |
209 | }; | 139 | }; |
210 | 140 | ||
@@ -224,6 +154,9 @@ struct snd_line6_pcm { | |||
224 | */ | 154 | */ |
225 | struct snd_pcm *pcm; | 155 | struct snd_pcm *pcm; |
226 | 156 | ||
157 | /* protection to state changes of in/out streams */ | ||
158 | struct mutex state_mutex; | ||
159 | |||
227 | /* Capture and playback streams */ | 160 | /* Capture and playback streams */ |
228 | struct line6_pcm_stream in; | 161 | struct line6_pcm_stream in; |
229 | struct line6_pcm_stream out; | 162 | struct line6_pcm_stream out; |
@@ -269,7 +202,7 @@ struct snd_line6_pcm { | |||
269 | int impulse_count; | 202 | int impulse_count; |
270 | 203 | ||
271 | /** | 204 | /** |
272 | Several status bits (see LINE6_BIT_*). | 205 | Several status bits (see LINE6_FLAG_*). |
273 | */ | 206 | */ |
274 | unsigned long flags; | 207 | unsigned long flags; |
275 | }; | 208 | }; |
@@ -278,8 +211,11 @@ extern int line6_init_pcm(struct usb_line6 *line6, | |||
278 | struct line6_pcm_properties *properties); | 211 | struct line6_pcm_properties *properties); |
279 | extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); | 212 | extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); |
280 | extern int snd_line6_prepare(struct snd_pcm_substream *substream); | 213 | extern int snd_line6_prepare(struct snd_pcm_substream *substream); |
214 | extern int snd_line6_hw_params(struct snd_pcm_substream *substream, | ||
215 | struct snd_pcm_hw_params *hw_params); | ||
216 | extern int snd_line6_hw_free(struct snd_pcm_substream *substream); | ||
281 | extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); | 217 | extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); |
282 | extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels); | 218 | extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type); |
283 | extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels); | 219 | extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type); |
284 | 220 | ||
285 | #endif | 221 | #endif |
diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 242265929145..f8b04e2d36b3 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c | |||
@@ -194,8 +194,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) | |||
194 | urb_out->transfer_buffer_length = urb_size; | 194 | urb_out->transfer_buffer_length = urb_size; |
195 | urb_out->context = line6pcm; | 195 | urb_out->context = line6pcm; |
196 | 196 | ||
197 | if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) && | 197 | if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running) && |
198 | !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) { | 198 | !test_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags)) { |
199 | struct snd_pcm_runtime *runtime = | 199 | struct snd_pcm_runtime *runtime = |
200 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; | 200 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; |
201 | 201 | ||
@@ -239,11 +239,10 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) | |||
239 | 239 | ||
240 | spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING); | 240 | spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING); |
241 | if (line6pcm->prev_fbuf) { | 241 | if (line6pcm->prev_fbuf) { |
242 | if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { | 242 | if (test_bit(LINE6_STREAM_IMPULSE, &line6pcm->out.running)) { |
243 | create_impulse_test_signal(line6pcm, urb_out, | 243 | create_impulse_test_signal(line6pcm, urb_out, |
244 | bytes_per_frame); | 244 | bytes_per_frame); |
245 | if (line6pcm->flags & | 245 | if (test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) { |
246 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) { | ||
247 | line6_capture_copy(line6pcm, | 246 | line6_capture_copy(line6pcm, |
248 | urb_out->transfer_buffer, | 247 | urb_out->transfer_buffer, |
249 | urb_out-> | 248 | urb_out-> |
@@ -252,11 +251,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) | |||
252 | urb_out->transfer_buffer_length); | 251 | urb_out->transfer_buffer_length); |
253 | } | 252 | } |
254 | } else { | 253 | } else { |
255 | if (! | 254 | if (!(line6pcm->line6->properties->capabilities & LINE6_CAP_HWMON) |
256 | (line6pcm->line6-> | 255 | && line6pcm->out.running && line6pcm->in.running) |
257 | properties->capabilities & LINE6_CAP_HWMON) | ||
258 | && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) | ||
259 | && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)) | ||
260 | add_monitor_signal(urb_out, line6pcm->prev_fbuf, | 256 | add_monitor_signal(urb_out, line6pcm->prev_fbuf, |
261 | line6pcm->volume_monitor, | 257 | line6pcm->volume_monitor, |
262 | bytes_per_frame); | 258 | bytes_per_frame); |
@@ -279,20 +275,18 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) | |||
279 | 275 | ||
280 | /* | 276 | /* |
281 | Submit all currently available playback URBs. | 277 | Submit all currently available playback URBs. |
282 | */ | 278 | must be called in line6pcm->out.lock context |
279 | */ | ||
283 | int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) | 280 | int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) |
284 | { | 281 | { |
285 | unsigned long flags; | ||
286 | int ret = 0, i; | 282 | int ret = 0, i; |
287 | 283 | ||
288 | spin_lock_irqsave(&line6pcm->out.lock, flags); | ||
289 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | 284 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { |
290 | ret = submit_audio_out_urb(line6pcm); | 285 | ret = submit_audio_out_urb(line6pcm); |
291 | if (ret < 0) | 286 | if (ret < 0) |
292 | break; | 287 | break; |
293 | } | 288 | } |
294 | 289 | ||
295 | spin_unlock_irqrestore(&line6pcm->out.lock, flags); | ||
296 | return ret; | 290 | return ret; |
297 | } | 291 | } |
298 | 292 | ||
@@ -326,7 +320,7 @@ static void audio_out_callback(struct urb *urb) | |||
326 | 320 | ||
327 | spin_lock_irqsave(&line6pcm->out.lock, flags); | 321 | spin_lock_irqsave(&line6pcm->out.lock, flags); |
328 | 322 | ||
329 | if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) { | 323 | if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { |
330 | struct snd_pcm_runtime *runtime = substream->runtime; | 324 | struct snd_pcm_runtime *runtime = substream->runtime; |
331 | 325 | ||
332 | line6pcm->out.pos_done += | 326 | line6pcm->out.pos_done += |
@@ -350,8 +344,7 @@ static void audio_out_callback(struct urb *urb) | |||
350 | if (!shutdown) { | 344 | if (!shutdown) { |
351 | submit_audio_out_urb(line6pcm); | 345 | submit_audio_out_urb(line6pcm); |
352 | 346 | ||
353 | if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, | 347 | if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { |
354 | &line6pcm->flags)) { | ||
355 | line6pcm->out.bytes += length; | 348 | line6pcm->out.bytes += length; |
356 | if (line6pcm->out.bytes >= line6pcm->out.period) { | 349 | if (line6pcm->out.bytes >= line6pcm->out.period) { |
357 | line6pcm->out.bytes %= line6pcm->out.period; | 350 | line6pcm->out.bytes %= line6pcm->out.period; |
@@ -387,79 +380,6 @@ static int snd_line6_playback_close(struct snd_pcm_substream *substream) | |||
387 | return 0; | 380 | return 0; |
388 | } | 381 | } |
389 | 382 | ||
390 | /* hw_params playback callback */ | ||
391 | static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, | ||
392 | struct snd_pcm_hw_params *hw_params) | ||
393 | { | ||
394 | int ret; | ||
395 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
396 | |||
397 | ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); | ||
398 | |||
399 | if (ret < 0) | ||
400 | return ret; | ||
401 | |||
402 | ret = snd_pcm_lib_malloc_pages(substream, | ||
403 | params_buffer_bytes(hw_params)); | ||
404 | if (ret < 0) { | ||
405 | line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | line6pcm->out.period = params_period_bytes(hw_params); | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | /* hw_free playback callback */ | ||
414 | static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream) | ||
415 | { | ||
416 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
417 | |||
418 | line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); | ||
419 | return snd_pcm_lib_free_pages(substream); | ||
420 | } | ||
421 | |||
422 | /* trigger playback callback */ | ||
423 | int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) | ||
424 | { | ||
425 | int err; | ||
426 | |||
427 | switch (cmd) { | ||
428 | case SNDRV_PCM_TRIGGER_START: | ||
429 | case SNDRV_PCM_TRIGGER_RESUME: | ||
430 | err = line6_pcm_acquire(line6pcm, | ||
431 | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); | ||
432 | |||
433 | if (err < 0) | ||
434 | return err; | ||
435 | |||
436 | break; | ||
437 | |||
438 | case SNDRV_PCM_TRIGGER_STOP: | ||
439 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
440 | err = line6_pcm_release(line6pcm, | ||
441 | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); | ||
442 | |||
443 | if (err < 0) | ||
444 | return err; | ||
445 | |||
446 | break; | ||
447 | |||
448 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
449 | set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); | ||
450 | break; | ||
451 | |||
452 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
453 | clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); | ||
454 | break; | ||
455 | |||
456 | default: | ||
457 | return -EINVAL; | ||
458 | } | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | /* playback pointer callback */ | 383 | /* playback pointer callback */ |
464 | static snd_pcm_uframes_t | 384 | static snd_pcm_uframes_t |
465 | snd_line6_playback_pointer(struct snd_pcm_substream *substream) | 385 | snd_line6_playback_pointer(struct snd_pcm_substream *substream) |
@@ -474,8 +394,8 @@ struct snd_pcm_ops snd_line6_playback_ops = { | |||
474 | .open = snd_line6_playback_open, | 394 | .open = snd_line6_playback_open, |
475 | .close = snd_line6_playback_close, | 395 | .close = snd_line6_playback_close, |
476 | .ioctl = snd_pcm_lib_ioctl, | 396 | .ioctl = snd_pcm_lib_ioctl, |
477 | .hw_params = snd_line6_playback_hw_params, | 397 | .hw_params = snd_line6_hw_params, |
478 | .hw_free = snd_line6_playback_hw_free, | 398 | .hw_free = snd_line6_hw_free, |
479 | .prepare = snd_line6_prepare, | 399 | .prepare = snd_line6_prepare, |
480 | .trigger = snd_line6_trigger, | 400 | .trigger = snd_line6_trigger, |
481 | .pointer = snd_line6_playback_pointer, | 401 | .pointer = snd_line6_playback_pointer, |
diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h index f6a9e18f87b6..51fce29e8726 100644 --- a/sound/usb/line6/playback.h +++ b/sound/usb/line6/playback.h | |||
@@ -31,6 +31,5 @@ extern struct snd_pcm_ops snd_line6_playback_ops; | |||
31 | 31 | ||
32 | extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); | 32 | extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); |
33 | extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); | 33 | extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); |
34 | extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd); | ||
35 | 34 | ||
36 | #endif | 35 | #endif |
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index 33d16ecf18a0..61fa6256d7b0 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c | |||
@@ -189,9 +189,9 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, | |||
189 | line6pcm->volume_monitor = ucontrol->value.integer.value[0]; | 189 | line6pcm->volume_monitor = ucontrol->value.integer.value[0]; |
190 | 190 | ||
191 | if (line6pcm->volume_monitor > 0) | 191 | if (line6pcm->volume_monitor > 0) |
192 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR); | 192 | line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR); |
193 | else | 193 | else |
194 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); | 194 | line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); |
195 | 195 | ||
196 | return 1; | 196 | return 1; |
197 | } | 197 | } |
@@ -252,7 +252,7 @@ static void toneport_start_pcm(unsigned long arg) | |||
252 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; | 252 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; |
253 | struct usb_line6 *line6 = &toneport->line6; | 253 | struct usb_line6 *line6 = &toneport->line6; |
254 | 254 | ||
255 | line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR); | 255 | line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR); |
256 | } | 256 | } |
257 | 257 | ||
258 | /* control definition */ | 258 | /* control definition */ |