/*
* @file hv_drv_UsbUtilFunction (u_f.h)
* @brief Utility definitions for USB functions. 
*
* @author HiView SoC Software Team
* @version 1.0.0
* @date 2022-06-15
*/


#ifndef __HV_DRV_USB_UTILITY_FUNCTION_H
#define __HV_DRV_USB_UTILITY_FUNCTION_H

#include "hv_drv_UsbGadget.h"
#include "hv_drv_UsbDefines.h"
#include "hv_drv_UsbCompat.h"

/* Variable Length Array Macros **********************************************/
#define vla_group(groupname) size_t groupname##__next = 0
#define vla_group_size(groupname) groupname##__next

#define vla_item(groupname, type, name, n) \
    size_t groupname##_##name##__offset = ({                   \
        size_t align_mask = __alignof__(type) - 1;               \
        size_t offset = (groupname##__next + align_mask) & ~align_mask;\
        size_t size = (n) * sizeof(type);                   \
        groupname##__next = offset + size;                   \
        offset;                                   \
    })

#define vla_item_with_sz(groupname, type, name, n) \
    size_t groupname##_##name##__sz = (n) * sizeof(type);               \
    size_t groupname##_##name##__offset = ({                   \
        size_t align_mask = __alignof__(type) - 1;               \
        size_t offset = (groupname##__next + align_mask) & ~align_mask;\
        size_t size = groupname##_##name##__sz;                   \
        groupname##__next = offset + size;                   \
        offset;                                   \
    })

#define vla_ptr(ptr, groupname, name) \
    ((void *) ((char *)ptr + groupname##_##name##__offset))

struct usb_ep;
struct usb_request;

/**
 * alloc_ep_req - returns a usb_request allocated by the gadget driver and
 * allocates the request's buffer.
 *
 * @ep: the endpoint to allocate a usb_request
 * @len: usb_requests's buffer suggested size
 *
 * In case @ep direction is OUT, the @len will be aligned to ep's
 * wMaxPacketSize. In order to avoid memory leaks or drops, *always* use
 * usb_requests's length (req->length) to refer to the allocated buffer size.
 * Requests allocated via alloc_ep_req() *must* be freed by free_ep_req().
 */
struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len);

/* Frees a usb_request previously allocated by alloc_ep_req() */
static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
    kfree(req->buf);
    req->buf = NULL;
    usb_ep_free_request(ep, req);
}

#endif

