/*
* @file hv_drv_UsbPortingOsDevtab.h
* @brief Header file of usb adapting to os about dev tab.
*
* @author HiView SoC Software Team
* @version 1.0.0
* @date 2022-06-15
*/

#ifndef __HV_DRV_USB_PORTING_OS_DEVTAB_H
#define __HV_DRV_USB_PORTING_OS_DEVTAB_H

#include "hv_drv_UsbPortingOsTypes.h"
#include "hv_drv_UsbPortingOsIo.h"

// Set of functions which handle top level I/O functions
typedef struct _os_devio_table_t {
    os_errno (*write)(os_io_handle_t handle,
                      const void *buf,
                      u32 *len);
    os_errno (*read)(os_io_handle_t handle,
                     void *buf,
                     u32 *len);
    os_errno (*bwrite)(os_io_handle_t handle,
                       const void *buf,
                       u32 *len,   // in blocks
                       u32 pos);   // in blocks
    os_errno (*bread)(os_io_handle_t handle,
                      void *buf,
                      u32 *len,    // in blocks
                      u32 pos);    // in blocks
    os_errno  (*select)(os_io_handle_t handle,
                        u32 which,
                        OS_ADDRWORD info);
    os_errno (*get_config)(os_io_handle_t handle,
                           u32 key,
                           void *buf,
                           u32 *len);
    os_errno (*set_config)(os_io_handle_t handle,
                           u32 key,
                           const void *buf,
                           u32 *len);
} os_devio_table_t;


// Default functions

os_errno os_devio_cwrite(os_io_handle_t handle,
                         const void *buf, u32 *len);
os_errno os_devio_cread(os_io_handle_t handle,
                        void *buf, u32 *len);
os_errno os_devio_bwrite(os_io_handle_t handle,
                         const void *buf, u32 *len,
                         u32 pos);
os_errno os_devio_bread(os_io_handle_t handle,
                        void *buf, u32 *len,
                        u32 pos);

os_errno os_devio_select(os_io_handle_t handle,
                         u32 which,
                         OS_ADDRWORD info);

os_errno os_devio_get_config(os_io_handle_t handle,
                             u32 key,
                             void* buf,
                             u32* len);

os_errno os_devio_set_config(os_io_handle_t handle,
                             u32 key,
                             void* buf,
                             u32* len);

// Initialization macros

#define CHAR_DEVIO_TABLE(_l,_write,_read,_select,_get_config,_set_config)    \
os_devio_table_t _l = {                                         \
    _write,                                                     \
    _read,                                                      \
    os_devio_bwrite,                                            \
    os_devio_bread,                                             \
    _select,                                                    \
    _get_config,                                                \
    _set_config,                                                \
};

// Note: _bwrite and _bread pass len and pos in terms of blocks, not
// bytes.
#define BLOCK_DEVIO_TABLE(_l,_bwrite,_bread,_select,_get_config,_set_config)    \
os_devio_table_t _l = {                                         \
    os_devio_cwrite,                                            \
    os_devio_cread,                                             \
    _bwrite,                                                    \
    _bread,                                                     \
    _select,                                                    \
    _get_config,                                                \
    _set_config,                                                \
};

#define DEVIO_TABLE(_l,_write,_read,_select,_get_config,_set_config) \
        CHAR_DEVIO_TABLE(_l,_write,_read,_select,_get_config,_set_config)

typedef struct os_devtab_entry {
    const char          *name;
    const char          *dep_name;
    os_devio_table_t    *handlers;
    boolean             (*init)(struct os_devtab_entry *tab);
    os_errno            (*lookup)(struct os_devtab_entry **tab,
                              struct os_devtab_entry *sub_tab,
                              const char *name);
    void                *priv;
    unsigned long       status;
} OS_HAL_TABLE_TYPE os_devtab_entry_t;

#define OS_DEVTAB_STATUS_AVAIL   0x0001
#define OS_DEVTAB_STATUS_CHAR    0x1000
#define OS_DEVTAB_STATUS_BLOCK   0x2000
#define OS_DEVTAB_STATUS_INITED  0x4000

#define CHAR_DEVTAB_ENTRY(_l,_name,_dep_name,_handlers,_init,_lookup,_priv)  \
os_devtab_entry_t _l OS_HAL_TABLE_ENTRY(devtab) = {                     \
   _name,                                                               \
   _dep_name,                                                           \
   _handlers,                                                           \
   _init,                                                               \
   _lookup,                                                             \
   _priv,                                                               \
   OS_DEVTAB_STATUS_CHAR                                                \
};

#define BLOCK_DEVTAB_ENTRY(_l,_name,_dep_name,_handlers,_init,_lookup,_priv)  \
os_devtab_entry_t _l  =                            {                    \
   _name,                                                               \
   _dep_name,                                                           \
   _handlers,                                                           \
   _init,                                                               \
   _lookup,                                                             \
   _priv,                                                               \
   OS_DEVTAB_STATUS_BLOCK                                               \
};

#define DEVTAB_ENTRY(_l,_name,_dep_name,_handlers,_init,_lookup,_priv)  \
        CHAR_DEVTAB_ENTRY(_l,_name,_dep_name,_handlers,_init,_lookup,_priv)


#define DEVTAB_ENTRY_NO_INIT(_l,_name,_dep_name,_handlers,_init,_lookup,_priv)  \
os_devtab_entry_t _l = {                                                        \
   _name,                                                                       \
   _dep_name,                                                                   \
   _handlers,                                                                   \
   _init,                                                                       \
   _lookup,                                                                     \
   _priv,                                                                       \
   OS_DEVTAB_STATUS_CHAR                                                        \
};

void os_dev_register(os_devtab_entry_t *dev);
void os_dev_unregister(os_devtab_entry_t *dev);

#endif
