/*
 * @file hv_drv_UsbBitWise.h
 * @brief Header file of usb module.
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-06-15
 */


#ifndef __HV_DRV_USB_BITWISE_H
#define __HV_DRV_USB_BITWISE_H

#include "hv_drv_UsbPortingTypes.h"

#define __BITS_PER_LONG  32
#define BITOP_WORD(nr)  (nr / __BITS_PER_LONG)
INLINE void set_bit(int nr, volatile unsigned long *addr) {
    addr[nr / __BITS_PER_LONG] |= 1UL << (nr % __BITS_PER_LONG);
}

INLINE void clear_bit(int nr, volatile unsigned long *addr) {
    addr[nr / __BITS_PER_LONG] &= ~(1UL << (nr % __BITS_PER_LONG));
}

INLINE int test_bit(int nr, const unsigned long *addr) {
    return ((1UL << (nr % __BITS_PER_LONG)) & (addr[nr / __BITS_PER_LONG])) != 0;
}

INLINE int test_and_clear_bit(int nr, volatile unsigned long *addr) {
    const unsigned b = ((1UL << (nr % __BITS_PER_LONG)) & (addr[nr / __BITS_PER_LONG]));
    clear_bit(nr, addr);

    return b != 0;
}

/* awkward implement */
INLINE long find_next_zero_bit(const unsigned long *addr,
                               unsigned long size, unsigned long offset) {
    int max_of = BITOP_WORD(size);
    int addr_of = BITOP_WORD(offset);
    const unsigned long *temp = addr + addr_of;

    int ofc = offset - (addr_of * __BITS_PER_LONG);
    int i, of;
    for (of = addr_of; of < max_of; of++) {
        for (i = ofc; i < __BITS_PER_LONG; i++) {
            if ((1 << i) & *temp)
                continue;
            else
                break;
        }
        if (i == __BITS_PER_LONG) {
            temp += 1;
            ofc = 0;
        } else
            break;
    }

    return (((of) * __BITS_PER_LONG) + i);
}


#define DIV_ROUND_UP(n,d)   (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE        8
#define BITS_TO_LONGS(nr)    DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))

/* common */
#define DECLARE_BITMAP(name, bits) \
    unsigned long name[BITS_TO_LONGS(bits)]

#define small_const_nbits(nbits) \
    (__builtin_constant_p(nbits) && (nbits) <= __BITS_PER_LONG)

static inline void bitmap_zero(unsigned long *dst, int nbits)
{
    if (small_const_nbits(nbits))
        *dst = 0UL;
    else {
        int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
        HV_MEMSET(dst, 0, len);
    }
}

#endif
