| // SPDX-License-Identifier: GPL-2.0 |
| #include <linux/kthread.h> |
| #include <linux/wait.h> |
| |
| #include "spk_types.h" |
| #include "speakup.h" |
| #include "spk_priv.h" |
| |
| DECLARE_WAIT_QUEUE_HEAD(speakup_event); |
| EXPORT_SYMBOL_GPL(speakup_event); |
| |
| int speakup_thread(void *data) |
| { |
| unsigned long flags; |
| int should_break; |
| struct bleep our_sound; |
| |
| our_sound.active = 0; |
| our_sound.freq = 0; |
| our_sound.jiffies = 0; |
| |
| mutex_lock(&spk_mutex); |
| while (1) { |
| DEFINE_WAIT(wait); |
| |
| while (1) { |
| spin_lock_irqsave(&speakup_info.spinlock, flags); |
| our_sound = spk_unprocessed_sound; |
| spk_unprocessed_sound.active = 0; |
| prepare_to_wait(&speakup_event, &wait, |
| TASK_INTERRUPTIBLE); |
| should_break = kthread_should_stop() || |
| our_sound.active || |
| (synth && synth->catch_up && synth->alive && |
| (speakup_info.flushing || |
| !synth_buffer_empty())); |
| spin_unlock_irqrestore(&speakup_info.spinlock, flags); |
| if (should_break) |
| break; |
| mutex_unlock(&spk_mutex); |
| schedule(); |
| mutex_lock(&spk_mutex); |
| } |
| finish_wait(&speakup_event, &wait); |
| if (kthread_should_stop()) |
| break; |
| |
| if (our_sound.active) |
| kd_mksound(our_sound.freq, our_sound.jiffies); |
| if (synth && synth->catch_up && synth->alive) { |
| /* |
| * It is up to the callee to take the lock, so that it |
| * can sleep whenever it likes |
| */ |
| synth->catch_up(synth); |
| } |
| |
| speakup_start_ttys(); |
| } |
| mutex_unlock(&spk_mutex); |
| return 0; |
| } |