/*****************************************************************
>file name : pcm.h
>create time : Mon 18 Jan 2021 02:04:15 PM CST
*****************************************************************/
#ifndef _SOUND_PCM_H_
#define _SOUND_PCM_H_
#include "audio_cfifo.h"
#include "os/os_api.h"

struct sound_pcm_hardware {
    unsigned int info;		/* SOUND_PCM_INFO_* */
    unsigned int formats;			/* SOUND_PCM_FMTBIT_* */
    unsigned int rates;		/* SOUND_PCM_RATE_* */
    unsigned int rate_min;		/* min rate */
    unsigned int rate_max;		/* max rate */
    unsigned int channels_min;	/* min channels */
    unsigned int channels_max;	/* max channels */
    int buffer_bytes_max;	/* max buffer size */
    int period_bytes_min;	/* min period size */
    int period_bytes_max;	/* max period size */
    unsigned int periods_min;	/* min # of periods */
    unsigned int periods_max;	/* max # of periods */
    int fifo_size;		/* fifo size in bytes */
};

struct sound_pcm_substream;
struct sound_pcm_hw_params;

/*****************************************************************************/
/* SOUND PCM逻辑设备错误返回值*/
#define ESNDPCM_NOMEM               1       /* PCM设备申请不到内存 */
#define ESNDPCM_NODEV               2       /* 找不到PCM设备 */
#define ESNDPCM_INVAL               3       /* 无效的设备平台(未初始化) */
#define ESNDPCM_UNKNOWN_RATE        4       /* PCM设备不支持的采样率 */
#define ESNDPCM_CONFLICT_RATE       5       /* PCM设备与设置采样率冲突 */
#define ESNDPCM_NOFIFO              6       /* PCM设备中没有设置runtime的fifo */

/*****************************************************************************/

#define SOUND_PCM_TRIGGER_START     1       /* 触发DMA/CODEC开启 */
#define SOUND_PCM_TRIGGER_STOP      2       /* 触发DMA/CODEC停止 */
#define SOUND_PCM_TRIGGER_IRQ       3       /* 触发DMA下一个中断外传 */

#define SOUND_PCM_GET_HW_PARAMS             _IOR('P', 1, sizeof(struct sound_pcm_hw_params)) /* Get硬件参数 */
#define SOUND_PCM_SET_HW_PARAMS             _IOW('P', 2, sizeof(struct sound_pcm_hw_params)) /* Set硬件参数 */
#define SOUND_PCM_GET_HW_BUFFERED_LEN       _IOR('P', 3, sizeof(unsigned int)) /* Get硬件参数 */
#define SOUND_PCM_WAIT_SWN_MOVE             _IOR('P', 4, sizeof(unsigned int)) /* 等待dac swn 输出一个点后，再往后走硬件参数 */
#define SOUND_PCM_GET_HW_HRP                _IOR('P', 5, sizeof(unsigned int)) /* Get硬件读指针 */
#define SOUND_PCM_MOUNT_SYNCTS              _IOW('P', 7, sizeof(unsigned int)) /* 挂载音频同步处理 */
#define SOUND_PCM_UNMOUNT_SYNCTS            _IOW('P', 8, sizeof(unsigned int)) /* 卸载音频同步处理 */

enum pcm_state {
    SOUND_PCM_STATE_IDLE = 0,               /* PCM设备空闲 */
    SOUND_PCM_STATE_PREPARED,               /* PCM设备硬件准备就绪 */
    SOUND_PCM_STATE_RUNNING,                /* PCM设备DMA/CODEC运行中 */
    SOUND_PCM_STATE_SUSPENDED,              /* PCM设备挂起 */
};

/*
 * Sound PCM设备支持标准sample rate定义
 * */
#define SOUND_PCM_RATE_8000		    (1<<0)		/* 8000Hz */
#define SOUND_PCM_RATE_11025		(1<<1)		/* 11025Hz */
#define SOUND_PCM_RATE_12000		(1<<2)		/* 12000Hz */
#define SOUND_PCM_RATE_16000		(1<<3)		/* 16000Hz */
#define SOUND_PCM_RATE_22050		(1<<4)		/* 22050Hz */
#define SOUND_PCM_RATE_24000		(1<<5)		/* 24000Hz */
#define SOUND_PCM_RATE_32000		(1<<6)		/* 32000Hz */
#define SOUND_PCM_RATE_44100		(1<<7)		/* 44100Hz */
#define SOUND_PCM_RATE_48000		(1<<8)		/* 48000Hz */
#define SOUND_PCM_RATE_64000		(1<<9)		/* 64000Hz */
#define SOUND_PCM_RATE_88200		(1<<10)		/* 88200Hz */
#define SOUND_PCM_RATE_96000		(1<<11)		/* 96000Hz */
#define SOUND_PCM_RATE_128000		(1<<12)		/* 128000Hz */
#define SOUND_PCM_RATE_176400		(1<<13)		/* 176400Hz */
#define SOUND_PCM_RATE_192000		(1<<14)		/* 192000Hz */
#define SOUND_PCM_RATE_UNKNOWN      (1<<15)     /* Unknown sample rate */

