int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) { unsigned long flags_old = __sync_fetch_and_or(&line6pcm->flags, channels); unsigned long flags_new = flags_old | channels; int err = 0; line6pcm->prev_fbuf = NULL; if (test_flags(flags_old, flags_new, MASK_CAPTURE)) { /* Waiting for completion of active URBs in the stop handler is a bug, we therefore report an error if capturing is restarted too soon. */ if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) return -EBUSY; if (!(flags_new & MASK_PCM_ALSA_CAPTURE)) { err = line6_alloc_capture_buffer(line6pcm); if (err < 0) goto pcm_start_error; } line6pcm->count_in = 0; line6pcm->prev_fsize = 0; err = line6_submit_audio_in_all_urbs(line6pcm); if (err < 0) goto pcm_start_error; } if (test_flags(flags_old, flags_new, MASK_PLAYBACK)) { /* See comment above regarding PCM restart. */ if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) return -EBUSY; if (!(flags_new & MASK_PCM_ALSA_PLAYBACK)) { err = line6_alloc_playback_buffer(line6pcm); if (err < 0) goto pcm_start_error; } line6pcm->count_out = 0; err = line6_submit_audio_out_all_urbs(line6pcm); if (err < 0) goto pcm_start_error; } return 0; pcm_start_error: __sync_fetch_and_and(&line6pcm->flags, ~channels); return err; }
/* start a PCM stream */ static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, int type) { unsigned long flags; struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); int ret = 0; spin_lock_irqsave(&pstr->lock, flags); if (!test_and_set_bit(type, &pstr->running) && !(pstr->active_urbs || pstr->unlink_urbs)) { pstr->count = 0; /* Submit all currently available URBs */ if (direction == SNDRV_PCM_STREAM_PLAYBACK) ret = line6_submit_audio_out_all_urbs(line6pcm); else ret = line6_submit_audio_in_all_urbs(line6pcm); } if (ret < 0) clear_bit(type, &pstr->running); spin_unlock_irqrestore(&pstr->lock, flags); return ret; }
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) { unsigned long flags_old, flags_new, flags_final; int err; do { flags_old = ACCESS_ONCE(line6pcm->flags); flags_new = flags_old | channels; } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); flags_final = flags_old; line6pcm->prev_fbuf = NULL; if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { /* Invoked multiple times in a row so allocate once only */ if (!line6pcm->buffer_in) { line6pcm->buffer_in = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * line6pcm->max_packet_size, GFP_KERNEL); if (!line6pcm->buffer_in) { err = -ENOMEM; goto pcm_acquire_error; } flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; } } if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { /* Waiting for completion of active URBs in the stop handler is a bug, we therefore report an error if capturing is restarted too soon. */ if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); return -EBUSY; } line6pcm->count_in = 0; line6pcm->prev_fsize = 0; err = line6_submit_audio_in_all_urbs(line6pcm); if (err < 0) goto pcm_acquire_error; flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; } if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { /* Invoked multiple times in a row so allocate once only */ if (!line6pcm->buffer_out) { line6pcm->buffer_out = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * line6pcm->max_packet_size, GFP_KERNEL); if (!line6pcm->buffer_out) { err = -ENOMEM; goto pcm_acquire_error; } flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; } } if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { /* See comment above regarding PCM restart. */ if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) { dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); return -EBUSY; } line6pcm->count_out = 0; err = line6_submit_audio_out_all_urbs(line6pcm); if (err < 0) goto pcm_acquire_error; flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; } return 0; pcm_acquire_error: /* If not all requested resources/streams could be obtained, release those which were successfully obtained (if any). */ line6_pcm_release(line6pcm, flags_final & channels); return err; }
int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels) { unsigned long flags_old = __sync_fetch_and_or(&line6pcm->flags, channels); unsigned long flags_new = flags_old | channels; int err = 0; #if LINE6_BACKUP_MONITOR_SIGNAL if (!(line6pcm->line6->properties->capabilities & LINE6_BIT_HWMON)) { line6pcm->prev_fbuf = kmalloc(LINE6_ISO_PACKETS * line6pcm->max_packet_size, GFP_KERNEL); if (!line6pcm->prev_fbuf) { dev_err(line6pcm->line6->ifcdev, "cannot malloc monitor buffer\n"); return -ENOMEM; } } #else line6pcm->prev_fbuf = NULL; #endif if (((flags_old & MASK_CAPTURE) == 0) && ((flags_new & MASK_CAPTURE) != 0)) { /* Waiting for completion of active URBs in the stop handler is a bug, we therefore report an error if capturing is restarted too soon. */ if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) return -EBUSY; line6pcm->buffer_in = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * line6pcm->max_packet_size, GFP_KERNEL); if (!line6pcm->buffer_in) { dev_err(line6pcm->line6->ifcdev, "cannot malloc capture buffer\n"); return -ENOMEM; } line6pcm->count_in = 0; line6pcm->prev_fsize = 0; err = line6_submit_audio_in_all_urbs(line6pcm); if (err < 0) { __sync_fetch_and_and(&line6pcm->flags, ~channels); return err; } } if (((flags_old & MASK_PLAYBACK) == 0) && ((flags_new & MASK_PLAYBACK) != 0)) { /* See comment above regarding PCM restart. */ if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) return -EBUSY; line6pcm->buffer_out = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * line6pcm->max_packet_size, GFP_KERNEL); if (!line6pcm->buffer_out) { dev_err(line6pcm->line6->ifcdev, "cannot malloc playback buffer\n"); return -ENOMEM; } line6pcm->count_out = 0; err = line6_submit_audio_out_all_urbs(line6pcm); if (err < 0) { __sync_fetch_and_and(&line6pcm->flags, ~channels); return err; } } return 0; }