#include "dev_manager.h"
#include "dev_reg.h"
#include "app_config.h"
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
#include "dev_multiplex_api.h"
#endif
#include "spi/nor_fs.h"
#include "dev_update.h"

// *INDENT-OFF*

#if (TCFG_DEV_MANAGER_ENABLE)

#define DEV_MANAGER_TASK_NAME							"dev_mg"
#define DEV_MANAGER_SCAN_DISK_MAX_DEEPTH				9

///设备管理总控制句柄
struct __dev_manager {
	struct list_head 	list;
	OS_MUTEX			mutex;
	OS_SEM			    sem;
	u32 				counter;
};
static struct __dev_manager dev_mg;
#define __this	(&dev_mg)


///设备节点结构体
struct __dev {
	struct list_head 	entry;
	struct __dev_reg 	*parm;//设备参数
	struct imount 		*fmnt;
	volatile u8			valid:	1;//有效设备标记， 这里有效是指是否有可播放文件
	volatile u32		active_stamp;///活动设备时间戳，通过时间戳记录当前最后活动设备
};


static u32 __dev_manager_get_time_stamp(void)
{
	u32 counter = __this->counter;
	__this->counter ++;
	return counter;
}

int __dev_manager_add(char *logo, u8 need_mount)
{
	if (logo == NULL) {
		return DEV_MANAGER_ADD_ERR_PARM;
	}
	int i;
	printf("%s add start\n", logo);
	struct __dev_reg *p = NULL;
	struct __dev_reg *n;

	for(n=(struct __dev_reg *)dev_reg; n->logo != NULL; n++){
		if (!strcmp(n->logo, logo)) {
			p = n;
			break;
		}
	}

	if (p) {
		///挂载文件系统
		if (dev_manager_list_check_by_logo(logo)) {
			printf("dev online aready, err!!!\n");
			return DEV_MANAGER_ADD_IN_LIST_AREADY;
		}
		struct __dev *dev = (struct __dev *)zalloc(sizeof(struct __dev));
		if(dev == NULL){
			return DEV_MANAGER_ADD_ERR_NOMEM;
		}
		os_mutex_pend(&__this->mutex, 0);
		if(need_mount){
			dev->fmnt = mount(p->name, p->storage_path, p->fs_type, 3, NULL);
		}
		dev->parm = p;
		dev->valid = (dev->fmnt ? 1 : 0);
		dev->active_stamp = __dev_manager_get_time_stamp();//timer_get_ms();
		list_add_tail(&dev->entry, &__this->list);
		os_mutex_post(&__this->mutex);
		printf("%s, %s add ok, dev->fmnt = %x,  %d\n", __FUNCTION__, logo, (int)dev->fmnt, dev->active_stamp);
		if(dev->fmnt == NULL){
			return DEV_MANAGER_ADD_ERR_MOUNT_FAIL;
		}
		return DEV_MANAGER_ADD_OK;
	}
	printf("dev_manager_add can not find logo %s\n",logo);
	return DEV_MANAGER_ADD_ERR_NOT_FOUND;
}

static int __dev_manager_del(char *logo)
{
	if (logo == NULL) {
		return -1;
	}
	struct __dev *dev, *n;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry_safe(dev, n, &__this->list, entry) {
		if (!strcmp(dev->parm->logo, logo)) {
			///卸载文件系统
			if(dev->fmnt){
				unmount(dev->parm->storage_path);
			}
			list_del(&dev->entry);
			free(dev);
			printf("%s, %s del ok\n", __FUNCTION__, logo);
			break;
		}
	}
	os_mutex_post(&__this->mutex);
	return 0;
}