#define SOUND_PCM_RATE_8000_44100	(SOUND_PCM_RATE_8000|SOUND_PCM_RATE_11025|SOUND_PCM_RATE_12000|\
					 SOUND_PCM_RATE_16000|SOUND_PCM_RATE_22050|SOUND_PCM_RATE_24000|\
					 SOUND_PCM_RATE_32000|SOUND_PCM_RATE_44100)
#define SOUND_PCM_RATE_8000_48000	(SOUND_PCM_RATE_8000_44100|SOUND_PCM_RATE_48000)
#define SOUND_PCM_RATE_8000_96000	(SOUND_PCM_RATE_8000_48000|SOUND_PCM_RATE_64000|\
					 SOUND_PCM_RATE_88200|SOUND_PCM_RATE_96000)
#define SOUND_PCM_RATE_8000_192000	(SOUND_PCM_RATE_8000_96000|SOUND_PCM_RATE_128000|SOUND_PCM_RATE_176400|\
					 SOUND_PCM_RATE_192000)

/*
 * PCM设备与硬件DMA同步flag
 */
#define DMA_SYNC_R          (1 << 0)                    /* 读同步 */
#define DMA_SYNC_W          (1 << 1)                    /* 写同步 */
#define DMA_SYNC_RW         (DMA_SYNC_R | DMA_SYNC_W)   /* 读写同步 */

/*
 * Sound运行时间单位
 */
#define SOUND_TIME_MS       0
#define SOUND_TIME_US       1


/*
 * PCM设备操作函数
 */
struct sound_pcm_ops {
    int (*open)(struct sound_pcm_substream *substream);
    int (*close)(struct sound_pcm_substream *substream);
    int (*ioctl)(struct sound_pcm_substream *substream,
                 unsigned int cmd, void *arg);
    int (*prepare)(struct sound_pcm_substream *substream);
    int (*trigger)(struct sound_pcm_substream *substream, int cmd);
    int (*pointer)(struct sound_pcm_substream *substream);
    int (*silence)(struct sound_pcm_substream *substream, int channel, u32 pos, u32 count);
};


struct sound_pcm_hw_params {
    u32 rates;
    int sample_rate;
    u8  sample_bits;
    u8  channels;
};

struct sound_dma_buffer {
    u8 mode;
    void *addr;
    s16  size;
    struct audio_cfifo fifo;
};

struct sound_pcm_map_status {
    u8 state;
    u8 ref_count;
};

struct sound_pcm_syncts_entry {
    void *private_data;
    struct list_head entry;
};

struct sound_pcm_map_fifo {
    void *addr;                         /* FIFO地址 */
    u16 bytes;                          /* FIFO大小(bytes) */
    u16 frame_len;                      /* FIFO帧总长度(bytes / ch / 2) */
    struct audio_cfifo cfifo;           /* FIFO结构实体 */
    void (*sync)(struct sound_pcm_substream *substream, u8 flag);    /* FIFO同步 */
    u8 is_malloc;
};

struct sound_pcm_runtime {
    /*fifo*/
    u32 hw_ptr;                         /* 当前硬件位置 */
    u32 sw_ptr;                         /* 当前软件位置 */
    u32 hw_ptr_jiffies;                 /* 当前硬件位置对应的时间 */
    u32 dma_irq_ptr;                    /* 设置的dma到达该ptr起中断 */
    u32(*sound_current_time)(void);     /* 当前采样时间获取 */
    struct sound_pcm_map_fifo *fifo;
    u8 time_type;                       /* 采样指针位置的时钟类型 */

    /* -- HW params -- */
    u8  channels;		/* 采样通道 */
    u8  sample_bits;
    u16 period_size;	/* 采样周期块大小(pingpong buffer模式) */
    u32 periods;		/* 采样周期个数 */
    int sample_rate;    /* sample_rate */

    /* -- SW params -- */
    u8 run_mode;            /*OVERRUN或非OVERRUN*/
    //u32 start_threshold;    [>启动DMA的阈值<]
    //u32 stop_threshold;     [>停止DMA的阈值<]
    //u32 silence_threshold;  [>静音数据阈值 <]
    //u32 silence_size;	    [>填充静音数据的大小 <]

    u32 silence_start;      /* 静音起始位置 */
    u32 silence_filled;     /* 已填充的静音数据 */
    int buffer_delay;

    struct sound_pcm_map_status *status; /*映射硬件中的状态*/

    /* -- DMA -- */
    struct sound_dma_buffer *dma;	/* DMA缓冲 */

    OS_MUTEX *mutex;
};


struct sound_pcm_stream;
struct sound_pcm_substream {
    struct sound_pcm_stream *stream;
    struct sound_pcm_runtime *runtime; /* 数据流运行结构 */
    struct audio_cfifo_channel fifo;   /* fifo缓冲 */
    void *private_data;
    struct list_head entry;
    void *irq_priv;
    void (*irq_handler)(void *priv);
    u8 direction;                      /* 数据流方向 */
    struct list_head syncts_list;
    unsigned int hw_opened: 1;
};

