#include "sr_device.h"
#include "sr_osal.h"

#include <string.h>


static os_list_node_t gDeviceList = OS_LIST_INIT(gDeviceList);

/**
 ***********************************************************************************************************************
 * @brief           This function registers a device and places it on the list of device object.
 *
 * @param[in]       dev             The descriptor of device control block.
 * @param[in]       name            Pointer to device name string.
 * @param[in]       flag            Flags of device.
 *
 * @return          Regist result.
 * @retval          SR_OK          Successful.
 * @retval          SR_INVALID       Fail.
 ***********************************************************************************************************************
 */
int SR_DeviceRegister(SR_DEVICE_T *dev, const char *name)
{

    if (dev == SR_NULL)
    {
        return SR_INVALID;
    }

    if ((SR_NULL == name) || (SR_NULL != SR_DeviceFind(name)))
    {
        return SR_INVALID;
    }

    SR_OsEnterCritical();

    dev->name = name;

    dev->refCount  = 0;


    os_list_add(&gDeviceList, &dev->list);
   
    SR_OsExitCritical();

    return SR_OK;
}

/**
 ***********************************************************************************************************************
 * @brief           Find device by name on the device object list .
 *
 * @details         This function will find device by name on the device object list.
 *
 * @param[in]       name            Pointer to device name string.
 *
 * @return          On success, return a device control block descriptor; on error, SR_NULL is returned.
 * @retval          not SR_NULL     Return a task control block descriptor.
 * @retval          SR_NULL         No task to be found.
 ***********************************************************************************************************************
 */
SR_DEVICE_T *SR_DeviceFind(const char *name)
{
    SR_DEVICE_T *dev = SR_NULL;

    SR_OsEnterCritical();

    os_list_for_each_entry(dev, &gDeviceList, SR_DEVICE_T, list)
    {
        if (0 == strncmp(dev->name, name, 16))
        {
            SR_OsExitCritical();
					
			return dev;  
            
        }
    }

    SR_OsExitCritical();
    return SR_NULL;
}

/**
 ***********************************************************************************************************************
 * @brief           This function will open the device through the open function installed on the device.
 *
 * @param[in]       dev             The descriptor of device control block.
 *
 * @return          Open result.
 ***********************************************************************************************************************
 */
int SR_DeviceOpen(SR_DEVICE_T *dev)
{
    int result = SR_OK;

    if (dev == SR_NULL)
    {
        return SR_INVALID;
    }

    SR_OsEnterCritical();

    if (dev->refCount++ == 0)
    {
        if (dev->ops != SR_NULL && dev->ops->open != SR_NULL)
        {
        	SR_OsExitCritical();
            result = dev->ops->open(dev);

			SR_OsEnterCritical();
            if (result != SR_OK)
            {            	 
                //SR_LOG(DEBUG,"Initialize device:%s failed. The error code is %d", SR_DEVICE_NAME(dev), result);
                dev->refCount--;
            }
        }
    }

    SR_OsExitCritical();

    return result;
}


/**
 ***********************************************************************************************************************
 * @brief           This function will close the device through the close function installed on the device.
 *
 * @param[in]       dev             The descriptor of device control block.
 *
 * @return          Close result.
 ***********************************************************************************************************************
 */
int SR_DeviceClose(SR_DEVICE_T *dev)
{
    int result = SR_OK;


    if (dev == SR_NULL)
    {
        return SR_INVALID;
    }

    SR_OsEnterCritical();

    if (dev->refCount == 0)
    {
        SR_OsExitCritical();
        //SR_LOG(DEBUG,"invalid close device %p\r\n", dev);
        return SR_FAIL;
    }

    if (dev->refCount-- > 1)
    {
        SR_OsExitCritical();
        goto end;
    }

    SR_OsExitCritical();

    if (dev->ops != SR_NULL && dev->ops->close != SR_NULL)
    {
        dev->ops->close(dev);
    }


end:

    return result;
}







srSSize_t SR_DeviceRead(SR_DEVICE_T *dev, srOff_t pos, void *buffer, srSize_t size)
{
    if (!dev || !buffer) 
	{
        return -1;
    }

	
	if (dev->refCount == 0)
	{
		//rt_set_errno(-RT_ERROR);
		return 0;
	}

	if (dev->ops->read != SR_NULL)
    {
        return dev->ops->read(dev, pos, buffer, size);
    }
	
    return 0;
}


srSSize_t SR_DeviceWrite(SR_DEVICE_T *dev, srOff_t pos, void *buffer, srSize_t size) 
{
    if (!dev || !buffer) 
	{
        return -1;
    }

	 if (dev->refCount == 0)
    {
        //rt_set_errno(-RT_ERROR);
        return 0;
    }

	 if (dev->ops->write != SR_NULL)
    {
        return dev->ops->write(dev, pos, buffer, size);
    }
	
    return 0;
}



int SR_DeviceControl(SR_DEVICE_T *dev, int cmd, void *arg)
{
    if (!dev) 
	{
        return -1;
    }

	if (dev->ops->control != SR_NULL)
    {
        return dev->ops->control(dev, cmd, arg);
    }

    return SR_NOIMPT;
}