//*----------------------------------------------------------------------------*/
/**@brief    设备增加接口
   @param	 logo:逻辑盘符，如：sd0/sd1/udisk0等
   @return   0:成功，非0是失败
   @note
*/
/*----------------------------------------------------------------------------*/
int dev_manager_add(char *logo)
{
	if(logo == NULL){
		return -1;
	}
	int ret = 0;
#if TCFG_RECORD_FOLDER_DEV_ENABLE
	char rec_dev_logo[16] = {0};
	sprintf(rec_dev_logo, "%s%s", logo, "_rec");
	ret = __dev_manager_add(rec_dev_logo, 1);
	if(ret == DEV_MANAGER_ADD_OK){
		ret = __dev_manager_add(logo, 1);
		if(ret){
			__dev_manager_del(logo);
			__dev_manager_del(rec_dev_logo);
		}
	}else if(ret == DEV_MANAGER_ADD_ERR_NOT_FOUND){
		ret = __dev_manager_add(logo, 1);
	}
	else{
		ret = __dev_manager_add(logo, 0);
	}
#else
	ret = __dev_manager_add(logo, 1);
#endif//TCFG_RECORD_FOLDER_DEV_ENABLE

	return ret;
}

//*----------------------------------------------------------------------------*/
/**@brief    设备删除接口
   @param	 logo:逻辑盘符，如：sd0/sd1/udisk0等
   @return   0:成功，非0是失败
   @note
*/
/*----------------------------------------------------------------------------*/
int dev_manager_del(char *logo)
{
	if(logo == NULL){
		return -1;
	}
	__dev_manager_del(logo);
#if TCFG_RECORD_FOLDER_DEV_ENABLE
    char rec_dev_logo[16] = {0};
	sprintf(rec_dev_logo, "%s%s", logo, "_rec");
	__dev_manager_del(rec_dev_logo);
#endif//TCFG_RECORD_FOLDER_DEV_ENABLE

	return 0;
}
//*----------------------------------------------------------------------------*/
/**@brief    通过设备节点检查设备是否在线
   @param	 dev:设备节点
   @return   成功返回设备节点， 失败返回NULL
   @note     通过设备节点检查设备是否在设备链表中
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_check(struct __dev *dev)
{
	if (dev == NULL) {
		return NULL;
	}
	struct __dev *p;
	list_for_each_entry(p, &__this->list, entry) {
		if(!(p->fmnt)){
			continue;
		}
		if (dev == p) {
			return p;
		}
	}
	return NULL;
}
//*----------------------------------------------------------------------------*/
/**@brief    通过盘符检查设备是否在线
   @param	 logo:逻辑盘符，如:sd0/sd1/udisk0
   @return   成功返回设备节点， 失败返回NULL
   @note     通过设备节点检查设备是否在设备链表中
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_check_by_logo(char *logo)
{
	if (logo == NULL) {
		return NULL;
	}
	struct __dev *dev;
	list_for_each_entry(dev, &__this->list, entry) {
		if(!(dev->fmnt)){
			continue;
		}
		if (!strcmp(dev->parm->logo, logo)) {
			return dev;
		}
	}
	return NULL;
}
//*----------------------------------------------------------------------------*/
/**@brief    获取设备总数
   @param	 valid:
   					1：有效可播放设备, 0;所有设备,包括有可播放设备及无可播放设备
   @return   设备总数
   @note     根据使用情景决定接口参数
*/
/*----------------------------------------------------------------------------*/
u32 dev_manager_get_total(u8 valid)
{
	u32 total_valid = 0;
	u32 total = 0;
	struct __dev *dev;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry(dev, &__this->list, entry) {
		if(!(dev->fmnt)){
			continue;
		}
		if (dev->valid) {
			total_valid++;
		}
		total ++;
	}
	os_mutex_post(&__this->mutex);
	return (valid ? total_valid : total);
}
//*----------------------------------------------------------------------------*/
/**@brief    获取设备列表第一个设备
   @param	 valid:
   					1：有效可播放设备, 0;所有设备,包括有可播放设备及无可播放设备
   @return   成功返回设备设备节点,失败返回NULL
   @note     根据使用情景决定接口参数
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_find_first(u8 valid)
{
	struct __dev *dev = NULL;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry(dev, &__this->list, entry) {
		if(!(dev->fmnt)){
			continue;
		}
		if(valid){
			if (dev->valid) {
				os_mutex_post(&__this->mutex);
				return dev;
			}
		}else{
			os_mutex_post(&__this->mutex);
			return dev;
		}
	}
	os_mutex_post(&__this->mutex);
	return NULL;
}
//*----------------------------------------------------------------------------*/
/**@brief    获取设备列表最后一个设备
   @param	 valid:
   					1：有效可播放设备中查找
					0：所有设备,包括有可播放设备及无可播放设备中查找
   @return   成功返回设备设备节点,失败返回NULL
   @note     根据使用情景决定接口参数
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_find_last(u8 valid)
{
	struct __dev *dev = NULL;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry_reverse(dev, &__this->list, entry) {
		if(!(dev->fmnt)){
			continue;
		}
		if(valid){
			if (dev->valid) {
				os_mutex_post(&__this->mutex);
				return dev;
			}
		}else{
			os_mutex_post(&__this->mutex);
			return dev;
		}
	}
	os_mutex_post(&__this->mutex);
	return NULL;
}
//*----------------------------------------------------------------------------*/
/**@brief    获取上一个设备节点
   @param
   			dev:当前设备节点
			valid:
   					1：有效可播放设备中查找,
					0：所有设备,包括有可播放设备及无可播放设备中查找
   @return   成功返回设备设备节点,失败返回NULL
   @note     根据当前设置的参数设备节点，找链表中的上一个设备
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_find_prev(struct __dev *dev, u8 valid)
{
	if (dev == NULL) {
		return NULL;
	}
	struct __dev *p = NULL;
	os_mutex_pend(&__this->mutex, 0);
	if (dev_manager_check(dev) == NULL) {
		///传入的参数无效， 返回活动设备
		os_mutex_post(&__this->mutex);
		return dev_manager_find_active(valid);
	}
	list_for_each_entry(p, &dev->entry, entry) {
        if((void*)p == (void*)(&__this->list)){
            continue;
        }
        if(!(p->fmnt)){
			continue;
		}
		if(valid){
			if (p->valid) {
				os_mutex_post(&__this->mutex);
				return p;
			}
		}else{
			os_mutex_post(&__this->mutex);
			return p;
		}
	}
	os_mutex_post(&__this->mutex);
	return NULL;
}
//*----------------------------------------------------------------------------*/
/**@brief    获取下一个设备节点
   @param
   			dev:当前设备节点
			valid:
   					1：有效可播放设备中查找,
					0：所有设备,包括有可播放设备及无可播放设备中查找
   @return   成功返回设备设备节点,失败返回NULL
   @note     根据当前设置的参数设备节点，找链表中的下一个设备
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_find_next(struct __dev *dev, u8 valid)
{
	if (dev == NULL) {
		return NULL;
	}
	struct __dev *p = NULL;
	os_mutex_pend(&__this->mutex, 0);
	if (dev_manager_check(dev) == NULL) {
		///传入的参数无效， 返回活动设备
		os_mutex_post(&__this->mutex);
		return dev_manager_find_active(valid);
	}

	list_for_each_entry_reverse(p, &dev->entry, entry) {
        if((void*)p == (void*)(&__this->list)){
            continue;
        }
		if(!(p->fmnt)){
			continue;
		}
		if(valid){
			if (p->valid) {
				os_mutex_post(&__this->mutex);
				return p;
			}
		}else{
			os_mutex_post(&__this->mutex);
			return p;
		}
	}
	os_mutex_post(&__this->mutex);
	return NULL;
}
//*----------------------------------------------------------------------------*/
/**@brief    获取当前活动设备节点
   @param
			valid:
   					1：有效可播放设备中查找,
					0：所有设备,包括有可播放设备及无可播放设备中查找
   @return   成功返回设备设备节点,失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_find_active(u8 valid)
{
	struct __dev *dev = NULL;
	struct __dev *active = NULL;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry(dev, &__this->list, entry) {
		if(!(dev->fmnt)){
			continue;
		}
		if(valid){
			if (dev->valid) {
				if (active) {
					if (active->active_stamp < dev->active_stamp) {
						active = dev;
					}
				} else {
					active = dev;
				}
			}
		}else{
			if (active) {
				if (active->active_stamp < dev->active_stamp) {
					active = dev;
				}
			} else {
				active = dev;
			}

		}
	}
	os_mutex_post(&__this->mutex);
	return active;
}
//*----------------------------------------------------------------------------*/
/**@brief    获取指定设备节点
   @param
   			logo：指定逻辑盘符，如：sd0/sd1/udisk0
			valid:
   					1：有效可播放设备中查找,
					0：所有设备,包括有可播放设备及无可播放设备中查找
   @return   成功返回设备设备节点,失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_find_spec(char *logo, u8 valid)
{
	if (logo == NULL) {
		return NULL;
	}
	struct __dev *dev = NULL;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry(dev, &__this->list, entry) {
		if(!(dev->fmnt)){
			continue;
		}
		if (!strcmp(dev->parm->logo, logo)) {
			if(valid){
				if (dev->valid) {
					os_mutex_post(&__this->mutex);
					return dev;
				}
			}else{
				os_mutex_post(&__this->mutex);
				return dev;
			}
		}
	}
	os_mutex_post(&__this->mutex);
	return NULL;
}
//*----------------------------------------------------------------------------*/
/**@brief    获取指定序号设备节点
   @param
   			index：指定序号，指的是在设备链表中的顺序
			valid:
   					1：有效可播放设备中查找,
					0：所有设备,包括有可播放设备及无可播放设备中查找
   @return   成功返回设备设备节点,失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_find_by_index(u32 index, u8 valid)
{
	struct __dev *dev = NULL;
	u32 i = 0;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry(dev, &__this->list, entry) {
		if(!(dev->fmnt)){
			continue;
		}
		if(valid){
			if (dev->valid) {
				if (i == index) {
					os_mutex_post(&__this->mutex);
					return dev;
				}
				i++;
			}
		}else{
			if (i == index) {
				os_mutex_post(&__this->mutex);
				return dev;
			}
			i++;
		}
	}
	os_mutex_post(&__this->mutex);
	return NULL;
}
//*----------------------------------------------------------------------------*/
/**@brief   设备扫盘释放
   @param
   			fsn：扫描句柄
   @return  无
   @note
*/
/*----------------------------------------------------------------------------*/
void dev_manager_scan_disk_release(struct vfscan *fsn)
{
	if (fsn) {
		fscan_release(fsn);
	}
}
//*----------------------------------------------------------------------------*/
/**@brief   设备扫盘
   @param
   			dev：设备节点
   			path：指定扫描目录
   			parm：扫描参数，包括文件后缀等
   			cycle_mode：播放循环模式
			callback：扫描打断回调
   @return  成功返回扫描控制句柄，失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
struct vfscan *dev_manager_scan_disk(struct __dev *dev, const char *path, const char *parm, u8 cycle_mode, struct __scan_callback *callback)
{
	if (dev_manager_check(dev) == NULL) {
		return NULL;
	}
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0

#if (TCFG_DM_MULTIPLEX_WITH_SD_PORT == 0)     //0:sd0  1:sd1 //dm 参与复用的sd配置
        if(!memcmp(dev->parm->logo ,"sd0",strlen("sd0"))){
#else
        if(!memcmp(dev->parm->logo ,"sd1",strlen("sd1"))){
#endif
            dev_usb_change_sd();
        }

    if(!memcmp(dev->parm->logo ,"udisk",strlen("udisk")))
        dev_sd_change_usb();

    if (dev_manager_online_check(dev, 1) == NULL) {
        printf("mult remount fail !!!\n");
        return NULL;
    }
#endif
	char *fsn_path = NULL;
	char *tmp_path = NULL;
	if (path) {
		if (*path == '/') {
			path++;
		}
		tmp_path = zalloc(strlen(dev->parm->root_path) + strlen(path) + 1);
		if (tmp_path == NULL) {
			return NULL;
		}
		sprintf(tmp_path, "%s%s", dev->parm->root_path, path);
		fsn_path = tmp_path;
	} else {
		fsn_path = dev->parm->root_path;
	}
	printf("fsn_path = %s, scan parm = %s\n", fsn_path, parm);
	struct vfscan *fsn;
	/* clock_add_set(SCAN_DISK_CLK); */
	if(callback && callback->enter){
		callback->enter(dev);//扫描前处理， 可以在注册的回调里提高系统时钟等处理
	}
	fsn = fscan_interrupt(
			(const char *)fsn_path,
			parm,
			DEV_MANAGER_SCAN_DISK_MAX_DEEPTH,
			((callback) ? callback->scan_break : NULL));
	/* clock_remove_set(SCAN_DISK_CLK); */
	if(callback && callback->exit){
		callback->exit(dev);//扫描后处理， 可以在注册的回调里还原到enter前的状态
	}
	if (fsn) {
		if (fsn->file_number == 0) {
			printf("dev nofile\n");
#if (TCFG_DEV_UPDATE_IF_NOFILE_ENABLE)
			///没有文件找升级文件
			dev_update_check(dev->parm->logo);
#endif/*TCFG_DEV_UPDATE_IF_NOFILE_ENABLE*/
			///没有文件,释放fsn， 减少外面流程的处理
			dev_manager_scan_disk_release(fsn);
			fsn = NULL;
		} else {
			fsn->cycle_mode = cycle_mode;
		}
	}

	if (tmp_path) {
		free(tmp_path);
	}
	return fsn;
}
//*----------------------------------------------------------------------------*/
/**@brief   通过设备节点标记指定设备是否有效
   @param
   			dev：设备节点
			flag:
   					1：设备有效,
					0：设备无效
   @return
   @note    这里有无效是指是否有可播放文件
*/
/*----------------------------------------------------------------------------*/
void dev_manager_set_valid(struct __dev *dev, u8 flag)
{
	os_mutex_pend(&__this->mutex, 0);
	if (dev_manager_check(dev)) {
		dev->valid = flag;
	}
	os_mutex_post(&__this->mutex);
}
//*----------------------------------------------------------------------------*/
/**@brief   通过逻辑盘符标记指定设备是否有效
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
			flag:
   					1：设备有效,
					0：设备无效
   @return
   @note    这里有无效是指是否有可播放文件
*/
/*----------------------------------------------------------------------------*/
void dev_manager_set_valid_by_logo(char *logo, u8 flag)
{
	if (logo == NULL) {
		return ;
	}
	struct __dev *dev = NULL;
	os_mutex_pend(&__this->mutex, 0);
	dev = dev_manager_check_by_logo(logo);
	if (dev) {
		dev->valid = flag;
	}
	os_mutex_post(&__this->mutex);
}
//*----------------------------------------------------------------------------*/
/**@brief   激活指定设备节点的设备
   @param
   			dev：设备节点
   @return
   @note    该接口可以将设备变为最新活动设备
*/
/*----------------------------------------------------------------------------*/
void dev_manager_set_active(struct __dev *dev)
{
	os_mutex_pend(&__this->mutex, 0);
	if (dev_manager_check(dev)) {
		dev->active_stamp = __dev_manager_get_time_stamp();//timer_get_ms();
	}
	os_mutex_post(&__this->mutex);
}
//*----------------------------------------------------------------------------*/
/**@brief   激活指定逻辑盘符的设备
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
   @return
   @note    该接口可以将设备变为最新活动设备
*/
/*----------------------------------------------------------------------------*/
void dev_manager_set_active_by_logo(char *logo)
{
	if (logo == NULL) {
		return ;
	}
	struct __dev *dev = NULL;
	os_mutex_pend(&__this->mutex, 0);
	dev = dev_manager_check_by_logo(logo);
	if (dev) {
		dev->active_stamp = __dev_manager_get_time_stamp();//timer_get_ms();
	}
	os_mutex_post(&__this->mutex);
}
//*----------------------------------------------------------------------------*/
/**@brief   获取设备节点的逻辑盘符
   @param
   			dev：设备节点
   @return  成功返回逻辑盘符，如：sd0/sd1/udisk0，失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
char *dev_manager_get_logo(struct __dev *dev)
{
	char *logo = NULL;
	os_mutex_pend(&__this->mutex, 0);
	if (dev_manager_check(dev) == NULL) {
		os_mutex_post(&__this->mutex);
		return NULL;
	}
	logo = dev->parm->logo;
	os_mutex_post(&__this->mutex);
	return logo;
}
//*----------------------------------------------------------------------------*/
/**@brief   获取物理设备节点的逻辑盘符(去掉_rec后缀)
   @param
   			dev：设备节点
   @return  成功返回逻辑盘符，如：sd0/sd1/udisk0，失败返回NULL
   @note    物理逻辑盘符是指非录音文件夹设备盘符(录音文件夹设备如：sd0_rec)
*/
/*----------------------------------------------------------------------------*/
char *dev_manager_get_phy_logo(struct __dev *dev)
{
    char *logo = dev_manager_get_logo(dev);
    char phy_dev_logo[16] = {0};
    if (logo) {
        char *str = strstr(logo, "_rec");
        if (str) {
            strncpy(phy_dev_logo, logo, strlen(logo) - strlen(str));
			struct __dev *phy_dev = dev_manager_find_spec(phy_dev_logo, 0);
			return dev_manager_get_logo(phy_dev);
        }
	}
	return logo;
}
//*----------------------------------------------------------------------------*/
/**@brief   获取录音文件夹设备节点的逻辑盘符(追加_rec后缀)
   @param
   			dev：设备节点
   @return  成功返回逻辑盘符，如：sd0_rec/sd1_rec/udisk0_rec，失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
char *dev_manager_get_rec_logo(struct __dev *dev)
{
    char *logo = dev_manager_get_logo(dev);
    char rec_dev_logo[16] = {0};
    if (logo) {
        char *str = strstr(logo, "_rec");
		if (!str) {
			sprintf(rec_dev_logo, "%s%s", logo, "_rec");
			struct __dev *rec_dev = dev_manager_find_spec(rec_dev_logo, 0);
			return dev_manager_get_logo(rec_dev);
        }
	}
	return logo;
}
//*----------------------------------------------------------------------------*/
/**@brief   通过设备节点获取设备文件系统根目录
   @param
   			dev：设备节点
   @return  成功返回根目录，失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
char *dev_manager_get_root_path(struct __dev *dev)
{
	char *path = NULL;
	os_mutex_pend(&__this->mutex, 0);
	if (dev_manager_check(dev) == NULL) {
		os_mutex_post(&__this->mutex);
		return NULL;
	}
	path = dev->parm->root_path;
	os_mutex_post(&__this->mutex);
	return path;
}
//*----------------------------------------------------------------------------*/
/**@brief   通过逻辑盘符获取设备文件系统根目录
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
   @return  成功返回根目录，失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
char *dev_manager_get_root_path_by_logo(char *logo)
{
	char *path = NULL;
	os_mutex_pend(&__this->mutex, 0);
	struct __dev *dev = dev_manager_check_by_logo(logo);
	if (dev == NULL) {
		os_mutex_post(&__this->mutex);
		return NULL;
	}
	path = dev->parm->root_path;
	os_mutex_post(&__this->mutex);
	return path;
}

//*----------------------------------------------------------------------------*/
/**@brief   通过设备节点获取设备mount信息
   @param
            dev：设备节点
   @return  成功返回对应指针，失败返回NULL
   @note
*/
/*----------------------------------------------------------------------------*/
struct imount *dev_manager_get_mount_hdl(struct __dev *dev)
{
    if (dev == NULL) {
        return NULL;
    }else{
        return dev->fmnt;
    }
}
//*----------------------------------------------------------------------------*/
/**@brief   通过逻辑盘符判断设备是否在线
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
			valid：
				1：检查有效可播放设备
				0：检查所有设备
   @return  1：在线 0：不在线
   @note
*/
/*----------------------------------------------------------------------------*/
int dev_manager_online_check_by_logo(char *logo, u8 valid)
{
	struct __dev *dev = dev_manager_find_spec(logo, valid);
	return (dev ? 1 : 0);
}
//*----------------------------------------------------------------------------*/
/**@brief   通过设备节点判断设备是否在线
   @param
   			dev：设备节点
			valid：
				1：检查有效可播放设备
				0：检查所有设备
   @return  1：在线 0：不在线
   @note
*/
/*----------------------------------------------------------------------------*/
int dev_manager_online_check(struct __dev *dev, u8 valid)
{
	if (dev_manager_check(dev) == NULL) {
		return 0;
	}else{
		if(valid){
			return (dev->valid ? 1 : 0);
		}else{
			return 1;
		}
	}
}