struct sound_pcm_stream {
    struct sound_pcm_substream *substream;              /* 与设备共享的子数据流 */
    const struct sound_pcm_ops *ops;                          /* PCM操作函数 */
    void *platform_device;
};


/*************************************************************************
 * 采样率转换为bit表示
 * Input    :  sample_rate - 采样率
 * Output   :  采样率的bit表示
 * Notes    :
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_match_standard_rate(int sample_rate);

/*************************************************************************
 * 创建sound pcm数据流
 * Input    :  stream  - sound_pcm_stream二级指针，
 *             name    - 设备名，
 *             direction - 数据流方向.
 * Output   :  0 - 创建成功，非0 - 失败.
 * Notes    :
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_create(struct sound_pcm_stream **stream, const char *name, u8 direction);

/*************************************************************************
 * 设置pcm设备中断处理函数
 * Input    :  stream  - sound_pcm_stream指针，
 *             priv    - 回调私有数据，
 *             handler - 回调处理函数.
 * Output   :  无.
 * Notes    :  pingpong模式可以用来处理音频采样定时，
 *             也可以使用中断处理唤醒等功能。
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
void sound_pcm_set_irq_handler(struct sound_pcm_stream *stream, void *priv, void (*handler)(void *));

/*************************************************************************
 * pcm设备数据流准备
 * Input    :  stream  - sound_pcm_stream指针，
 *             sample_rate  - 设备采样率，
 *             delay - 设备缓冲延时，
 *             mode  - 数据流overrun/block模式选择.
 * Output   :  0 - 成功，非0 - 失败.
 * Notes    :
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_prepare(struct sound_pcm_stream *stream, int sample_rate, int delay, int mode);

/*************************************************************************
 * pcm设备数据流开启采样
 * Input    :  stream  - sound_pcm_stream指针.
 * Output   :  0 - 成功，非0 - 失败.
 * Notes    :
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_start(struct sound_pcm_stream *stream);

/*************************************************************************
 * pcm设备数据流停止采样
 * Input    :  stream  - sound_pcm_stream指针.
 * Output   :  0 - 成功，非0 - 失败.
 * Notes    :
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_stop(struct sound_pcm_stream *stream);

/*************************************************************************
 * pcm设备数据流触发一次中断
 * Input    :  stream  - sound_pcm_stream指针,
 *             time_unit - 设置中断起来时间的单位，
 *             time      - 设置多少时间后起来（临近）.
 * Output   :  0 - 成功，非0 - 失败.
 * Notes    :
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_trigger_interrupt(struct sound_pcm_stream *stream, u8 time_unit, int time);

/*************************************************************************
 * pcm设备数据子流中断处理函数
 * Input    :  substream  - sound_pcm_substream指针.
 * Output   :  0 - 成功，非0 - 失败.
 * Notes    :  一般由设备的DMA中断调用该函数进行中断分配和更新DMA信息.
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_substream_irq_handler(struct sound_pcm_substream *substream);

/*************************************************************************
 * pcm设备设置数据声道分布
 * Input    :  stream  - sound_pcm_stream指针,
 *             map     - 声道分布.
 * Output   :  0 - 成功，非0 - 失败.
 * Notes    :
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_set_data_map(struct sound_pcm_stream *stream, u16 map);

/*************************************************************************
 * pcm设备写入数据
 * Input    :  stream  - sound_pcm_stream指针,
 *             data    - 数字音频数据,
 *             len     - 数据长度.
 * Output   :  实际写入的长度.
 * Notes    :
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_write(struct sound_pcm_stream *stream, void *data, int len);

/*************************************************************************
 * pcm设备io控制函数
 * Input    :  stream  - sound_pcm_stream指针,
 *             cmd     - 命令,
 *             arg     - 参数.
 * Output   :  0 - 成功，非0 - 失败.
 * Notes    :  PCM数据流的ioctl函数(数字音频相关)
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_iotcl(struct sound_pcm_stream *stream, int cmd, void *arg);

/*************************************************************************
 * pcm设备控制器io控制函数
 * Input    :  stream  - sound_pcm_stream指针,
 *             cmd     - 命令,
 *             arg     - 参数.
 * Output   :  0 - 成功，非0 - 失败.
 * Notes    :  PCM设备的控制器ioctl函数(增益/电源等相关)
 * History  :  2021/03/11 by Lichao.
 *=======================================================================*/
int sound_pcm_ctl_ioctl(struct sound_pcm_stream *stream, int cmd, void *arg);
int sound_pcm_read(struct sound_pcm_stream *stream, void *data, int len);
void sound_pcm_free(struct sound_pcm_stream *stream);


void sound_pcm_mount_syncts(struct sound_pcm_stream *stream, void *syncts);
void sound_pcm_unmount_syncts(struct sound_pcm_stream *stream, void *syncts);

#define sound_pcm_set_syncts        sound_pcm_mount_syncts

#endif
