/*
 *  Advanced Linux Sound Architecture
 *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#define __KERNEL_SYSCALLS__
#include "driver.h"
#include "sthread.h"
#ifdef LINUX_2_1
#include <linux/smp_lock.h>
#endif

/*
 *  THIS CODE ISN'T WORKING!!!
 *  AT LEAST FOR LATEST 2.2.0pre KERNEL!!!
 */

#if 0

snd_spin_define_static(threads);
static snd_thread_t *snd_threads = NULL;
snd_mutex_define_static(thread);
static int snd_thread_pid = -1;
static int errno;

#include <asm/unistd.h>

#ifndef LINUX_2_1
static void snd_exit_fs(struct task_struct *tsk)
{
	struct fs_struct * fs = tsk->fs;

	if (fs) {
		tsk->fs = NULL;
		if (!--fs->count) {
			iput(fs->root);
			iput(fs->pwd);
			kfree(fs);
		}
	}
}
#endif

static inline void use_init_file_context(void)
{
#ifndef LINUX_2_1
	unsigned long flags;
#endif
	
#ifdef LINUX_2_1
	lock_kernel();
	exit_fs(current);
#else
	snd_cli(&flags);
	snd_exit_fs(current);
#endif
	sprintf(current->comm, "sound_thread");
	current->mm->arg_start = 0;
	current->mm->arg_end = 0;
	current->policy = SCHED_OTHER;
	current->priority = (5*HZ/100);		/* 50ms timeslices */
#ifdef LINUX_2_1
	unlock_kernel();
#else
	current->blocked = -1;			/* block all (like nohup) */
	snd_sti(&flags);
#endif
}

static int snd_thread(void *data)
{
	unsigned long flags;
	snd_thread_t *t;
	int i;

	printk("snd_thread!!!\n");
#if 0
	use_init_file_context();

#ifdef LINUX_2_1
	spin_lock_irq(&current->sigmask_lock);
	flush_signals(current);
	memset(&current->blocked, 0xff, sizeof(current->blocked));
	spin_unlock_irq(&current->sigmask_lock);

	for (i = 0; i < current->files->max_fds; i++) {
		 if (current->files->fd[i])
		 	close(i);
	}
#else
	for (i = 0; i < NR_OPEN; i++) {
		 if (current->files->fd[i])
		 	close(i);
	}
#endif
	current->uid = current->euid = current->fsuid = 0;
	current->gid = 0;
#endif

	i = 0;
	while (1) {
		printk("abcd - %i\n", i++);
		return 0;
		current->state = TASK_INTERRUPTIBLE;
#ifdef LINUX_2_1
		schedule_timeout(1);
#else
		schedule();
#endif
		current->state = TASK_RUNNING;
		printk("okok - %i\n", i);
		return 0;
		snd_spin_lock_static(threads, &flags);
		if (snd_threads == NULL) {
			snd_thread_pid = -1;
			snd_spin_unlock_static(threads, &flags);
			return 0;
		}
		for (t = snd_threads; t; t = t->next)
			if (t->callback)
				t->callback(t->data);
		snd_spin_unlock_static(threads, &flags);
	}
}

snd_thread_t *snd_thread_create(void (*callback)(void *data), void *data)
{
	unsigned long flags;
	snd_thread_t *t;
	
	t = snd_calloc(sizeof(snd_thread_t));
	if (t == NULL)
		return NULL;
	t->callback = callback;
	t->data = data;
	snd_spin_lock_static(threads, &flags);
	t->next = snd_threads;
	snd_threads = t;
	snd_spin_unlock_static(threads, &flags);
	snd_mutex_down_static(thread);
	if (snd_thread_pid < 0) {
		printk("thread go!!\n");
		snd_thread_pid = kernel_thread(snd_thread, NULL, CLONE_FS);
		if (snd_thread_pid < 0)
			snd_printk("fork failed for sound thread");
#if 1
		printk("thread pid = %i\n", snd_thread_pid);
#endif
	}
	snd_mutex_up_static(thread);
	printk("ok..\n");
	return t;
}

int snd_thread_remove(snd_thread_t *t)
{
	unsigned long flags;
	snd_thread_t *prev;

	snd_spin_lock_static(threads, &flags);
	if (snd_threads == t) {
		snd_threads = t->next;
	} else {
		prev = snd_threads;
		while (prev && prev->next != t) prev = prev->next;
		if (!prev) {
			snd_spin_unlock_static(threads, &flags);
			return -ENOENT;
		}
		prev->next = t->next;
	}
	snd_spin_unlock_static(threads, &flags);
	snd_free(t, sizeof(snd_thread_t));
	return 0;
}

#endif
