打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

概念

ioctl 是设备驱动程序中设备控制接口函数,一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。

ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的调用个数如下:
int ioctl(int fd, ind cmd, …);
其中fd是用户程序打开设备时使用open函数返回的文件标示符,cmd是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,这个参数的有无和cmd的意义相关。
ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数来控制设备的I/O通道。

ioctl的必要性

如果不用ioctl的话,也可以实现对设备I/O通道的控制,但那是蛮拧了。
例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数 据流通过,如果有的话,那么后面就跟着控制命令(一般在socket编程中常常这样做)。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员 自己也会头昏眼花的。所以,我们就使用ioctl来实现控制的功能。要记住,用户程序所作的只是通过命令码(cmd)告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。

在这里插入图片描述

在计算机中,ioctl(input/output control)是一个专用于设备输入输出操作的系统调用,该调用传入一个跟设备有关的请求码,系统调用的功能完全取决于请求码。举个例子,CD-ROM驱动程序可以弹出光驱,它就提供了一个对应的Ioctl请求码。设备无关的请求码则提供了内核调用权限。ioctl这名字第一次出现在Unix第七版中,他在很多类unix系统(比如Linux、Mac OSX等)都有提供,不过不同系统的请求码对应的设备有所不同。Microsoft Windows在Win32 API里提供了相似的函数,叫做DeviceIoControl。

功能和接口基本相同,名字发生了变化.
ioctl既可以往内核读也可以写,read/write在执行大数据量读/写时比较有优势。
在应用层调用ioctl函数时,内核会调用对应驱动中的ublocked_ioctl函数,向内核读写数据。

/**
 * operations set for device object
 */
struct device_ops_s
{
    int32_t (*open)(device_t *dev);
    int32_t (*close)(device_t *dev);
    xssize_t (*read)(device_t *dev, char *buffer, xsize_t size, xloff_t *pos);
    xssize_t (*write)(device_t *dev, const char *buffer, xsize_t size, xloff_t *pos);
    int32_t (*ioctl)(device_t *dev, uint32_t cmd, void *args);
};

#include "errorno.h"

#include "device.h"

#define DEVICE_ENTER_CRITICAL()
#define DEVICE_EXIT_CRITICAL()

#define device_ops_open             (dev->dev_ops->open)
#define device_ops_close            (dev->dev_ops->close)
#define device_ops_read             (dev->dev_ops->read)
#define device_ops_write            (dev->dev_ops->write)
#define device_ops_ioctl            (dev->dev_ops->ioctl)

/**
 * This function finds a device driver by specified name.
 *
 * @param name the device driver's name
 *
 * @return the registered device driver on successful, or NULL on failure.
 */
device_t* device_find(const char *name)
{
    device_t *obj;
    obj = (device_t*)object_find(OBJECT_CLASS_DEVICE, name);
    return obj;
}

/**
 * This function registers a device driver with specified name.
 *
 * @param dev the pointer of device driver structure
 * @param name the device driver's name
 * @param flags the capabilities flag of device
 *
 * @return the error code, EOK on initialization successfully.
 */