//*----------------------------------------------------------------------------*/
/**@brief   通过逻辑盘符判断设备是否在设备链表中
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
   @return  1：在设备链表中， 0：不在设备链表中
   @note	该接口会检查所有在设备链表中的设备，忽略mount，valid等状态
*/
/*----------------------------------------------------------------------------*/
struct __dev *dev_manager_list_check_by_logo(char *logo)
{
	if (logo == NULL) {
		return 0;
	}
	struct __dev *dev;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry(dev, &__this->list, entry) {
		if (!strcmp(dev->parm->logo, logo)) {
			os_mutex_post(&__this->mutex);
			return dev;
		}
	}
	os_mutex_post(&__this->mutex);
	return NULL;
}

//*----------------------------------------------------------------------------*/
/**@brief   检查链表中没有挂载的设备并重新挂载
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
   @return  1：在设备链表中， 0：不在设备链表中
   @note	该接口会检查所有在设备链表中的设备，忽略mount，valid等状态
*/
/*----------------------------------------------------------------------------*/
void dev_manager_list_check_mount(void)
{
	struct __dev *dev;
	os_mutex_pend(&__this->mutex, 0);
	list_for_each_entry(dev, &__this->list, entry) {
		if(dev->valid == 0){
			if(dev->fmnt){
				unmount(dev->parm->storage_path);
				dev->fmnt = NULL;
			}
		}
		if(dev->fmnt == NULL){
			struct __dev_reg *p = dev->parm;
			dev->fmnt = mount(p->name, p->storage_path, p->fs_type, 3, NULL);
			dev->valid = (dev->fmnt ? 1 : 0);
		}
	}
	os_mutex_post(&__this->mutex);
}

