/*
 * RT-Linux task queues
 *
 *  Copyright (C) 1999 FSM Labs (http://www.fsmlabs.com/)
 *  Written by Michael Barabanov <baraban@fsmlabs.com>
 */

#ifndef __RTL_TQUEUE__
#define __RTL_TQUEUE__

#include <linux/tqueue.h>

extern spinlock_t rtl_tqueue_lock;

/* these can not be used with non-RTL queues */
extern __inline__ void rtl_queue_task(struct tq_struct *bh_pointer,
			   task_queue *bh_list)
{
	if (!test_and_set_bit(0,&bh_pointer->sync)) {
		rtl_irqstate_t flags;
		rtl_spin_lock_irqsave(&rtl_tqueue_lock, flags);
		bh_pointer->next = *bh_list;
		*bh_list = bh_pointer;
		rtl_spin_unlock_irqrestore(&rtl_tqueue_lock, flags);
	}
}

/*
 * Call all "bottom halfs" on a given list.
 */
extern __inline__ void rtl_run_task_queue(task_queue *list)
{
	if (*list) {
		rtl_irqstate_t flags;
		struct tq_struct *p;

		rtl_spin_lock_irqsave(&rtl_tqueue_lock, flags);
		p = *list;
		*list = NULL;
		rtl_spin_unlock_irqrestore(&rtl_tqueue_lock, flags);
		
		while (p) {
			void *arg;
			void (*f) (void *);
			struct tq_struct *save_p;
			arg    = p -> data;
			f      = p -> routine;
			save_p = p;
			p      = p -> next;
			mb();
			(*f)(arg);
			mb();
			save_p -> sync = 0;
		}
	}
}

/* this function can only be called from Linux */
extern __inline__ void rtl_move_to_linux_tq(task_queue *list, task_queue *destlist)
{
	if (*list) {
		rtl_irqstate_t flags;
		struct tq_struct *p;
		rtl_spin_lock_irqsave (&rtl_tqueue_lock, flags);
		p = *list;
		*list = NULL;
		rtl_spin_unlock_irqrestore (&rtl_tqueue_lock, flags);

		spin_lock_irqsave(&tqueue_lock, flags);
		while (p) {
			struct tq_struct *save_p = p;
			p = p -> next;
			save_p->next = *destlist;
			*destlist = save_p;
			mb();
		}
		spin_unlock_irqrestore(&tqueue_lock, flags);
	}
}

#endif
