// 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;
}