//*----------------------------------------------------------------------------*/
/**@brief   设备挂载
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
   @return  0：成功， -1：失败
   @note	需要主动mount设备可以调用改接口
*/
/*----------------------------------------------------------------------------*/
static int __dev_manager_mount(char *logo)
{
	int ret = 0;
	os_mutex_pend(&__this->mutex, 0);
	struct __dev *dev = dev_manager_list_check_by_logo(logo);
	if (dev == NULL) {
		os_mutex_post(&__this->mutex);
		return -1;
	}
	if(dev->fmnt == NULL){
		struct __dev_reg *p = dev->parm;
		dev->fmnt = mount(p->name, p->storage_path, p->fs_type, 3, NULL);
		dev->valid = (dev->fmnt ? 1 : 0);
	}
	ret = (dev->valid ? 0 : -1);
	os_mutex_post(&__this->mutex);
	return ret;
}
//*----------------------------------------------------------------------------*/
/**@brief   设备卸载
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
   @return  0：成功， -1：失败
   @note	需要主动unmount设备可以调用改接口
*/
/*----------------------------------------------------------------------------*/
static int __dev_manager_unmount(char *logo)
{
	os_mutex_pend(&__this->mutex, 0);
	struct __dev *dev = dev_manager_check_by_logo(logo);
	if (dev == NULL) {
		os_mutex_post(&__this->mutex);
		return -1;
	}
	if(dev->fmnt){
		unmount(dev->parm->storage_path);
		dev->fmnt = NULL;
	}
	dev->valid = 0;
	os_mutex_post(&__this->mutex);
	return 0;
}

