diff --git a/build_and_install.sh b/build_and_install.sh old mode 100755 new mode 100644 diff --git a/tascam_controls/build_appimage.sh b/tascam_controls/build_appimage.sh old mode 100755 new mode 100644 diff --git a/us144mkii.c b/us144mkii.c index 6053973..c8da90e 100644 --- a/us144mkii.c +++ b/us144mkii.c @@ -258,21 +258,7 @@ error: return -ENOMEM; } -void tascam_stop_work_handler(struct work_struct *work) -{ - struct tascam_card *tascam = - container_of(work, struct tascam_card, stop_work); - if (!atomic_read(&tascam->playback_active)) { - usb_kill_anchored_urbs(&tascam->playback_anchor); - usb_kill_anchored_urbs(&tascam->feedback_anchor); - } - if (!atomic_read(&tascam->capture_active)) - usb_kill_anchored_urbs(&tascam->capture_anchor); - - if (!atomic_read(&tascam->playback_active) && !atomic_read(&tascam->capture_active)) - atomic_set(&tascam->active_urbs, 0); -} /** * tascam_card_private_free() - Frees private data associated with the sound @@ -316,7 +302,6 @@ static int tascam_suspend(struct usb_interface *intf, pm_message_t message) snd_pcm_suspend_all(tascam->pcm); - cancel_work_sync(&tascam->stop_work); cancel_work_sync(&tascam->capture_work); cancel_work_sync(&tascam->midi_in_work); cancel_work_sync(&tascam->midi_out_work); @@ -498,8 +483,10 @@ static int tascam_probe(struct usb_interface *intf, tascam->capture_34_source = 1; spin_lock_init(&tascam->lock); + spin_lock_init(&tascam->trigger_lock); spin_lock_init(&tascam->midi_in_lock); spin_lock_init(&tascam->midi_out_lock); + atomic_set(&tascam->stream_active, 0); init_usb_anchor(&tascam->playback_anchor); init_usb_anchor(&tascam->capture_anchor); init_usb_anchor(&tascam->feedback_anchor); @@ -508,7 +495,6 @@ static int tascam_probe(struct usb_interface *intf, timer_setup(&tascam->error_timer, tascam_error_timer, 0); - INIT_WORK(&tascam->stop_work, tascam_stop_work_handler); INIT_WORK(&tascam->stop_pcm_work, tascam_stop_pcm_work_handler); INIT_WORK(&tascam->capture_work, tascam_capture_work_handler); init_completion(&tascam->midi_out_drain_completion); @@ -588,7 +574,6 @@ static void tascam_disconnect(struct usb_interface *intf) if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { /* Ensure all deferred work is complete before freeing resources */ snd_card_disconnect(tascam->card); - cancel_work_sync(&tascam->stop_work); cancel_work_sync(&tascam->capture_work); cancel_work_sync(&tascam->midi_in_work); cancel_work_sync(&tascam->midi_out_work); diff --git a/us144mkii.h b/us144mkii.h index 95c4341..cb31364 100644 --- a/us144mkii.h +++ b/us144mkii.h @@ -229,8 +229,10 @@ struct tascam_card { /* --- Stream State --- */ spinlock_t lock; + spinlock_t trigger_lock; atomic_t playback_active; atomic_t capture_active; + atomic_t stream_active; atomic_t active_urbs; int current_rate; @@ -273,7 +275,6 @@ struct tascam_card { struct us144mkii_frame_pattern_observer fpo; /* --- Workqueues --- */ - struct work_struct stop_work; struct work_struct stop_pcm_work; struct work_struct capture_work; struct work_struct midi_in_work; @@ -308,14 +309,7 @@ void tascam_free_urbs(struct tascam_card *tascam); */ int tascam_alloc_urbs(struct tascam_card *tascam); -/** - * tascam_stop_work_handler() - Work handler to stop all active streams. - * @work: Pointer to the work_struct. - * - * This function is scheduled to stop all active URBs (playback, feedback, - * capture) and reset the active_urbs counter. - */ -void tascam_stop_work_handler(struct work_struct *work); + /* us144mkii_pcm.h */ #include "us144mkii_pcm.h" diff --git a/us144mkii_pcm.c b/us144mkii_pcm.c index a3d96ea..118d73b 100644 --- a/us144mkii_pcm.c +++ b/us144mkii_pcm.c @@ -282,12 +282,30 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct tascam_card *tascam = snd_pcm_substream_chip(substream); int err = 0; int i; + unsigned long flags; + + spin_lock_irqsave(&tascam->trigger_lock, flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (atomic_xchg(&tascam->playback_active, 1) == 0) { + if (atomic_fetch_inc(&tascam->stream_active) == 0) { + for (i = 0; i < NUM_FEEDBACK_URBS; i++) { + usb_get_urb(tascam->feedback_urbs[i]); + usb_anchor_urb(tascam->feedback_urbs[i], &tascam->feedback_anchor); + err = usb_submit_urb(tascam->feedback_urbs[i], GFP_ATOMIC); + if (err < 0) { + usb_unanchor_urb(tascam->feedback_urbs[i]); + usb_put_urb(tascam->feedback_urbs[i]); + atomic_dec(&tascam->active_urbs); + break; + } + atomic_inc(&tascam->active_urbs); + } + } + for (i = 0; i < NUM_PLAYBACK_URBS; i++) { usb_get_urb(tascam->playback_urbs[i]); usb_anchor_urb(tascam->playback_urbs[i], &tascam->playback_anchor); @@ -299,23 +317,24 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) } atomic_inc(&tascam->active_urbs); } - for (i = 0; i < NUM_FEEDBACK_URBS; i++) { - usb_get_urb(tascam->feedback_urbs[i]); - usb_anchor_urb(tascam->feedback_urbs[i], - &tascam->feedback_anchor); - err = usb_submit_urb(tascam->feedback_urbs[i], - GFP_ATOMIC); - if (err < 0) { - usb_unanchor_urb(tascam->feedback_urbs[i]); - usb_put_urb(tascam->feedback_urbs[i]); - atomic_dec(&tascam->active_urbs); - break; - } - atomic_inc(&tascam->active_urbs); - } } } else { if (atomic_xchg(&tascam->capture_active, 1) == 0) { + if (atomic_fetch_inc(&tascam->stream_active) == 0) { + for (i = 0; i < NUM_FEEDBACK_URBS; i++) { + usb_get_urb(tascam->feedback_urbs[i]); + usb_anchor_urb(tascam->feedback_urbs[i], &tascam->feedback_anchor); + err = usb_submit_urb(tascam->feedback_urbs[i], GFP_ATOMIC); + if (err < 0) { + usb_unanchor_urb(tascam->feedback_urbs[i]); + usb_put_urb(tascam->feedback_urbs[i]); + atomic_dec(&tascam->active_urbs); + break; + } + atomic_inc(&tascam->active_urbs); + } + } + for (i = 0; i < NUM_CAPTURE_URBS; i++) { usb_get_urb(tascam->capture_urbs[i]); usb_anchor_urb(tascam->capture_urbs[i], &tascam->capture_anchor); @@ -335,14 +354,19 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_PAUSE_PUSH: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (atomic_xchg(&tascam->playback_active, 0) == 1) { - usb_kill_anchored_urbs(&tascam->playback_anchor); - usb_kill_anchored_urbs(&tascam->feedback_anchor); - schedule_work(&tascam->stop_work); + if (atomic_dec_and_test(&tascam->stream_active)) + usb_unlink_anchored_urbs(&tascam->feedback_anchor); + + usb_unlink_anchored_urbs(&tascam->playback_anchor); + } } else { if (atomic_xchg(&tascam->capture_active, 0) == 1) { - usb_kill_anchored_urbs(&tascam->capture_anchor); - schedule_work(&tascam->stop_work); + if (atomic_dec_and_test(&tascam->stream_active)) + usb_unlink_anchored_urbs(&tascam->feedback_anchor); + + usb_unlink_anchored_urbs(&tascam->capture_anchor); + } } break; @@ -351,6 +375,8 @@ int tascam_pcm_trigger(struct snd_pcm_substream *substream, int cmd) break; } + spin_unlock_irqrestore(&tascam->trigger_lock, flags); + return err; } int tascam_init_pcm(struct snd_pcm *pcm) diff --git a/us144mkii_playback.c b/us144mkii_playback.c index 0cb9699..392da96 100644 --- a/us144mkii_playback.c +++ b/us144mkii_playback.c @@ -276,7 +276,7 @@ void feedback_urb_complete(struct urb *urb) } goto out; } - if (!tascam || !atomic_read(&tascam->playback_active)) + if (!tascam || !atomic_read(&tascam->stream_active)) goto out; playback_ss = tascam->playback_substream;