int32_t device_register(device_t *dev, const char *name, xflag_t flags)
{
    int32_t ret;

    if (dev == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (device_find(name) != NULL)
    {
        return RETVAL(E_FAIL);
    }

    dev->flag = flags;
    dev->oflag = DEVICE_OFLAG_CLOSE;
    dev->ref_cnt = 0;

    ret = object_attack(&(dev->obj), OBJECT_CLASS_DEVICE, name);

    return ret;
}

/**
 * This function removes a previously registered device driver
 *
 * @param dev the pointer of device driver structure
 *
 * @return the error code, EOK on successfully.
 */
int32_t device_unregister(device_t *dev)
{
    int32_t ret;

    if (dev == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (object_get_type(&(dev->obj)) != OBJECT_CLASS_DEVICE)
    {
        return RETVAL(E_NO_DEV);
    }

    ret = object_detach(&(dev->obj));

    return ret;
}

/**
 * This function will open a device
 *
 * @param dev the pointer of device driver structure
 * @param oflag the flags for device open
 *
 * @return the result
 */
int32_t device_open(device_t *dev, xflag_t oflag)
{
    int32_t ret = RETVAL(E_OK);

    if (dev == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (object_get_type(&(dev->obj)) != OBJECT_CLASS_DEVICE)
    {
        return RETVAL(E_NO_DEV);
    }

    /* device is a stand alone device and opened */
    if ((dev->flag & DEVICE_FLAG_STANDALONE) &&
        (dev->oflag & DEVICE_OFLAG_OPEN))
    {
        return RETVAL(E_BUSY);
    }

    /* call device_open interface */
    if (device_ops_open != NULL)
    {
        ret = device_ops_open(dev);
    }
    else
    {
        /* set open flag */
        dev->oflag = (oflag & DEVICE_OFLAG_MASK);
    }

    /* set open flag */
    if (ret == RETVAL(E_OK))
    {
        dev->oflag |= DEVICE_OFLAG_OPEN;
        dev->ref_cnt ++;
    }

    return ret;
}

/**
 * This function will close a device
 *
 * @param dev the pointer of device driver structure
 *
 * @return the result
 */
int32_t device_close(device_t *dev)
{
    int32_t ret = RETVAL(E_OK);

    if (dev == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (object_get_type(&(dev->obj)) != OBJECT_CLASS_DEVICE)
    {
        return RETVAL(E_NO_DEV);
    }

    if (dev->ref_cnt == 0)
    {
        return RETVAL(E_STATE);
    }

    dev->ref_cnt --;
    if (dev->ref_cnt != 0)
    {
        return RETVAL(E_OK);
    }

    /* call device_close interface */
    if (device_ops_close != NULL)
    {
        ret = device_ops_close(dev);
    }

    /* set open flag */
    if (ret == RETVAL(E_OK))
    {
        dev->oflag = DEVICE_OFLAG_CLOSE;
    }

    return ret;
}

/**
 * This function will read some data from a device.
 *
 * @param dev the pointer of device driver structure
 * @param pos the position of reading
 * @param buffer the data buffer to save read data
 * @param size the size of buffer
 *
 * @return the actually read size on successful, otherwise negative returned.
 *
 * @note since 0.4.0, the unit of size/pos is a block for block device.
 */
xssize_t device_read(device_t *dev, char *buffer, xsize_t size, xloff_t *pos)
{
    if (dev == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (object_get_type(&(dev->obj)) != OBJECT_CLASS_DEVICE)
    {
        return RETVAL(E_NO_DEV);
    }

    if (dev->ref_cnt == 0)
    {
        return RETVAL(E_STATE);
    }

    /* call device_read interface */
    if (device_ops_read != NULL)
    {
        return device_ops_read(dev, buffer, size, pos);
    }

    return RETVAL(E_NOT_SUPPORT);
}

/**
 * This function will write some data to a device.
 *
 * @param dev the pointer of device driver structure
 * @param pos the position of written
 * @param buffer the data buffer to be written to device
 * @param size the size of buffer
 *
 * @return the actually written size on successful, otherwise negative returned.
 *
 * @note since 0.4.0, the unit of size/pos is a block for block device.
 */
xssize_t device_write(device_t *dev, const char *buffer, xsize_t size, xloff_t *pos)
{
    if (dev == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (object_get_type(&(dev->obj)) != OBJECT_CLASS_DEVICE)
    {
        return RETVAL(E_NO_DEV);
    }

    if (dev->ref_cnt == 0)
    {
        return RETVAL(E_STATE);
    }

    /* call device_write interface */
    if (device_ops_write != NULL)
    {
        return device_ops_write(dev, buffer, size, pos);
    }

    return RETVAL(E_NOT_SUPPORT);
}

/**
 * This function will perform a variety of control functions on devices.
 *
 * @param dev the pointer of device driver structure
 * @param cmd the command sent to device
 * @param arg the argument of command
 *
 * @return the result
 */
int32_t device_ioctl(device_t *dev, int cmd, void *arg)
{
    if (dev == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (object_get_type(&(dev->obj)) != OBJECT_CLASS_DEVICE)
    {
        return RETVAL(E_NO_DEV);
    }

    if (dev->ref_cnt == 0)
    {
        return RETVAL(E_STATE);
    }

    /* call device_write interface */
    if (device_ops_ioctl != NULL)
    {
        return device_ops_ioctl(dev, cmd, arg);
    }

    return RETVAL(E_NOT_SUPPORT);
}

#ifndef _DEVICE_H_
#define _DEVICE_H_

#include "typedefs.h"
#include "object.h"
#include "driver.h"

/**
 * device flags defitions
 */
#define DEVICE_FLAG_DEACTIVATE          0x0000  /**< device is not not initialized */

#define DEVICE_FLAG_RDONLY              0x0001  /**< read only */
#define DEVICE_FLAG_WRONLY              0x0002  /**< write only */
#define DEVICE_FLAG_RDWR                0x0003  /**< read and write */

#define DEVICE_FLAG_REMOVABLE           0x0004  /**< removable device */
#define DEVICE_FLAG_STANDALONE          0x0008  /**< standalone device */
#define DEVICE_FLAG_ACTIVATED           0x0010  /**< device is activated */
#define DEVICE_FLAG_SUSPENDED           0x0020  /**< device is suspended */
#define DEVICE_FLAG_STREAM              0x0040  /**< stream mode */

#define DEVICE_FLAG_INT_RX              0x0100  /**< INT mode on Rx */
#define DEVICE_FLAG_DMA_RX              0x0200  /**< DMA mode on Rx */
#define DEVICE_FLAG_INT_TX              0x0400  /**< INT mode on Tx */
#define DEVICE_FLAG_DMA_TX              0x0800  /**< DMA mode on Tx */

#define DEVICE_OFLAG_CLOSE              0x0000  /**< device is closed */
#define DEVICE_OFLAG_RDONLY             0x0001  /**< read only access */
#define DEVICE_OFLAG_WRONLY             0x0002  /**< write only access */
#define DEVICE_OFLAG_RDWR               0x0003  /**< read and write */
#define DEVICE_OFLAG_OPEN               0x0008  /**< device is opened */
#define DEVICE_OFLAG_MASK               0x0F0F  /**< mask of open flag */

/**
 * general device commands
 */
#define DEVICE_CTRL_RESUME              0x0100  /**< resume device */
#define DEVICE_CTRL_SUSPEND             0x0200  /**< suspend device */
#define DEVICE_CTRL_CONFIG              0x0300  /**< configure device */
#define DEVICE_CTRL_STATE               0x0400  /**< get device state */

#define DEVICE_CTRL_SET_INT             0x1000  /**< set interrupt */
#define DEVICE_CTRL_CLR_INT             0x1100  /**< clear interrupt */
#define DEVICE_CTRL_GET_INT             0x1200  /**< get interrupt status */

/**
 * special device commands
 */
#define DEVICE_CTRL_CHAR_STREAM         0x3000  /**< stream mode on char device */

#define DEVICE_CTRL_BLK_GETGEOME        0x4000  /**< get geometry information   */
#define DEVICE_CTRL_BLK_SYNC            0x4100  /**< flush data to block device */
#define DEVICE_CTRL_BLK_ERASE           0x4200  /**< erase block on block device */
#define DEVICE_CTRL_BLK_AUTOREFRESH     0x4300  /**< block device : enter/exit auto refresh mode */

#define DEVICE_CTRL_NETIF_GETMAC        0x5000  /**< get mac address */

#define DEVICE_CTRL_MTD_FORMAT          0x6000  /**< format a MTD device */

#define DEVICE_CTRL_RTC_GET_TIME        0x7000  /**< get time */
#define DEVICE_CTRL_RTC_SET_TIME        0x7100  /**< set time */
#define DEVICE_CTRL_RTC_GET_ALARM       0x7200  /**< get alarm */
#define DEVICE_CTRL_RTC_SET_ALARM       0x7300  /**< set alarm */

/**
 * device (I/O) class type
 */
typedef enum
{
    DEVICE_CLASS_CHAR,                          /**< character device */
    DEVICE_CLASS_BLOCK,                         /**< block device */
    DEVICE_CLASS_NETIF,                         /**< net interface */
    DEVICE_CLASS_MTD,                           /**< memory device */
    DEVICE_CLASS_CAN,                           /**< CAN device */
    DEVICE_CLASS_RTC,                           /**< RTC device */
    DEVICE_CLASS_SOUND,                         /**< Sound device */
    DEVICE_CLASS_GRAPHIC,                       /**< Graphic device */
    DEVICE_CLASS_I2C_BUS,                       /**< I2C bus device */
    DEVICE_CLASS_USB_DEVICE,                    /**< USB slave device */
    DEVICE_CLASS_USB_HOST,                      /**< USB host bus */
    DEVICE_CLASS_SPI_BUS,                       /**< SPI bus device */
    DEVICE_CLASS_SPI_DEVICE,                    /**< SPI device */
    DEVICE_CLASS_SDIO,                          /**< SDIO bus device */
    DEVICE_CLASS_PM,                            /**< PM pseudo device */
    DEVICE_CLASS_PIPE,                          /**< Pipe device */
    DEVICE_CLASS_PORTAL,                        /**< Portal device */
    DEVICE_CLASS_TIMER,                         /**< Timer device */
    DEVICE_CLASS_MISCELLANEOUS,                 /**< Miscellaneous device */
    DEVICE_CLASS_SENSOR,                        /**< Sensor device */
    DEVICE_CLASS_TOUCH,                         /**< Touch device */
    DEVICE_CLASS_UNKNOWN                        /**< unknown device */
} device_class_t;

typedef struct device_s device_t;
typedef struct device_ops_s device_ops_t;

/**
 * operations set for device object
 */
struct device_ops_s
{
    int32_t (*open)(device_t *dev);
    int32_t (*close)(device_t *dev);
    xssize_t (*read)(device_t *dev, char *buffer, xsize_t size, xloff_t *pos);
    xssize_t (*write)(device_t *dev, const char *buffer, xsize_t size, xloff_t *pos);
    int32_t (*ioctl)(device_t *dev, uint32_t cmd, void *args);
};

/**
 * Device structure
 */
struct device_s
{
    object_t            obj;                    /**< inherit from rt_object */

    device_class_t      type;                   /**< device type */
    xflag_t             flag;                   /**< device flag */
    xflag_t             oflag;                  /**< device open flag */

    uint8_t             ref_cnt;                /**< reference count */
    uint8_t             dev_id;                 /**< 0 - 255 */

    const device_ops_t  *dev_ops;               /**< common device interface */
    driver_t            *dev_drv;               /**< device driver */
    void                *dev_data;              /**< device private data */
};

int32_t device_register(device_t *dev, const char *name, xflag_t flags);
int32_t device_unregister(device_t *dev);

device_t* device_find(const char *name);
int32_t device_open(device_t *dev, xflag_t oflag);
int32_t device_close(device_t *dev);
xssize_t device_read(device_t *dev, char *buffer, xsize_t size, xloff_t *pos);
xssize_t device_write(device_t *dev, const char *buffer, xsize_t size, xloff_t *pos);
int32_t device_ioctl(device_t *dev, int cmd, void *arg);

#endif // _DEVICE_H_


#include "errorno.h"

#include "driver.h"

#define DRIVER_ENTER_CRITICAL()
#define DRIVER_EXIT_CRITICAL()

/**
 * This function finds a driver by specified name.
 *
 * @param name the driver's name
 *
 * @return the registered driver on successful, or NULL on failure.
 */
driver_t* driver_find(const char *name)
{
    driver_t *obj;
    obj = (driver_t*)object_find(OBJECT_CLASS_DRIVER, name);
    return obj;
}

/**
 * This function registers a driver with specified name.
 *
 * @param drv the pointer of driver structure
 * @param name the driver's name
 *
 * @return the error code, EOK on initialization successfully.
 */
int32_t driver_register(driver_t *drv, const char *name)
{
    int32_t ret;

    if (drv == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (driver_find(name) != NULL)
    {
        return RETVAL(E_FAIL);
    }

    ret = object_attack(&(drv->obj), OBJECT_CLASS_DRIVER, name);

    return ret;
}

/**
 * This function removes a previously registered driver
 *
 * @param drv the pointer of driver structure
 *
 * @return the error code, EOK on successfully.
 */
int32_t driver_unregister(driver_t *drv)
{
    int32_t ret;

    if (drv == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (object_get_type(&(drv->obj)) != OBJECT_CLASS_DRIVER)
    {
        return RETVAL(E_NO_DEV);
    }

    ret = object_detach(&(drv->obj));

    return ret;
}

/**
 * This function will probe the specified driver
 *
 * @param drv the pointer of driver structure
 *
 * @return the result
 */
int32_t driver_probe(driver_t *drv)
{
    int32_t ret = RETVAL(E_OK);

    if (drv == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (drv->probe == NULL)
    {
        return RETVAL(E_NOT_SUPPORT);
    }

    ret = drv->probe();

    return ret;
}

/**
 * This function will remove the specified driver
 *
 * @param drv the pointer of driver structure
 *
 * @return the result
 */
int32_t driver_remove(driver_t *drv)
{
    int32_t ret = RETVAL(E_OK);

    if (drv == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (drv->remove == NULL)
    {
        return RETVAL(E_NOT_SUPPORT);
    }

    ret = drv->remove();

    return ret;
}

/**
 * This function will set the reception indication callback function. This callback function
 * is invoked when this driver receives data.
 *
 * @param drv the pointer of driver structure
 * @param rx_ind the indication callback function
 *
 * @return EOK
 */
void driver_set_rx_ind_cbk(driver_t *drv, drv_rx_ind_cbk_t rx_ind)
{
    if (drv != NULL)
    {
        drv->rx_ind_cbk = rx_ind;
    }
}

/**
 * This function will set the indication callback function when device has
 * written data to physical hardware.
 *
 * @param drv the pointer of driver structure
 * @param tx_done the indication callback function
 *
 * @return EOK
 */
void driver_set_tx_done_cbk(driver_t *drv, drv_tx_done_cbk_t tx_done)
{
    if (drv != NULL)
    {
        drv->tx_done_cbk = tx_done;
    }
}

/**
 * This function will sent rx indicate
 *
 * @param drv the pointer of driver structure
 *
 * @return the result
 */
void driver_rx_ind_to_upper(driver_t *drv, void *buffer, uint16_t size)
{
    if (drv != NULL && drv->rx_ind_cbk != NULL)
    {
        drv->rx_ind_cbk(buffer, size);
    }
}

/**
 * This function will sent the tx done message
 *
 * @param drv the pointer of driver structure
 *
 * @return the result
 */
void driver_tx_done_to_upper(driver_t *drv, void *buffer, uint16_t size)
{
    if (drv != NULL && drv->tx_done_cbk != NULL)
    {
        drv->tx_done_cbk(buffer, size);
    }
}

/**
 * This function will set the private data
 *
 * @param drv the pointer of driver structure
 *
 * @return the result
 */
void driver_set_drvdata(driver_t *drv, void* drv_data)
{
    if (drv != NULL)
    {
        drv->drv_data = drv_data;
    }
}

/**
 * This function will get the private data
 *
 * @param drv the pointer of driver structure
 *
 * @return the result
 */
void* driver_get_drvdata(driver_t *drv)
{
    if (drv == NULL)
    {
        return NULL;
    }

    return drv->drv_data;
}



#ifndef _DRIVER_H_
#define _DRIVER_H_

#include "typedefs.h"
#include "object.h"

/**
 * driver class type
 */
typedef enum
{
    DRIVER_CLASS_NET,                                   /** net driver */
    DRIVER_CLASS_MTD,                                   /** memory driver */
    DRIVER_CLASS_CAN,                                   /** CAN driver */
    DRIVER_CLASS_RTC,                                   /** RTC driver */
    DRIVER_CLASS_SOUND,                                 /** Sound driver */
    DRIVER_CLASS_LED,                                   /** LED driver */
    DRIVER_CLASS_GRAPHIC,                               /** Graphic driver */
    DRIVER_CLASS_I2C,                                   /** I2C bus driver */
    DRIVER_CLASS_USB_DEVICE,                            /** USB slave driver */
    DRIVER_CLASS_USB_HOST,                              /** USB host bus */
    DRIVER_CLASS_SPI_BUS,                               /** SPI bus driver */
    DRIVER_CLASS_SPI_DEVICE,                            /** SPI driver */
    DRIVER_CLASS_SDIO,                                  /** SDIO bus driver */
    DRIVER_CLASS_SENSOR,                                /** Sensor driver */
    DRIVER_CLASS_TOUCH,                                 /** Touch driver */
    DRIVER_CLASS_FULE_GAUGE,                            /** Fuel gauge driver */
    DRIVER_CLASS_CHARGER,                               /** Charger driver */
    DRIVER_CLASS_BUCK_BOOST,
    DRIVER_CLASS_UNKNOWN                                /** unknown driver */
} driver_class_t;

typedef struct driver_s driver_t;

/**
 * Operations set for driver object
 */
typedef struct
{
    int32_t (*shutdown)(driver_t *drv);
    int32_t (*suspend)(driver_t *drv);
    int32_t (*resume)(driver_t *dev);
} driver_pm_ops_t;

typedef void (*drv_rx_ind_cbk_t)(void *buffer, uint16_t size);
typedef void (*drv_tx_done_cbk_t)(void *buffer, uint16_t size);

/**
 * Driver structure
 */
struct driver_s
{
    object_t                obj;                        /** inherit from object */
    driver_class_t          type;                       /** driver type */
    int32_t                 (*probe)(void);             /** driver probe */
    int32_t                 (*remove)(void);            /** driver remove */
    drv_rx_ind_cbk_t        rx_ind_cbk;                 /** RX callback */
    drv_tx_done_cbk_t       tx_done_cbk;                /** TX callback */
    const driver_pm_ops_t   *pm_ops;                    /** common interface */
    void                    *drv_data;                  /** driver private data */
};

int32_t driver_register(driver_t *drv, const char *name);
int32_t driver_unregister(driver_t *drv);

driver_t* driver_find(const char *name);
int32_t driver_probe(driver_t *drv);
int32_t driver_remove(driver_t *drv);

void driver_set_rx_ind_cbk(driver_t *drv, drv_rx_ind_cbk_t rx_ind);
void driver_set_tx_done_cbk(driver_t *drv, drv_tx_done_cbk_t tx_done);

void driver_rx_ind_to_upper(driver_t *drv, void *buffer, uint16_t size);
void driver_tx_done_to_upper(driver_t *drv, void *buffer, uint16_t size);

void driver_set_drvdata(driver_t *drv, void* drv_data);
void* driver_get_drvdata(driver_t *drv);

#endif // _DRIVER_H_


#include <string.h>

#include "errorno.h"
#include "sys_cmsis.h"

#include "object.h"

#define OBJECT_MALLOC(sz)               mem_malloc(sz)
#define OBJECT_FREE(ptr)                mem_free(ptr)

#define OBJECT_ENTER_CRITICAL()         sys_enter_critical()
#define OBJECT_EXIT_CRITICAL(VAL)       sys_exit_critical(VAL)

#define _OBJ_SET_LIST_INIT(t)     \
    { &(g_object_sets[t].obj_list), &(g_object_sets[t].obj_list) }


static object_set_t g_object_sets[OBJECT_CLASS_UNKNOWN - 1] =
{
    /* initialize object container - device */
    { OBJECT_CLASS_DEVICE, _OBJ_SET_LIST_INIT(OBJECT_CLASS_DEVICE - 1) },
    /* initialize object container - driver */
    { OBJECT_CLASS_DRIVER, _OBJ_SET_LIST_INIT(OBJECT_CLASS_DRIVER - 1) },
};

/**
 * This function will return the specified type of object information.
 *
 * @param type the type of object
 * @return the object type information or NULL
 */
object_set_t* object_get_obj_set(object_class_t type)
{
    int index;

    for (index = 0; index < (OBJECT_CLASS_UNKNOWN - 1); index ++)
    {
        if (g_object_sets[index].obj_type == type)
        {
            return &g_object_sets[index];
        }
    }

    return NULL;
}

/**
 * This function will initialize an object and add it to object system
 * management.
 *
 * @param object the specified object to be initialized.
 * @param type the object type.
 * @param name the object name. In system, the object's name must be unique.
 */
int32_t object_attack(object_t *object, object_class_t type, const char *name)
{
    // register uint32_t temp;
    object_set_t *obj_set = NULL;
    object_t *obj = NULL;
    xlist_node_t *node = NULL;

    /* get object information */
    obj_set = object_get_obj_set(type);
    if (obj_set == NULL)
    {
        return RETVAL(E_NULL);
    }

    /* check object type to avoid re-initialization */

    /* enter critical */
    uint32_t temp;
    temp = OBJECT_ENTER_CRITICAL();
    /* try to find object */
    xlist_for_each(node, &(obj_set->obj_list))
    {
        obj = xlist_entry(node, object_t, list);
        if (obj == object)
        {
            OBJECT_EXIT_CRITICAL(temp);
            return RETVAL(E_FAIL);
        }
    }
    /* leave critical */
    OBJECT_EXIT_CRITICAL(temp);

    /* initialize object's parameters */
    /* set object type to static */
    object->type = type | OBJECT_CLASS_STATIC;

    /* copy name */
    strncpy(object->name, name, OBJECT_NAME_SIZE);
    object->name[OBJECT_NAME_SIZE-1] = '\0';

    /* lock interrupt */
    // temp = hw_interrupt_disable();
    temp = OBJECT_ENTER_CRITICAL();

    /* insert object into information object list */
    xlist_insert_after(&(obj_set->obj_list), &(object->list));

    /* unlock interrupt */
    // hw_interrupt_enable(temp);
    OBJECT_EXIT_CRITICAL(temp);

    return RETVAL(E_OK);
}

/**
 * This function will detach a static object from object system,
 * and the memory of static object is not freed.
 *
 * @param object the specified object to be detached.
 */
int32_t object_detach(object_t* object)
{
    // register uint32_t temp;

    /* object check */
    if (object == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (!object_is_static_obj(object))
    {
        return RETVAL(E_FAIL);
    }

    /* reset object type */
    object->type = OBJECT_CLASS_NULL;

    /* lock interrupt */
    // temp = hw_interrupt_disable();
    uint32_t temp;
    temp = OBJECT_ENTER_CRITICAL();

    /* remove from old list */
    xlist_remove(&(object->list));

    /* unlock interrupt */
    // hw_interrupt_enable(temp);
    OBJECT_EXIT_CRITICAL(temp);

    return RETVAL(E_OK);
}

/**
 * This function will allocate an object from object system
 *
 * @param type the type of object
 * @param name the object name. In system, the object's name must be unique.
 *
 * @return object
 */
object_t* object_alloc_attack(object_class_t type, const char *name, xsize_t obj_size)
{
    // register uint32_t temp;
    object_set_t *obj_set = NULL;
    object_t *obj = NULL;

    /* get object information */
    obj_set = object_get_obj_set(type);
    if (obj_set == NULL)
    {
        return NULL;
    }

    if (object_find(type, name) == NULL)
    {
        return NULL;
    }

    obj = (object_t *)OBJECT_MALLOC(obj_size);
    if (obj == NULL)
    {
        /* no memory can be allocated */
        return NULL;
    }

    /* clean memory data of object */
    memset(obj, 0, obj_size);

    /* initialize object's parameters */

    /* set object type */
    obj->type = type;

    /* copy name */
    strncpy(obj->name, name, OBJECT_NAME_SIZE);
    obj->name[OBJECT_NAME_SIZE-1] = '\0';

    /* lock interrupt */
    // temp = hw_interrupt_disable();
    uint32_t temp;
    temp = OBJECT_ENTER_CRITICAL();

    /* insert object into information object list */
    xlist_insert_after(&(obj_set->obj_list), &(obj->list));

    /* unlock interrupt */
    // hw_interrupt_enable(temp);
    OBJECT_EXIT_CRITICAL(temp);

    return obj;
}

/**
 * This function will delete an object and release object memory.
 *
 * @param object the specified object to be deleted.
 */
int32_t object_free_detack(object_t* object)
{
    // register uint32_t temp;

    /* object check */
    if (object == NULL)
    {
        return RETVAL(E_NULL);
    }

    if (object_is_static_obj(object))
    {
        return RETVAL(E_FAIL);
    }

    /* reset object type */
    object->type = OBJECT_CLASS_NULL;

    /* lock interrupt */
    // temp = hw_interrupt_disable();
    uint32_t temp;
    temp = OBJECT_ENTER_CRITICAL();

    /* remove from old list */
    xlist_remove(&(object->list));

    /* unlock interrupt */
    // hw_interrupt_enable(temp);
    OBJECT_EXIT_CRITICAL(temp);

    /* free the memory of object */
    OBJECT_FREE(object);

    return RETVAL(E_OK);
}

/**
 * This function will judge the object is system object or not.
 * Normally, the system object is a static object and the type
 * of object set to Object_Class_Static.
 *
 * @param object the specified object to be judged.
 *
 * @return TRUE if a system object, FALSE for others.
 */
bool object_is_static_obj(object_t* object)
{
    if (object->type & OBJECT_CLASS_STATIC)
    {
        return true;
    }

    return false;
}

/**
 * This function will return the type of object without
 * Object_Class_Static flag.
 *
 * @param object the specified object to be get type.
 *
 * @return the type of object.
 */
object_class_t object_get_type(object_t* object)
{
    if (object == NULL)
    {
        return OBJECT_CLASS_NULL;
    }

    return (object->type & ~OBJECT_CLASS_STATIC);
}

/**
 * This function will find specified name object from object
 * container.
 *
 * @param name the specified name of object.
 * @param type the type of object
 *
 * @return the found object or NULL if there is no this object
 * in object container.
 *
 * @note this function shall not be invoked in interrupt status.
 */
object_t* object_find(object_class_t type, const char *name)
{
    object_set_t *obj_set = NULL;
    object_t *obj = NULL;
    xlist_node_t *node = NULL;

    /* parameter check */
    if ((name == NULL) || (type >= OBJECT_CLASS_UNKNOWN))
    {
        return NULL;
    }

    /* try to find object */
    obj_set = object_get_obj_set(type);
    if (obj_set == NULL)
    {
        return NULL;
    }

    /* enter critical */
    uint32_t temp;
    temp = OBJECT_ENTER_CRITICAL();
    xlist_for_each(node, &(obj_set->obj_list))
    {
        obj = xlist_entry(node, object_t, list);
        if (strncmp(obj->name, name, OBJECT_NAME_SIZE) == 0)
        {
            OBJECT_EXIT_CRITICAL(temp);
            return obj;
        }
    }
    /* leave critical */
    OBJECT_EXIT_CRITICAL(temp);

    return NULL;
}


#ifndef _OBJECT_H_
#define _OBJECT_H_

#include "typedefs.h"
#include "xlist2.h"

#define OBJECT_NAME_SIZE     10

/**
 *  The object type can be one of the follows with specific
 */
typedef enum
{
    OBJECT_CLASS_NULL,
    OBJECT_CLASS_DEVICE,                    /**< The object is a device */
    OBJECT_CLASS_DRIVER,                    /**< The object is a driver */
    OBJECT_CLASS_UNKNOWN,                   /**< The object is unknown. */
    OBJECT_CLASS_STATIC = 0x80              /**< The object is a static object. */
} object_class_t;

/**
 * Base structure of Kernel object
 */
typedef struct
{
    object_class_t  type;                   /**< type of kernel object */
    char            name[OBJECT_NAME_SIZE]; /**< name of kernel object */
    xlist_t         list;                   /**< list node of kernel object */
} object_t;

/**
 * The information of the kernel object
 */
typedef struct
{
    object_class_t  obj_type;               /**< object class type */
    xlist_t         obj_list;               /**< object list */
} object_set_t;


object_set_t* object_get_obj_set(object_class_t type);

int32_t object_attack(object_t *object, object_class_t type, const char *name);
int32_t object_detach(object_t* object);

object_t* object_alloc_attack(object_class_t type, const char *name, xsize_t obj_size);
int32_t object_free_detack(object_t* object);

bool object_is_static_obj(object_t* object);

object_class_t object_get_type(object_t* object);
object_t* object_find(object_class_t type, const char *name);

#endif // _OBJECT_H_

posted on 2022-09-13 14:20  xuejianqiang  阅读(70)  评论(0编辑  收藏  举报  来源
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033