//*----------------------------------------------------------------------------*/
/**@brief   设备挂载
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
   @return  0：成功， -1：失败
   @note	慎用
*/
/*----------------------------------------------------------------------------*/
int dev_manager_mount(char *logo)
{
	int ret = __dev_manager_mount(logo);
	if(ret == 0){
#if TCFG_RECORD_FOLDER_DEV_ENABLE
		char rec_dev_logo[16] = {0};
		sprintf(rec_dev_logo, "%s%s", logo, "_rec");
		ret = __dev_manager_mount(rec_dev_logo);
		if(ret){
			__dev_manager_unmount(logo);
		}
#endif
	}
	return ret;
}

//*----------------------------------------------------------------------------*/
/**@brief   设备卸载
   @param
   			logo：逻辑盘符，如：sd0/sd1/udisk0
   @return  0：成功， -1：失败
   @note	慎用
*/
/*----------------------------------------------------------------------------*/
int dev_manager_unmount(char *logo)
{
#if TCFG_RECORD_FOLDER_DEV_ENABLE
	char rec_dev_logo[16] = {0};
	sprintf(rec_dev_logo, "%s%s", logo, "_rec");
	__dev_manager_unmount(rec_dev_logo);
#endif
	__dev_manager_unmount(logo);
	return 0;
}


