/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) Equator Technologies
 */
#ifndef _ASM_BSP_BITOPS_H_
#define _ASM_BSP_BITOPS_H_


#include <eti/mm.h>
#include <asm/system.h>


#define BITOPS_FUN(fun, XXX) \
       extern __inline__  int fun(int nr, void *addr)      \
       {                                       \
	       int	 mask, retval;         \
	       unsigned long flags;            \
	       unsigned long *word= addr;      \
                                               \
	       word += nr >> 5;                \
	       mask  = 1 << (nr & 0x1f);       \
                                               \
	       save_and_cli(flags);            \
                                               \
	       retval = (mask & *word) != 0;   \
                                               \
               XXX;                            \
                                               \
	       restore_flags(flags);           \
               return retval;                  \
       }


BITOPS_FUN( test_bit,                   {}       )
BITOPS_FUN( test_and_set_bit,     *word |=  mask )
BITOPS_FUN( test_and_clear_bit,   *word &= ~mask )
BITOPS_FUN( test_and_change_bit,  *word ^=  mask )

#define set_bit(nr,addr)    test_and_set_bit(nr,addr)
#define clear_bit(nr,addr)  test_and_clear_bit(nr,addr)
#define change_bit(nr,addr) test_and_change_bit(nr,addr)


#ifdef __KERNEL__

extern __inline__ unsigned long ffz(unsigned long x)
{
	n32 tmp;
	int pos;

	if (x == ~0) return 0;

	/* bit reverse */
	tmp = hmpv_brcopyrev_32(x, 0x3, 0x3);

	/* find position of left-most zero */
	pos = hmpv_lmz_32(tmp);

	return (31 - pos);
}

extern __inline__ int ffs(int x)
{
	n32 tmp;
	int pos;

	if (!x) return 0;

	/* bit reverse */
	tmp = hmpv_brcopyrev_32(x, 0x3, 0x3);

	/* find position of left-most one */
	pos = hmpv_lmo_32(tmp);

	return (32 - pos);
}

/*
 * Find next zero bit in a bitmap reasonably efficiently..
 */
extern inline unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset)
{
	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
	unsigned long result = offset & ~31UL;
	unsigned long tmp;

	if (offset >= size)
		return size;
	size -= result;
	offset &= 31UL;
	if (offset) {
		tmp = *(p++);
		tmp |= ~0UL >> (32-offset);
		if (size < 32)
			goto found_first;
		if (~tmp)
			goto found_middle;
		size -= 32;
		result += 32;
	}
	while (size & ~31UL) {
		if (~(tmp = *(p++)))
			goto found_middle;
		result += 32;
		size -= 32;
	}
	if (!size)
		return result;
	tmp = *p;
found_first:
	tmp |= ~0UL << size;
	if (tmp == ~0UL)        /* Are any bits zero? */
		return result + size; /* Nope. */
found_middle:
	return result + ffz(tmp);
}

#define find_first_zero_bit(addr, size) \
	find_next_zero_bit((addr), (size), 0)

/*
 * hweightN: returns the hamming weight (i.e. the number
 * of bits set) of a N-bit word
 */

#define hweight32(x) generic_hweight32(x)
#define hweight16(x) generic_hweight16(x)
#define hweight8(x) generic_hweight8(x)

/* Bitmap functions for the ext2 filesystem.  */
#define ext2_set_bit                 test_and_set_bit
#define ext2_clear_bit               test_and_clear_bit
#define ext2_test_bit                test_bit
#define ext2_find_first_zero_bit     find_first_zero_bit
#define ext2_find_next_zero_bit      find_next_zero_bit

/* Bitmap functions for the minix filesystem.  */
#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
#define minix_test_bit(nr,addr) test_bit(nr,addr)
#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)

#endif /* __KERNEL__ */

#endif	/* _ASM_BSP_BITOPS_H */