//*----------------------------------------------------------------------------*/
/**@brief   设备检测线程处理
   @param
   @return
   @note
*/
/*----------------------------------------------------------------------------*/
extern void hidden_file(u8 flag);
static void dev_manager_task(void *p)
{
	int res = 0;
	int msg[8] = {0};
	///过滤隐藏 和 .开头名名的字文件
	hidden_file(1);
	///设备初始化，
	devices_init();

#if SDFILE_STORAGE && TCFG_CODE_FLASH_ENABLE
	dev_manager_add(SDFILE_DEV);
#endif

#if TCFG_NOR_REC
	dev_manager_add("rec_nor");
#endif

#if TCFG_NOR_FAT
    dev_manager_add("fat_nor");
#endif

#if TCFG_NOR_FS
	dev_manager_add("res_nor");
#endif

#if TCFG_VIR_UDISK_ENABLE
	dev_manager_add("vir_udisk0");
#endif

#if TCFG_VIRFAT_FLASH_ENABLE
	dev_manager_add("virfat_flash");
    dev_manager_set_valid_by_logo("virfat_flash", 0);///将设备设置为无效设备
#endif

#if FLASH_INSIDE_REC_ENABLE
    set_rec_capacity(512*1024);//需要先设置容量,注意要小于Ini文件设置大小.
    _sdfile_rec_init();
	dev_manager_add("rec_sdfile");
#endif

	os_sem_post(&__this->sem);

	while (1) {
		res = os_task_pend("taskq", msg, ARRAY_SIZE(msg));
		switch (res) {
			case OS_TASKQ:
				switch (msg[0]) {
					case Q_EVENT:
						break;
					case Q_MSG:
						break;
					default:
						break;
				}
				break;
			default:
				break;
		}
	}
}

void dev_manager_var_init()
{
	memset(__this, 0, sizeof(struct __dev_manager));
	INIT_LIST_HEAD(&__this->list);
	os_mutex_create(&__this->mutex);
}

#endif/*TCFG_DEV_MANAGER_ENABLE*/
//*----------------------------------------------------------------------------*/
/**@brief   设备管理器初始化
   @param
   @return
   @note
*/
/*----------------------------------------------------------------------------*/
void dev_manager_init(void)
{
#if (TCFG_DEV_MANAGER_ENABLE)
    dev_manager_var_init();

	os_sem_create(&__this->sem, 0);

	int err = task_create(dev_manager_task, NULL, DEV_MANAGER_TASK_NAME);
	if (err != OS_NO_ERR) {
		ASSERT(0, "task_create fail!!! %x\n", err);
	}
	os_sem_pend(&__this->sem, 0);
#else
	devices_init();
#endif
}

