From 26197d3b0d046a21a6786b7fb9d35e093c0738be Mon Sep 17 00:00:00 2001 From: MacRsh Date: Wed, 31 Jan 2024 22:31:10 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=9B=B4=E6=96=B0=E5=86=85=E7=BD=AE=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E5=90=8D=E3=80=822.=E7=A7=BB=E9=99=A4=E9=A9=B1?= =?UTF-8?q?=E5=8A=A8=E7=B1=BB=E5=9E=8B=E3=80=823.=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E6=94=AF=E6=8C=81=E6=AF=8F=E4=B8=AA=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=8F=8F=E8=BF=B0=E7=AC=A6=E7=8B=AC=E7=AB=8B=E6=8C=82?= =?UTF-8?q?=E8=BD=BD=EF=BC=8C=E4=B8=8D=E9=99=90=E4=B8=8A=E9=99=90=E3=80=82?= =?UTF-8?q?4.offset=E4=BF=AE=E6=94=B9=E4=B8=BAposition=EF=BC=8C=E6=9B=B4?= =?UTF-8?q?=E5=BC=BA=E8=B0=83=E5=86=99=E5=85=A5=E4=BD=8D=E7=BD=AE=E6=A6=82?= =?UTF-8?q?=E5=BF=B5=E3=80=825.=E8=AE=BE=E5=A4=87=E4=B8=AD=E6=96=AD?= =?UTF-8?q?=E6=A6=82=E5=BF=B5=E4=BF=AE=E6=AD=A3=EF=BC=8C=E7=88=B6=E7=B3=BB?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E4=B8=AD=E6=96=AD=E4=B8=8D=E4=BB=85=E5=94=A4?= =?UTF-8?q?=E8=B5=B7=E8=87=AA=E8=BA=AB=E7=9A=84=E5=9B=9E=E8=B0=83=E5=87=BD?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E5=90=8C=E6=97=B6=E4=B9=9F=E5=B0=86=E9=80=92?= =?UTF-8?q?=E5=BD=92=E5=94=A4=E9=86=92=E5=AD=90=E8=AE=BE=E5=A4=87=E5=9B=9E?= =?UTF-8?q?=E8=B0=83=E5=87=BD=E6=95=B0=EF=BC=88=E6=9B=B4=E5=BC=BA=E8=B0=83?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E5=85=B3=E7=B3=BB=EF=BC=89=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/mr_def.h | 367 ++++++++++---------- source/device.c | 882 ++++++++++++++++++++++++----------------------- 2 files changed, 630 insertions(+), 619 deletions(-) diff --git a/include/mr_def.h b/include/mr_def.h index 63d7134..d2858fb 100644 --- a/include/mr_def.h +++ b/include/mr_def.h @@ -20,82 +20,92 @@ extern "C" { #endif /* __cplusplus */ /** - * @brief Mr-library version. + * @addtogroup Version + * @{ */ -#define _MR_VERSION_MAJOR 0 /**< Major version */ -#define _MR_VERSION_MINOR 0 /**< Minor version */ -#define _MR_VERSION_PATCH 8 /**< Patch version */ -#define _MR_VERSION_STR(major, minor, patch) \ - MR_STR(major) "." MR_STR(minor) "." MR_STR(patch) -#define MR_VERSION (_MR_VERSION_MAJOR << 16 | _MR_VERSION_MINOR << 8 | _MR_VERSION_PATCH) -#define MR_VERSION_STR _MR_VERSION_STR(_MR_VERSION_MAJOR, _MR_VERSION_MINOR, _MR_VERSION_PATCH) +#define MR_VERSION_MAJOR 0 /**< Major version (X.y.z) */ +#define MR_VERSION_MINOR 0 /**< Minor version (x.Y.z) */ +#define MR_VERSION_PATCH 9 /**< Patch version (x.y.Z) */ /** - * @brief Compiler related. + * @brief Version hex. + * + * @note [23:16] major version, [15:8] minor version, [7:0] patch version, [31:24] reserved. + */ +#define MR_VERSION (MR_VERSION_MAJOR << 16 | MR_VERSION_MINOR << 8 | MR_VERSION_PATCH) +/** @} */ + +/** + * @addtogroup Compiler + * @{ */ #if defined(__ARMCC_VERSION) -#define MR_SECTION(x) __attribute__((section(x))) -#define MR_USED __attribute__((used)) -#define MR_WEAK __attribute__((weak)) -#define MR_INLINE static __inline -typedef int ssize_t; +#define MR_SECTION(x) __attribute__((section(x))) /**< Section */ +#define MR_USED __attribute__((used)) /**< Used */ +#define MR_WEAK __attribute__((weak)) /**< Weak */ +#define MR_INLINE static __inline /**< Inline */ +typedef int ssize_t; /**< ssize_t type */ #elif defined (__IAR_SYSTEMS_ICC__) -#define MR_SECTION(x) @ x -#define MR_USED __root -#define MR_WEAK __weak -#define MR_INLINE static inline +#define MR_SECTION(x) @ x /**< Section */ +#define MR_USED __root /**< Used */ +#define MR_WEAK __weak /**< Weak */ +#define MR_INLINE static inline /**< Inline */ #elif defined (__GNUC__) -#define MR_SECTION(x) __attribute__((section(x))) -#define MR_USED __attribute__((used)) -#define MR_WEAK __attribute__((weak)) -#define MR_INLINE static __inline +#define MR_SECTION(x) __attribute__((section(x))) /**< Section */ +#define MR_USED __attribute__((used)) /**< Used */ +#define MR_WEAK __attribute__((weak)) /**< Weak */ +#define MR_INLINE static __inline /**< Inline */ #elif defined (__ADSPBLACKFIN__) -#define MR_SECTION(x) __attribute__((section(x))) -#define MR_USED __attribute__((used)) -#define MR_WEAK __attribute__((weak)) -#define MR_INLINE static inline +#define MR_SECTION(x) __attribute__((section(x))) /**< Section */ +#define MR_USED __attribute__((used)) /**< Used */ +#define MR_WEAK __attribute__((weak)) /**< Weak */ +#define MR_INLINE static inline /**< Inline */ #elif defined (_MSC_VER) -#define MR_SECTION(x) -#define MR_USED -#define MR_WEAK -#define MR_INLINE static __inline +#define MR_SECTION(x) /**< Section */ +#define MR_USED /**< Used */ +#define MR_WEAK /**< Weak */ +#define MR_INLINE static __inline /**< Inline */ #elif defined (__TASKING__) -#define MR_SECTION(x) __attribute__((section(x))) -#define MR_USED __attribute__((used, protect)) -#define MR_WEAK __attribute__((weak)) -#define MR_INLINE static inline +#define MR_SECTION(x) __attribute__((section(x))) /**< Section */ +#define MR_USED \ + __attribute__((used, protect)) /**< Used */ +#define MR_WEAK __attribute__((weak)) /**< Weak */ +#define MR_INLINE static inline /**< Inline */ +#else +#define MR_SECTION(x) __attribute__((section(x))) /**< Section */ +#define MR_USED __attribute__((used)) /**< Used */ +#define MR_WEAK __attribute__((weak)) /**< Weak */ +#define MR_INLINE static __inline /**< Inline */ #endif /* __ARMCC_VERSION */ - -typedef int (*mr_init_fn_t)(void); +/** @} */ /** - * @brief Exports an auto initialization function with level. + * @addtogroup Auto-init + * @{ */ -#define _MR_INIT_EXPORT(fn, level) \ +typedef void (*mr_init_fn_t)(void); /**< Auto initialization function */ +#define MR_INIT_EXPORT(fn, level) \ MR_USED const mr_init_fn_t _mr_auto_init_##fn MR_SECTION("mr_auto_init."level) = fn +#define MR_INIT_BOARD_EXPORT(fn) MR_INIT_EXPORT(fn, "1") /**< Exports a Board initialization function */ +#define MR_INIT_DRV_EXPORT(fn) MR_INIT_EXPORT(fn, "2") /**< Exports a Driver initialization function */ +#define MR_INIT_DEV_EXPORT(fn) MR_INIT_EXPORT(fn, "3") /**< Exports a Device initialization function */ +#define MR_INIT_APP_EXPORT(fn) MR_INIT_EXPORT(fn, "4") /**< Exports an App initialization function */ +/** @} */ /** - * @brief Exports a board auto initialization function. + * @addtogroup Basic + * @{ */ -#define MR_INIT_BOARD_EXPORT(fn) _MR_INIT_EXPORT(fn, "1") +#define MR_NULL ((void *)0) /**< Null pointer */ +#define MR_DISABLE (0) /**< Disable */ +#define MR_ENABLE (1) /**< Enable */ +#define MR_FALSE (0) /**< False */ +#define MR_TRUE (1) /**< True */ +/** @} */ /** - * @brief Exports a driver auto initialization function. - */ -#define MR_INIT_DRV_EXPORT(fn) _MR_INIT_EXPORT(fn, "2") - -/** - * @brief Exports a device auto initialization function. - */ -#define MR_INIT_DEV_EXPORT(fn) _MR_INIT_EXPORT(fn, "3") - -/** - * @brief Exports a app auto initialization function. - */ -#define MR_INIT_APP_EXPORT(fn) _MR_INIT_EXPORT(fn, "4") - -/** - * @brief Error code. + * @addtogroup Error + * @{ */ #define MR_EOK (0) /**< No error */ #define MR_ENOMEM (-1) /**< No enough memory */ @@ -105,32 +115,43 @@ typedef int (*mr_init_fn_t)(void); #define MR_EEXIST (-5) /**< Exists */ #define MR_ENOTSUP (-6) /**< Operation not supported */ #define MR_EINVAL (-7) /**< Invalid argument */ +/** @} */ /** - * @brief Null pointer. + * @addtogroup Memory + * @{ */ -#define MR_NULL ((void *)0) /** - * @brief Disable/enable. + * @brief Heap block structure. */ -#define MR_DISABLE (0) /**< Disable */ -#define MR_ENABLE (1) /**< Enable */ +struct mr_heap_block +{ + struct mr_heap_block *next; /**< Point to next block */ + uint32_t size: 31; /**< Size of this block */ + uint32_t allocated: 1; /**< Allocated flag */ +}; +/** @} */ /** - * @brief True/false. + * @addtogroup List + * @{ */ -#define MR_FALSE (0) /**< False */ -#define MR_TRUE (1) /**< True */ /** - * @brief Double linked list structure. + * @brief List structure. */ struct mr_list { struct mr_list *next; /**< Point to next node */ struct mr_list *prev; /**< Point to prev node */ }; +/** @} */ + +/** + * @addtogroup Ringbuffer + * @{ + */ /** * @brief Ring buffer structure. @@ -145,6 +166,12 @@ struct mr_ringbuf size_t read_index; /**< Read index */ size_t write_index; /**< Write index */ }; +/** @} */ + +/** + * @addtogroup AVL-tree + * @{ + */ /** * @brief AVL tree structure. @@ -156,108 +183,63 @@ struct mr_avl struct mr_avl *left_child; /**< Point to left-child node */ struct mr_avl *right_child; /**< Point to right-child node */ }; +/** @} */ /** - * @brief Synchronous/asynchronous operation flag. + * @addtogroup Device + * @{ */ +#define MR_MAGIC_NUMBER (0xdeadbeef) /**< Magic number */ + #define MR_SYNC (0) /**< Synchronous */ #define MR_ASYNC (1) /**< Asynchronous */ -/** - * @brief Magic number. - */ -#define MR_MAGIC_NUMBER (0xdeadbeef) +/* [31:24] are for lock, [23:0] reserved */ +#define MR_LOCK_RD (0x01 << 24) /**< Read lock */ +#define MR_LOCK_WR (0x02 << 24) /**< Write lock */ +#define MR_LOCK_RDWR (0x03 << 24) /**< Read/write lock */ +#define MR_LOCK_NONBLOCK (0x04 << 24) /**< Non-blocking lock */ +#define MR_LOCK_SLEEP (0x08 << 24) /**< Sleep lock */ -/** - * @brief Lock flags. - */ -#define MR_LFLAG_RD (0x01) /**< Read lock */ -#define MR_LFLAG_WR (0x02) /**< Write lock */ -#define MR_LFLAG_RDWR (0x03) /**< Read/write lock */ -#define MR_LFLAG_NONBLOCK (0x04) /**< Non-blocking lock */ -#define MR_LFLAG_SLEEP (0x08) /**< Sleep lock */ +/* [31:24] are for basic flags, [23:0] can define user flags */ +#define MR_O_CLOSED (0) /**< Closed flag */ +#define MR_O_QUERY (0) /**< Query flag */ +#define MR_O_RDONLY (0x01 << 24) /**< Read only flag */ +#define MR_O_WRONLY (0x02 << 24) /**< Write only flag */ +#define MR_O_RDWR (0x03 << 24) /**< Read/write flag */ +#define MR_O_NONBLOCK (0x04 << 24) /**< Non-blocking flag */ -/** - * @brief Open flags. - */ -#define MR_OFLAG_CLOSED (0) /**< Closed */ -#define MR_OFLAG_RDONLY (0x01) /**< Read only */ -#define MR_OFLAG_WRONLY (0x02) /**< Write only */ -#define MR_OFLAG_RDWR (0x03) /**< Read/write */ -#define MR_OFLAG_NONBLOCK (0x04) /**< Non-blocking */ -#define MR_OFLAG_DMA (0x08) /**< DMA */ +/* [31:24] are for basic commands, [23:0] can define user commands. (>0): user -> device, (<0): user <- device */ +#define MR_IOC_SPOS (0x01 << 24) /**< Set position command */ +#define MR_IOC_SRCB (0x02 << 24) /**< Set read callback command */ +#define MR_IOC_SWCB (0x03 << 24) /**< Set write callback command */ +#define MR_IOC_SCFG (0x04 << 24) /**< Set configuration command */ +#define MR_IOC_SRBSZ (0x05 << 24) /**< Set read buffer size command */ +#define MR_IOC_SWBSZ (0x06 << 24) /**< Set write buffer size command */ +#define MR_IOC_CRBD (0x07 << 24) /**< Clear read buffer data command */ +#define MR_IOC_CWBD (0x08 << 24) /**< Clear write buffer data command */ -/** - * @brief Support flags. - */ -#define MR_SFLAG_NONRDWR MR_OFLAG_CLOSED /**< Non-read/write */ -#define MR_SFLAG_RDONLY MR_OFLAG_RDONLY /**< Read only */ -#define MR_SFLAG_WRONLY MR_OFLAG_WRONLY /**< Write only */ -#define MR_SFLAG_RDWR MR_OFLAG_RDWR /**< Read/write */ -#define MR_SFLAG_NONBLOCK MR_OFLAG_NONBLOCK /**< Non-blocking */ -#define MR_SFLAG_DMA MR_OFLAG_DMA /**< DMA */ -#define MR_SFLAG_NONDRV (0x10) /**< Non-driver */ -#define MR_SFLAG_ONLY (0x20) /**< Only */ +#define MR_IOC_GPOS (-(0x01 << 24)) /**< Get position command */ +#define MR_IOC_GRCB (-(0x02 << 24)) /**< Get read callback command */ +#define MR_IOC_GWCB (-(0x03 << 24)) /**< Get write callback command */ +#define MR_IOC_GCFG (-(0x04 << 24)) /**< Get configuration command */ +#define MR_IOC_GRBSZ (-(0x05 << 24)) /**< Get read buffer size command */ +#define MR_IOC_GWBSZ (-(0x06 << 24)) /**< Get write buffer size command */ +#define MR_IOC_GRBDSZ (-(0x07 << 24)) /**< Get read buffer data size command */ +#define MR_IOC_GWBDSZ (-(0x08 << 24)) /**< Get write buffer data size command */ -/** - * @brief Device control command. - * - * @note [31:24] are for basic commands, [23:0] can define custom commands. - * (> 0) is set command, (< 0) is get command. - */ -#define MR_CTL_SET_OFFSET (0x02 << 24) /**< Set offset */ -#define MR_CTL_SET_RD_CALL (0x06 << 24) /**< Set read callback */ -#define MR_CTL_SET_WR_CALL (0x07 << 24) /**< Set write callback */ -#define MR_CTL_SET_CONFIG (0x08 << 24) /**< Set configuration */ -#define MR_CTL_SET_RD_BUFSZ (0x09 << 24) /**< Set read buffer size */ -#define MR_CTL_SET_WR_BUFSZ (0x0a << 24) /**< Set write buffer size */ -#define MR_CTL_CLR_RD_BUF (0x0b << 24) /**< Clear read buffer */ -#define MR_CTL_CLR_WR_BUF (0x0c << 24) /**< Clear write buffer */ - -#define MR_CTL_GET_OFLAGS (-(0x01 << 24)) /**< Get open flags */ -#define MR_CTL_GET_OFFSET (-(0x02 << 24)) /**< Get offset */ -#define MR_CTL_GET_SFLAGS (-(0x03 << 24)) /**< Get support flags */ -#define MR_CTL_GET_PATH (-(0x04 << 24)) /**< Get path */ -#define MR_CTL_GET_NAME (-(0x05 << 24)) /**< Get name */ -#define MR_CTL_GET_RD_CALL (-(0x06 << 24)) /**< Get read callback */ -#define MR_CTL_GET_WR_CALL (-(0x07 << 24)) /**< Get write callback */ -#define MR_CTL_GET_CONFIG (-(0x08 << 24)) /**< Get configuration */ -#define MR_CTL_GET_RD_BUFSZ (-(0x09 << 24)) /**< Get read buffer size */ -#define MR_CTL_GET_WR_BUFSZ (-(0x0a << 24)) /**< Get write buffer size */ -#define MR_CTL_GET_RD_DATASZ (-(0x0b << 24)) /**< Get read data size */ -#define MR_CTL_GET_WR_DATASZ (-(0x0c << 24)) /**< Get write data size */ - -/** - * @brief ISR event. - */ -#define MR_ISR_RD (0x01) /**< Read interrupt */ -#define MR_ISR_WR (0x02) /**< Write interrupt */ -#define MR_ISR_MASK (0xff) /**< Interrupt mask */ - -/** - * @brief Driver types. - */ -enum mr_drv_type -{ - Mr_Drv_Type_ADC, /**< ADC */ - Mr_Drv_Type_CAN, /**< CAN */ - Mr_Drv_Type_DAC, /**< DAC */ - Mr_Drv_Type_I2C, /**< I2C */ - Mr_Drv_Type_Pin, /**< PIN */ - Mr_Drv_Type_Serial, /**< SERIAL */ - Mr_Drv_Type_SPI, /**< SPI */ - Mr_Drv_Type_Timer, /**< Timer */ - Mr_Drv_Type_PWM, /**< PWM */ -}; +/* [31:24] are for interrupt flags, [23:0] can define user flags */ +#define MR_ISR_RD (0x01 << 24) /**< Read interrupt */ +#define MR_ISR_WR (0x02 << 24) /**< Write interrupt */ +#define MR_ISR_MASK (0x7f << 24) /**< Interrupt mask */ /** * @brief Driver structure. */ struct mr_drv { - int type; /**< Driver type */ - void *ops; /**< Driver operations */ - void *data; /**< Driver data */ + void *ops; /**< Operations */ + void *data; /**< Data */ }; /** @@ -265,17 +247,17 @@ struct mr_drv */ enum mr_dev_type { - Mr_Dev_Type_Root = -1, /**< Root */ - Mr_Dev_Type_ADC = Mr_Drv_Type_ADC, /**< ADC */ - Mr_Dev_Type_CAN = Mr_Drv_Type_CAN, /**< CAN */ - Mr_Dev_Type_DAC = Mr_Drv_Type_DAC, /**< DAC */ - Mr_Dev_Type_I2C = Mr_Drv_Type_I2C, /**< I2C */ - Mr_Dev_Type_Pin = Mr_Drv_Type_Pin, /**< PIN */ - Mr_Dev_Type_Serial = Mr_Drv_Type_Serial, /**< SERIAL */ - Mr_Dev_Type_SPI = Mr_Drv_Type_SPI, /**< SPI */ - Mr_Dev_Type_Timer = Mr_Drv_Type_Timer, /**< Timer */ - Mr_Dev_Type_PWM = Mr_Drv_Type_PWM, /**< PWM */ - Mr_Dev_Type_Component, /**< Component */ + MR_DEV_TYPE_ROOT = 0, /**< Root device */ + MR_DEV_TYPE_ADC, /**< ADC device */ + MR_DEV_TYPE_CAN, /**< CAN device */ + MR_DEV_TYPE_DAC, /**< DAC device */ + MR_DEV_TYPE_I2C, /**< I2C device */ + MR_DEV_TYPE_PIN, /**< PIN device */ + MR_DEV_TYPE_SERIAL, /**< Serial device */ + MR_DEV_TYPE_SPI, /**< SPI device */ + MR_DEV_TYPE_TIMER, /**< Timer device */ + MR_DEV_TYPE_PWM, /**< PWM device */ + MR_DEV_TYPE_COMPONENT, /**< Component device */ }; struct mr_dev; @@ -287,43 +269,64 @@ struct mr_dev_ops { int (*open)(struct mr_dev *dev); int (*close)(struct mr_dev *dev); - ssize_t (*read)(struct mr_dev *dev, int off, void *buf, size_t size, int async); - ssize_t (*write)(struct mr_dev *dev, int off, const void *buf, size_t size, int async); - int (*ioctl)(struct mr_dev *dev, int off, int cmd, void *args); + ssize_t (*read)(struct mr_dev *dev, void *buf, size_t count); + ssize_t (*write)(struct mr_dev *dev, const void *buf, size_t count); + int (*ioctl)(struct mr_dev *dev, int cmd, void *args); ssize_t (*isr)(struct mr_dev *dev, int event, void *args); }; +/** + * @brief Device callback structure. + */ +struct mr_dev_call +{ + void (*fn)(int desc, void *args); + struct mr_list list; +}; + /** * @brief Device structure. */ struct mr_dev { - int magic; /**< Magic number */ -#ifndef MR_CFG_DEV_NAME_MAX -#define MR_CFG_DEV_NAME_MAX (8) -#endif /* MR_CFG_DEV_NAME_MAX */ - char name[MR_CFG_DEV_NAME_MAX]; /**< Name */ - int type; /**< Device type */ - void *parent; /**< Parent */ - struct mr_list list; /**< List */ - struct mr_list clist; /**< Child list */ + uint32_t magic; /**< Magic number */ +#ifndef MR_CFG_DEV_NAME_LEN +#define MR_CFG_DEV_NAME_LEN (8) +#endif /* MR_CFG_DEV_NAME_LEN */ + char name[MR_CFG_DEV_NAME_LEN]; /**< Name */ + uint32_t type; /**< Type */ + int flags; /**< Flags */ + void *parent; /**< Parent device */ + struct mr_list list; /**< Same level device list */ + struct mr_list clist; /**< Child device list */ size_t ref_count; /**< Reference count */ - int sflags; /**< Support flags */ #ifdef MR_USING_RDWR_CTL - volatile int lflags; /**< Lock flags */ + volatile uint32_t lock; /**< Lock flags */ #endif /* MR_USING_RDWR_CTL */ + int sync; /**< Sync flag */ + int position; /**< Position */ - struct - { - int desc; /**< Device descriptor */ - int (*call)(int desc, void *args); /**< Callback function */ - } rd_call, wr_call; /**< Read/write call */ + struct mr_list rd_call_list; /**< Read callback list */ + struct mr_list wr_call_list; /**< Write callback list */ - const struct mr_dev_ops *ops; /**< Device operations */ + const struct mr_dev_ops *ops; /**< Operations */ const struct mr_drv *drv; /**< Driver */ }; +/** + * @brief Device descriptor structure. + */ +struct mr_dev_desc +{ + struct mr_dev *dev; /**< Device */ + int flags; /**< Open flags */ + int position; /**< Current position */ + struct mr_dev_call rd_call; /**< Read callback */ + struct mr_dev_call wr_call; /**< Write callback */ +}; +/** @} */ + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/source/device.c b/source/device.c index 8eebd3f..63808be 100644 --- a/source/device.c +++ b/source/device.c @@ -8,30 +8,40 @@ #include "include/mr_api.h" -#define MR_ROOT_DEV_NAME "dev" - -static struct mr_dev root_dev = +static struct mr_dev root_dev = /**< Root device */ { - MR_MAGIC_NUMBER, - MR_ROOT_DEV_NAME, - Mr_Dev_Type_Root, - MR_NULL, - {&root_dev.list, &root_dev.list}, - {&root_dev.clist, &root_dev.clist} + .name = "dev", + .type = MR_DEV_TYPE_ROOT, + .parent = MR_NULL, + .list = MR_LIST_INIT(root_dev.list), + .clist = MR_LIST_INIT(root_dev.clist) }; +#ifndef MR_CFG_DESC_NUM +#define MR_CFG_DESC_NUM (32) +#endif /* MR_CFG_DESC_NUM */ +static struct mr_dev_desc desc_map[MR_CFG_DESC_NUM] = {0}; /**< Device descriptor map */ + +#define DESC_OF(desc) (desc_map[(desc)]) /**< Descriptor of the device */ +/* Check if the descriptor is valid */ +#define DESC_IS_VALID(desc) (((desc) >= 0 && (desc) < MR_CFG_DESC_NUM) && ((DESC_OF(desc).dev) != MR_NULL)) +#ifdef MR_USING_DESC_CHECK +#define MR_DESC_CHECK(desc) if (DESC_IS_VALID(desc) == MR_FALSE) { return MR_EINVAL; } +#else +#define MR_DESC_CHECK(desc) +#endif /* MR_USING_DESC_CHECK */ + MR_INLINE int dev_is_root(struct mr_dev *dev) { - return (int)dev->type == Mr_Dev_Type_Root; + return dev->type == MR_DEV_TYPE_ROOT; } MR_INLINE struct mr_dev *dev_find_child(struct mr_dev *parent, const char *name) { - /* Find the child device */ for (struct mr_list *list = parent->clist.next; list != &parent->clist; list = list->next) { struct mr_dev *dev = (struct mr_dev *)MR_CONTAINER_OF(list, struct mr_dev, list); - if (strncmp(name, dev->name, MR_CFG_DEV_NAME_MAX) == 0) + if (strncmp(name, dev->name, MR_CFG_DEV_NAME_LEN) == 0) { return dev; } @@ -41,102 +51,84 @@ MR_INLINE struct mr_dev *dev_find_child(struct mr_dev *parent, const char *name) MR_INLINE int dev_register_child(struct mr_dev *parent, struct mr_dev *child, const char *name) { - /* Check whether the device with the same name exists */ if (dev_find_child(parent, name) != MR_NULL) { return MR_EEXIST; } - /* Insert the device into the child list */ child->magic = MR_MAGIC_NUMBER; - strncpy(child->name, name, MR_CFG_DEV_NAME_MAX); + strncpy(child->name, name, MR_CFG_DEV_NAME_LEN); child->parent = parent; mr_list_insert_before(&parent->clist, &child->list); return MR_EOK; } -MR_INLINE const char *dev_clear_path(const char *path) +static int dev_register_by_path(struct mr_dev *parent, struct mr_dev *dev, const char *path) { - /* Skip the leading '/' */ - if (*path == '/') + if (path[0] == '/') { path++; } - /* Skip the leading 'dev/'(root path) */ - if (strncmp(path, MR_ROOT_DEV_NAME"/", sizeof(MR_ROOT_DEV_NAME"/") - 1) == 0) - { - path += sizeof(MR_ROOT_DEV_NAME"/") - 1; - } - return path; -} - -MR_INLINE int dev_register_by_path(struct mr_dev *parent, struct mr_dev *dev, const char *path) -{ - char child_name[MR_CFG_DEV_NAME_MAX + 1] = {0}; - - /* Clear the path */ - path = dev_clear_path(path); - - /* Check whether the child path exists */ + /* Check for child path separator */ const char *child_path = strchr(path, '/'); if (child_path != MR_NULL) { - /* Get the child name */ - size_t len = (child_path - path) > MR_CFG_DEV_NAME_MAX ? MR_CFG_DEV_NAME_MAX : (child_path - path); + char child_name[MR_CFG_DEV_NAME_LEN + 1] = {0}; + size_t len = MR_BOUND(child_path - path, 0, MR_CFG_DEV_NAME_LEN); + + /* Find the child device */ strncpy(child_name, path, len); child_name[len] = '\0'; - - /* Find the child */ struct mr_dev *child = dev_find_child(parent, child_name); if (child == MR_NULL) { return MR_ENOTFOUND; } - /* Continue iterating */ + /* Register recursively */ return dev_register_by_path(child, dev, child_path); } else { - /* Register the child device to the parent */ + /* Register with parent */ return dev_register_child(parent, dev, path); } } -MR_INLINE struct mr_dev *dev_find_by_path(struct mr_dev *parent, const char *path) +static struct mr_dev *dev_find_by_path(struct mr_dev *parent, const char *path) { - char child_name[MR_CFG_DEV_NAME_MAX + 1] = {0}; + if (path[0] == '/') + { + path++; + } - /* Clear the path */ - path = dev_clear_path(path); - - /* Check whether the child path exists */ + /* Check for child path separator */ const char *child_path = strchr(path, '/'); if (child_path != MR_NULL) { - /* Get the child name */ - size_t len = (child_path - path) > MR_CFG_DEV_NAME_MAX ? MR_CFG_DEV_NAME_MAX : (child_path - path); + char child_name[MR_CFG_DEV_NAME_LEN + 1] = {0}; + size_t len = MR_BOUND(child_path - path, 0, MR_CFG_DEV_NAME_LEN); + + /* Find the child device */ strncpy(child_name, path, len); child_name[len] = '\0'; - - /* Find the child */ struct mr_dev *child = dev_find_child(parent, child_name); if (child == MR_NULL) { return MR_NULL; } - /* Continue iterating */ + /* Find recursively */ return dev_find_by_path(child, child_path); } else { - /* Find the child */ + /* Find with parent */ return dev_find_child(parent, path); } } #ifdef MR_USING_RDWR_CTL -MR_INLINE int dev_lock_take(struct mr_dev *dev, int take, int set) +static int dev_lock_take(struct mr_dev *dev, uint32_t take, uint32_t set) { /* Continue iterating until reach the root device */ if (dev_is_root(dev->parent) != MR_TRUE) @@ -148,18 +140,15 @@ MR_INLINE int dev_lock_take(struct mr_dev *dev, int take, int set) } } - /* Check whether the device is taken */ - if (dev->lflags & take) + if (dev->lock & take) { return MR_EBUSY; } - - /* Take the device */ - MR_BIT_SET(dev->lflags, set); + MR_BIT_SET(dev->lock, set); return MR_EOK; } -MR_INLINE void dev_lock_release(struct mr_dev *dev, int release) +static void dev_lock_release(struct mr_dev *dev, uint32_t release) { /* Continue iterating until reach the root device */ if (dev_is_root(dev->parent) != MR_TRUE) @@ -167,57 +156,108 @@ MR_INLINE void dev_lock_release(struct mr_dev *dev, int release) dev_lock_release(dev->parent, release); } - /* Release the device */ - MR_BIT_CLR(dev->lflags, release); + MR_BIT_CLR(dev->lock, release); } #endif /* MR_USING_RDWR_CTL */ -MR_INLINE int dev_get_path(struct mr_dev *dev, char *buf, size_t bufsz) -{ - int ret = 0; - - /* Continue to get the path of the parent device */ - if (dev->parent != MR_NULL) - { - ret = dev_get_path(dev->parent, buf, bufsz); - if (ret < 0) - { - return ret; - } - } - - /* Check whether the buffer is enough */ - if ((bufsz - ret) <= (strlen(dev->name) + 1)) - { - return ret; - } - ret += snprintf(buf + ret, bufsz - ret, "/%s", dev->name); - return ret; -} - -MR_INLINE int dev_register(struct mr_dev *dev, const char *path) -{ - /* Disable interrupt */ - mr_interrupt_disable(); - - /* Register the device to the root device */ - int ret = dev_register_by_path(&root_dev, dev, path); - - /* Enable interrupt */ - mr_interrupt_enable(); - return ret; -} - MR_INLINE struct mr_dev *dev_find(const char *path) { + /* Check whether the path is absolute */ + if (*path == '/') + { + path++; + const char *next_slash = strchr(path, '/'); + if ((next_slash == MR_NULL) || + (strncmp(path, root_dev.name, MR_BOUND(next_slash - path, 0, MR_CFG_DEV_NAME_LEN)) != 0)) + { + return MR_NULL; + } + path += MR_BOUND(next_slash - path, 0, MR_CFG_DEV_NAME_LEN); + } + /* Find the device from the root device */ return dev_find_by_path(&root_dev, path); } -MR_INLINE int dev_open(struct mr_dev *dev, int oflags) +MR_INLINE int dev_register(struct mr_dev *dev, const char *path) +{ + /* Check whether the path is absolute */ + if (*path == '/') + { + path++; + const char *next_slash = strchr(path, '/'); + if ((next_slash == MR_NULL) || + (strncmp(path, root_dev.name, MR_BOUND(next_slash - path, 0, MR_CFG_DEV_NAME_LEN)) != 0)) + { + return MR_EINVAL; + } + path += MR_BOUND(next_slash - path, 0, MR_CFG_DEV_NAME_LEN); + } + + /* Register the device with the root device */ + mr_interrupt_disable(); + int ret = dev_register_by_path(&root_dev, dev, path); + mr_interrupt_enable(); + return ret; +} + +static int dev_isr(struct mr_dev *dev, int event, void *args) +{ + /* Call the all registered callbacks */ + switch (event) + { + case MR_ISR_RD: + { + for (struct mr_list *list = dev->rd_call_list.next; list != &dev->rd_call_list; list = list->next) + { + struct mr_dev_desc *desc = (struct mr_dev_desc *)MR_CONTAINER_OF(list, + struct mr_dev_desc, + rd_call.list); + if (desc->rd_call.fn != MR_NULL) + { + desc->rd_call.fn((int)(desc - &desc_map[0]), args); + } + } + break; + } + case MR_ISR_WR: + { +#ifdef MR_USING_RDWR_CTL + dev_lock_release(dev, MR_LOCK_NONBLOCK); +#endif /* MR_USING_RDWR_CTL */ + for (struct mr_list *list = dev->wr_call_list.next; list != &dev->wr_call_list; list = list->next) + { + struct mr_dev_desc *desc = (struct mr_dev_desc *)MR_CONTAINER_OF(list, + struct mr_dev_desc, + wr_call.list); + if (desc->wr_call.fn != MR_NULL) + { + desc->wr_call.fn((int)(desc - &desc_map[0]), args); + } + } + break; + } + default: + { + return MR_ENOTSUP; + } + } + + /* Wake up all child devices */ + for (struct mr_list *list = dev->clist.next; list != &dev->clist; list = list->next) + { + struct mr_dev *cdev = (struct mr_dev *)MR_CONTAINER_OF(list, struct mr_dev, list); + + /* Handle recursively */ + dev_isr(cdev, event, args); + } + return MR_EOK; +} + +static int dev_open(struct mr_dev *dev, int flags) { #ifdef MR_USING_RDWR_CTL - if (MR_BIT_IS_SET(dev->sflags, oflags) != MR_ENABLE) + if (MR_BIT_IS_SET(dev->flags, flags) != MR_ENABLE) { return MR_ENOTSUP; } @@ -229,7 +269,7 @@ MR_INLINE int dev_open(struct mr_dev *dev, int oflags) /* Continue iterating until reach the root device */ if (dev_is_root(dev->parent) != MR_TRUE) { - int ret = dev_open(dev->parent, oflags); + int ret = dev_open(dev->parent, flags); if (ret < 0) { return ret; @@ -246,19 +286,13 @@ MR_INLINE int dev_open(struct mr_dev *dev, int oflags) } } } -#ifdef MR_USING_RDWR_CTL - else if (MR_BIT_IS_SET(dev->sflags, MR_SFLAG_ONLY) == MR_ENABLE) - { - return MR_EBUSY; - } -#endif /* MR_USING_RDWR_CTL */ /* Increase the reference count */ dev->ref_count++; return MR_EOK; } -MR_INLINE int dev_close(struct mr_dev *dev) +static int dev_close(struct mr_dev *dev) { /* Decrease the reference count */ dev->ref_count--; @@ -285,321 +319,122 @@ MR_INLINE int dev_close(struct mr_dev *dev) return MR_EOK; } -MR_INLINE ssize_t dev_read(struct mr_dev *dev, int off, void *buf, size_t size, int async) +MR_INLINE ssize_t dev_read(struct mr_dev *dev, int position, int sync, void *buf, size_t count) { #ifdef MR_USING_RDWR_CTL do { - /* Disable interrupt */ mr_interrupt_disable(); - int ret = dev_lock_take(dev, (MR_LFLAG_RD | MR_LFLAG_SLEEP), MR_LFLAG_RD); + int ret = dev_lock_take(dev, (MR_LOCK_RD | MR_LOCK_SLEEP), MR_LOCK_RD); if (ret < 0) { - /* Enable interrupt */ mr_interrupt_enable(); return ret; } - /* Enable interrupt */ mr_interrupt_enable(); } while (0); #endif /* MR_USING_RDWR_CTL */ + /* Update information */ + dev->sync = sync; + dev->position = position; + /* Read buffer from the device */ - ssize_t ret = dev->ops->read(dev, off, buf, size, async); + ssize_t ret = dev->ops->read(dev, buf, count); #ifdef MR_USING_RDWR_CTL - dev_lock_release(dev, MR_LFLAG_RD); + dev_lock_release(dev, MR_LOCK_RD); #endif /* MR_USING_RDWR_CTL */ return ret; } -MR_INLINE ssize_t dev_write(struct mr_dev *dev, int offset, const void *buf, size_t size, int async) +MR_INLINE ssize_t dev_write(struct mr_dev *dev, int position, int sync, const void *buf, size_t count) { #ifdef MR_USING_RDWR_CTL do { - /* Disable interrupt */ mr_interrupt_disable(); int ret = dev_lock_take(dev, - (MR_LFLAG_WR | MR_LFLAG_SLEEP | (async == MR_SYNC ? MR_LFLAG_NONBLOCK : 0)), - MR_LFLAG_WR); + (MR_LOCK_WR | MR_LOCK_SLEEP | (sync == MR_SYNC ? MR_LOCK_NONBLOCK : 0)), + MR_LOCK_WR); if (ret < 0) { - /* Enable interrupt */ mr_interrupt_enable(); return ret; } - /* Enable interrupt */ mr_interrupt_enable(); } while (0); #endif /* MR_USING_RDWR_CTL */ + /* Update information */ + dev->sync = sync; + dev->position = position; + /* Write buffer to the device */ - ssize_t ret = dev->ops->write(dev, offset, buf, size, async); + ssize_t ret = dev->ops->write(dev, buf, count); #ifdef MR_USING_RDWR_CTL - dev_lock_release(dev, MR_LFLAG_WR); - if ((async == MR_ASYNC) && (ret > 0)) + dev_lock_release(dev, MR_LOCK_WR); + if ((sync == MR_ASYNC) && (ret > 0)) { - /* Disable interrupt */ mr_interrupt_disable(); - dev_lock_take(dev, 0, MR_LFLAG_NONBLOCK); - /* Enable interrupt */ + dev_lock_take(dev, 0, MR_LOCK_NONBLOCK); mr_interrupt_enable(); } #endif /* MR_USING_RDWR_CTL */ return ret; } -MR_INLINE int dev_ioctl(struct mr_dev *dev, int desc, int off, int cmd, void *args) +MR_INLINE int dev_ioctl(struct mr_dev *dev, int position, int sync, int cmd, void *args) { - /* Check whether the device has an ioctl function */ if (dev->ops->ioctl == MR_NULL) { return MR_ENOTSUP; } - switch (cmd) - { - case MR_CTL_SET_RD_CALL: - { - dev->rd_call.desc = desc; - dev->rd_call.call = (int (*)(int desc, void *args))args; - return sizeof(dev->rd_call); - } - case MR_CTL_SET_WR_CALL: - { - dev->wr_call.desc = desc; - dev->wr_call.call = (int (*)(int desc, void *args))args; - return sizeof(dev->wr_call); - } - case MR_CTL_GET_SFLAGS: - { - if (args != MR_NULL) - { - int *sflags = (int *)args; - - *sflags = dev->sflags; - return sizeof(sflags); - } - return MR_EINVAL; - } - case MR_CTL_GET_PATH: - { - if (args != MR_NULL) - { - struct - { - char *buf; - size_t bufsz; - } *path = args; - - return dev_get_path(dev, path->buf, path->bufsz); - } - return MR_EINVAL; - } - case MR_CTL_GET_NAME: - { - if (args != MR_NULL) - { - char **name = (char **)args; - - *name = dev->name; - return sizeof(name); - } - return MR_EINVAL; - } - case MR_CTL_GET_RD_CALL: - { - if (args != MR_NULL) - { - *(int (**)(int desc, void *args))args = dev->rd_call.call; - return sizeof(dev->rd_call.call); - } - return MR_EINVAL; - } - case MR_CTL_GET_WR_CALL: - { - if (args != MR_NULL) - { - *(int (**)(int desc, void *args))args = dev->wr_call.call; - return sizeof(dev->wr_call.call); - } - return MR_EINVAL; - } - default: - { #ifdef MR_USING_RDWR_CTL - do + do + { + /* Lock only when user -> device command */ + if (cmd) + { + mr_interrupt_disable(); + int ret = dev_lock_take(dev, (MR_LOCK_RDWR | MR_LOCK_SLEEP | MR_LOCK_NONBLOCK), MR_LOCK_RDWR); + if (ret < 0) { - /* Disable interrupt */ - mr_interrupt_disable(); - int ret = dev_lock_take(dev, (MR_LFLAG_RDWR | MR_LFLAG_SLEEP | MR_LFLAG_NONBLOCK), MR_LFLAG_RDWR); - if (ret < 0) - { - /* Enable interrupt */ - mr_interrupt_enable(); - return ret; - } - /* Enable interrupt */ mr_interrupt_enable(); - } while (0); -#endif /* MR_USING_RDWR_CTL */ - - /* I/O control to the device */ - int ret = dev->ops->ioctl(dev, off, cmd, args); - -#ifdef MR_USING_RDWR_CTL - dev_lock_release(dev, MR_LFLAG_RDWR); -#endif /* MR_USING_RDWR_CTL */ - return ret; - } - } -} - -/** - * @brief This function register a device. - * - * @param dev The device. - * @param path The path of the device. - * @param type The type of the device. - * @param sflags The support flags of the device. - * @param ops The operations of the device. - * @param drv The driver of the device. - * - * @return MR_EOK on success, otherwise an error code. - */ -int mr_dev_register(struct mr_dev *dev, - const char *path, - int type, - int sflags, - struct mr_dev_ops *ops, - struct mr_drv *drv) -{ - static struct mr_dev_ops null_ops = {MR_NULL}; - - MR_ASSERT(dev != MR_NULL); - MR_ASSERT(dev->magic != MR_MAGIC_NUMBER); - MR_ASSERT(path != MR_NULL); - MR_ASSERT(type != Mr_Dev_Type_Root); - MR_ASSERT((ops != MR_NULL) || (sflags == MR_SFLAG_NONRDWR)); - MR_ASSERT((ops->read != MR_NULL) || (MR_BIT_IS_SET(sflags, MR_SFLAG_RDONLY) == MR_DISABLE)); - MR_ASSERT((ops->write != MR_NULL) || (MR_BIT_IS_SET(sflags, MR_SFLAG_WRONLY) == MR_DISABLE)); - MR_ASSERT((drv != MR_NULL) || (sflags & MR_SFLAG_NONDRV)); - MR_ASSERT((drv == MR_NULL) || (drv->type == type)); - - /* Initialize the fields */ - dev->magic = 0; - memset(dev->name, '\0', MR_CFG_DEV_NAME_MAX); - dev->parent = MR_NULL; - mr_list_init(&dev->list); - mr_list_init(&dev->clist); - dev->type = type; - dev->ref_count = 0; -#ifdef MR_USING_RDWR_CTL - dev->sflags = sflags; - dev->lflags = 0; -#endif /* MR_USING_RDWR_CTL */ - dev->rd_call.desc = -1; - dev->rd_call.call = MR_NULL; - dev->wr_call.desc = -1; - dev->wr_call.call = MR_NULL; - dev->ops = (ops != MR_NULL) ? ops : &null_ops; - dev->drv = drv; - - /* Register the device */ - return dev_register(dev, path); -} - -/** - * @brief This function handle device interrupt. - * - * @param dev The device to be handle. - * @param event The event to be handle. - * @param args The arguments of the event. - */ -int mr_dev_isr(struct mr_dev *dev, int event, void *args) -{ - MR_ASSERT(dev != MR_NULL); - - /* Check whether the device is opened */ - if (dev->ref_count == 0) - { - return MR_EINVAL; - } - - /* Check whether the device has ISR */ - if (dev->ops->isr == MR_NULL) - { - return MR_ENOTSUP; - } - - /* Call the device ISR */ - ssize_t ret = dev->ops->isr(dev, event, args); - if (ret < 0) - { - return (int)ret; - } - - /* Handle the event */ - switch (event & MR_ISR_MASK) - { - case MR_ISR_RD: - { - if (dev->rd_call.call != MR_NULL) - { - return dev->rd_call.call(dev->rd_call.desc, &ret); + return ret; } - return MR_EOK; + mr_interrupt_enable(); } - - case MR_ISR_WR: - { -#ifdef MR_USING_RDWR_CTL - dev_lock_release(dev, MR_LFLAG_NONBLOCK); + } while (0); #endif /* MR_USING_RDWR_CTL */ - if (dev->wr_call.call != MR_NULL) - { - return dev->wr_call.call(dev->wr_call.desc, &ret); - } - return MR_EOK; - } - default: - { - return MR_ENOTSUP; - } - } + /* Update information */ + dev->sync = sync; + dev->position = position; + + /* I/O control to the device */ + int ret = dev->ops->ioctl(dev, cmd, args); + +#ifdef MR_USING_RDWR_CTL + dev_lock_release(dev, MR_LOCK_RDWR); +#endif /* MR_USING_RDWR_CTL */ + return ret; } -/** - * @brief Device descriptor structure. - */ -static struct mr_desc -{ - struct mr_dev *dev; /* Device */ - int oflags; /* Open flags */ - int offset; /* Offset */ -#ifndef MR_CFG_DESC_MAX -#define MR_CFG_DESC_MAX (32) -#endif /* MR_CFG_DESC_MAX */ -} desc_map[MR_CFG_DESC_MAX] = {0}; - -#define DESC_OF(desc) (desc_map[(desc)]) -#define DESC_IS_VALID(desc) (((desc) >= 0 && (desc) < MR_CFG_DESC_MAX) && ((DESC_OF(desc).dev) != MR_NULL)) - -#ifdef MR_USING_DESC_CHECK -#define MR_DESC_CHECK(desc) if (DESC_IS_VALID(desc) == MR_FALSE) { return MR_EINVAL; } -#else -#define MR_DESC_CHECK(desc) -#endif /* MR_USING_DESC_CHECK */ - MR_INLINE int desc_allocate(const char *path) { int desc = -1; + struct mr_dev *dev = dev_find(path); + if (dev == MR_NULL) + { + return MR_ENOTFOUND; + } + /* Find a free descriptor */ - for (size_t i = 0; i < MR_CFG_DESC_MAX; i++) + for (size_t i = 0; i < MR_CFG_DESC_NUM; i++) { if (DESC_OF(i).dev == MR_NULL) { @@ -612,60 +447,163 @@ MR_INLINE int desc_allocate(const char *path) return MR_ENOMEM; } - /* Find the device */ - struct mr_dev *dev = dev_find(path); - if (dev == MR_NULL) - { - return MR_ENOTFOUND; - } - - /* Initialize the fields */ DESC_OF(desc).dev = dev; - DESC_OF(desc).offset = -1; - DESC_OF(desc).oflags = MR_OFLAG_CLOSED; + DESC_OF(desc).flags = MR_O_CLOSED; + DESC_OF(desc).position = -1; + DESC_OF(desc).rd_call.fn = MR_NULL; + DESC_OF(desc).wr_call.fn = MR_NULL; + mr_list_init(&DESC_OF(desc).rd_call.list); + mr_list_init(&DESC_OF(desc).wr_call.list); return desc; } MR_INLINE void desc_free(int desc) { - if (desc >= 0 && desc < MR_CFG_DESC_MAX) + if (DESC_IS_VALID(desc) == MR_TRUE) { DESC_OF(desc).dev = MR_NULL; - DESC_OF(desc).oflags = MR_OFLAG_CLOSED; - DESC_OF(desc).offset = -1; + DESC_OF(desc).flags = MR_O_CLOSED; + DESC_OF(desc).position = -1; + DESC_OF(desc).rd_call.fn = MR_NULL; + DESC_OF(desc).wr_call.fn = MR_NULL; + mr_list_remove(&DESC_OF(desc).rd_call.list); + mr_list_remove(&DESC_OF(desc).wr_call.list); } } +/** + * @brief This function register a device. + * + * @param dev The device. + * @param path The path of the device. + * @param type The type of the device. + * @param flags The support flags of the device. + * @param ops The operations of the device. + * @param drv The driver of the device. + * + * @return 0 on success, otherwise an error code. + * + * @retval -3 a node in the path is not found. + * @retval -5 name is already exists. + * @retval -7 path is invalid. + */ +int mr_dev_register(struct mr_dev *dev, + const char *path, + int type, + int flags, + struct mr_dev_ops *ops, + struct mr_drv *drv) +{ + MR_ASSERT(dev != MR_NULL); + MR_ASSERT(dev->magic != MR_MAGIC_NUMBER); + MR_ASSERT(path != MR_NULL); + MR_ASSERT(type != MR_DEV_TYPE_ROOT); + MR_ASSERT(flags >= MR_O_CLOSED); + MR_ASSERT(ops != MR_NULL); + MR_ASSERT((ops->read != MR_NULL) || (MR_BIT_IS_SET(flags, MR_O_RDONLY) == MR_DISABLE)); + MR_ASSERT((ops->write != MR_NULL) || (MR_BIT_IS_SET(flags, MR_O_WRONLY) == MR_DISABLE)); + + /* Initialize the fields */ + dev->magic = 0; + memset(dev->name, '\0', MR_CFG_DEV_NAME_LEN); + dev->type = type; + dev->flags = flags; + dev->parent = MR_NULL; + mr_list_init(&dev->list); + mr_list_init(&dev->clist); + dev->ref_count = 0; +#ifdef MR_USING_RDWR_CTL + dev->lock = 0; +#endif /* MR_USING_RDWR_CTL */ + dev->sync = MR_SYNC; + dev->position = -1; + mr_list_init(&dev->rd_call_list); + mr_list_init(&dev->wr_call_list); + dev->ops = ops; + dev->drv = drv; + + /* Register the device */ + return dev_register(dev, path); +} + +/** + * @brief This function handle device interrupt. + * + * @param dev The device to be handle. + * @param event The event to be handle. + * @param args The arguments of the event. + * + * @return 0 on success, otherwise an error code. + * + * @retval -6 device is closed or not supported. + * @retval other error code. + */ +int mr_dev_isr(struct mr_dev *dev, int event, void *args) +{ + MR_ASSERT(dev != MR_NULL); + MR_ASSERT(event >= 0); + + if ((dev->ref_count == 0) || (dev->ops->isr == MR_NULL)) + { + return MR_ENOTSUP; + } + + /* Call the device ISR */ + ssize_t ret = dev->ops->isr(dev, event, args); + if (ret < 0) + { + return (int)ret; + } + + /* Handle the ISR event */ + return dev_isr(dev, (event & MR_ISR_MASK), &ret); +} + /** * @brief This function open a device. * * @param path The path of the device. - * @param oflags The open flags of the device. + * @param flags The open flags. * - * @return The descriptor of the device, otherwise an error code. + * @return The descriptor of the device on success, the support flags of the device if flags is a query, + * otherwise an error code. + * + * @retval -1 not enough descriptor or memory. + * @retval -3 the path is not found. + * @retval -6 not supported flags. + * @retval other error code. */ -int mr_dev_open(const char *path, int oflags) +int mr_dev_open(const char *path, int flags) { MR_ASSERT(path != MR_NULL); - MR_ASSERT(oflags != MR_OFLAG_CLOSED); + MR_ASSERT(flags >= MR_O_CLOSED); - /* Allocate a descriptor */ + /* Query device flags */ + if (flags == MR_O_QUERY) + { + struct mr_dev *dev = dev_find(path); + if (dev == MR_NULL) + { + return MR_ENOTFOUND; + } + return dev->flags; + } + + /* Allocate descriptor and open device */ int desc = desc_allocate(path); if (desc < 0) { return desc; } - - /* Open the device */ - int ret = dev_open(DESC_OF(desc).dev, oflags); + int ret = dev_open(DESC_OF(desc).dev, flags); if (ret < 0) { desc_free(desc); return ret; } - /* Initialize the open flags */ - DESC_OF(desc).oflags = oflags; + /* Set descriptor flags */ + DESC_OF(desc).flags = flags; return desc; } @@ -674,20 +612,21 @@ int mr_dev_open(const char *path, int oflags) * * @param desc The descriptor of the device. * - * @return MR_EOK on success, otherwise an error code. + * @return 0 on success, otherwise an error code. + * + * @retval -7 descriptor is invalid. + * @retval other error code. */ int mr_dev_close(int desc) { MR_DESC_CHECK(desc); - /* Close the device */ + /* Close the device and free the descriptor */ int ret = dev_close(DESC_OF(desc).dev); if (ret < 0) { return ret; } - - /* Free the descriptor */ desc_free(desc); return MR_EOK; } @@ -697,17 +636,22 @@ int mr_dev_close(int desc) * * @param desc The descriptor of the device. * @param buf The buf buffer to be read. - * @param size The size of read. + * @param count The count of read. * * @return The size of the actual read, otherwise an error code. + * + * @retval -4 is currently accessed by another. + * @retval -6 not supported read. + * @retval -7 descriptor is invalid. + * @retval other error code. */ -ssize_t mr_dev_read(int desc, void *buf, size_t size) +ssize_t mr_dev_read(int desc, void *buf, size_t count) { - MR_ASSERT((buf != MR_NULL) || (size == 0)); + MR_ASSERT((buf != MR_NULL) || (count == 0)); MR_DESC_CHECK(desc); #ifdef MR_USING_RDWR_CTL - if (MR_BIT_IS_SET(DESC_OF(desc).oflags, MR_OFLAG_RDONLY) == MR_DISABLE) + if (MR_BIT_IS_SET(DESC_OF(desc).flags, MR_O_RDONLY) == MR_DISABLE) { return MR_ENOTSUP; } @@ -715,10 +659,10 @@ ssize_t mr_dev_read(int desc, void *buf, size_t size) /* Read buffer from the device */ return dev_read(DESC_OF(desc).dev, - DESC_OF(desc).offset, + DESC_OF(desc).position, + MR_BIT_IS_SET(DESC_OF(desc).flags, MR_O_NONBLOCK), buf, - size, - (MR_BIT_IS_SET(DESC_OF(desc).oflags, MR_OFLAG_NONBLOCK))); + count); } /** @@ -726,17 +670,22 @@ ssize_t mr_dev_read(int desc, void *buf, size_t size) * * @param desc The descriptor of the device. * @param buf The buf buffer to be written. - * @param size The size of write. + * @param count The count of write. * * @return The size of the actual write, otherwise an error code. + * + * @retval -4 is currently accessed by another. + * @retval -6 not supported write. + * @retval -7 descriptor is invalid. + * @retval other error code. */ -ssize_t mr_dev_write(int desc, const void *buf, size_t size) +ssize_t mr_dev_write(int desc, const void *buf, size_t count) { - MR_ASSERT((buf != MR_NULL) || (size == 0)); + MR_ASSERT((buf != MR_NULL) || (count == 0)); MR_DESC_CHECK(desc); #ifdef MR_USING_RDWR_CTL - if (MR_BIT_IS_SET(DESC_OF(desc).oflags, MR_OFLAG_WRONLY) == MR_DISABLE) + if (MR_BIT_IS_SET(DESC_OF(desc).flags, MR_O_WRONLY) == MR_DISABLE) { return MR_ENOTSUP; } @@ -744,10 +693,10 @@ ssize_t mr_dev_write(int desc, const void *buf, size_t size) /* Write buffer to the device */ return dev_write(DESC_OF(desc).dev, - DESC_OF(desc).offset, + DESC_OF(desc).position, + MR_BIT_IS_SET(DESC_OF(desc).flags, MR_O_NONBLOCK), buf, - size, - (MR_BIT_IS_SET(DESC_OF(desc).oflags, MR_OFLAG_NONBLOCK))); + count); } /** @@ -757,7 +706,12 @@ ssize_t mr_dev_write(int desc, const void *buf, size_t size) * @param cmd The command of the device. * @param args The arguments of the device. * - * @return The arguments of the device, otherwise an error code. + * @return The size of the actual control, otherwise an error code. + * + * @retval -4 is currently accessed by another. + * @retval -6 not supported ioctl or command. + * @retval -7 descriptor or argument is invalid. + * @retval other error code. */ int mr_dev_ioctl(int desc, int cmd, void *args) { @@ -765,71 +719,131 @@ int mr_dev_ioctl(int desc, int cmd, void *args) switch (cmd) { - case MR_CTL_SET_OFFSET: + case MR_IOC_SPOS: { if (args != MR_NULL) { - int offset = *(int *)args; + int position = *(int *)args; - DESC_OF(desc).offset = offset; - return sizeof(offset); + DESC_OF(desc).position = position; + return sizeof(position); } return MR_EINVAL; } - case MR_CTL_GET_OFFSET: + case MR_IOC_SRCB: + { + void (*fn)(int desc, void *args) = (void (*)(int desc, void *args))args; + + /* Link or unlink the callback function */ + DESC_OF(desc).rd_call.fn = fn; + mr_interrupt_disable(); + if (fn != MR_NULL) + { + mr_list_insert_before(&DESC_OF(desc).dev->rd_call_list, &DESC_OF(desc).rd_call.list); + } else + { + mr_list_remove(&DESC_OF(desc).rd_call.list); + } + mr_interrupt_enable(); + return sizeof(fn); + } + case MR_IOC_SWCB: + { + void (*fn)(int desc, void *args) = (void (*)(int desc, void *args))args; + + /* Link or unlink the callback function */ + DESC_OF(desc).wr_call.fn = fn; + mr_interrupt_disable(); + if (fn != MR_NULL) + { + mr_list_insert_before(&DESC_OF(desc).dev->wr_call_list, &DESC_OF(desc).wr_call.list); + } else + { + mr_list_remove(&DESC_OF(desc).wr_call.list); + } + mr_interrupt_enable(); + return sizeof(fn); + } + case MR_IOC_GPOS: { if (args != MR_NULL) { - int *offset = (int *)args; + int *position = (int *)args; - *offset = DESC_OF(desc).offset; - return sizeof(offset); + *position = DESC_OF(desc).position; + return sizeof(position); } return MR_EINVAL; } - case MR_CTL_GET_OFLAGS: + case MR_IOC_GRCB: { if (args != MR_NULL) { - int *oflags = (int *)args; - - *oflags = DESC_OF(desc).oflags; + *(void (**)(int desc, void *args))args = DESC_OF(desc).rd_call.fn; + return sizeof(DESC_OF(desc).rd_call.fn); + } + return MR_EINVAL; + } + case MR_IOC_GWCB: + { + if (args != MR_NULL) + { + *(void (**)(int desc, void *args))args = DESC_OF(desc).wr_call.fn; + return sizeof(DESC_OF(desc).wr_call.fn); } return MR_EINVAL; } default: { /* I/O control to the device */ - return dev_ioctl(DESC_OF(desc).dev, desc, DESC_OF(desc).offset, cmd, args); + return dev_ioctl(DESC_OF(desc).dev, + DESC_OF(desc).position, + MR_BIT_IS_SET(DESC_OF(desc).flags, MR_O_NONBLOCK), + cmd, + args); } } } -/** - * @brief This function check if the descriptor is valid. - * - * @param desc The descriptor of the device. - * - * @return MR_TRUE if the descriptor is valid, otherwise MR_FALSE. - */ -int mr_dev_is_valid(int desc) -{ - return DESC_IS_VALID(desc); -} - -#ifdef MR_USING_MSH +#if defined(MR_USING_MSH) && defined(MR_USING_MSH_DEV_CMD) #include "include/components/mr_msh.h" -static void msh_list_tree(struct mr_dev *parent, int level) +static int dev_get_path(struct mr_dev *dev, char *buf, size_t bufsz) +{ + int ret = 0; + + /* Continue iterating until reach the null parent */ + if (dev->parent != MR_NULL) + { + ret = dev_get_path(dev->parent, buf, bufsz); + } + + /* Check whether the buffer is enough */ + if ((bufsz - ret) <= (strlen(dev->name) + 1)) + { + return ret; + } + ret += snprintf(buf + ret, bufsz - ret, "/%s", dev->name); + return ret; +} + +int msh_dev_get_path(int desc, char *buf, size_t size) +{ + MR_DESC_CHECK(desc); + + return dev_get_path(DESC_OF(desc).dev, buf, size); +} + +void msh_dlist_tree(struct mr_dev *parent, int level) { if (level == 0) { - mr_msh_printf("|-- %-*s", MR_CFG_DEV_NAME_MAX, parent->name); + mr_msh_printf("|%s %-*s", mr_strflags(parent->flags), MR_CFG_DEV_NAME_LEN, parent->name); } else { - mr_msh_printf("%*s|-- %-*s", level, " ", MR_CFG_DEV_NAME_MAX, parent->name); + mr_msh_printf("%*s|%s %-*s", level, " ", mr_strflags(parent->flags), MR_CFG_DEV_NAME_LEN, parent->name); } - for (size_t i = 0; i < MR_CFG_DESC_MAX; i++) + for (size_t i = 0; i < MR_CFG_DESC_NUM; i++) { if (desc_map[i].dev == parent) { @@ -840,19 +854,13 @@ static void msh_list_tree(struct mr_dev *parent, int level) for (struct mr_list *child = parent->clist.next; child != &parent->clist; child = child->next) { struct mr_dev *dev = MR_CONTAINER_OF(child, struct mr_dev, list); - msh_list_tree(dev, level + 4); + msh_dlist_tree(dev, level + 7); } } -static int msh_cmd_dlist(int argc, void *argv) +struct mr_dev *msh_get_root(void) { - msh_list_tree(&root_dev, 0); - return MR_EOK; + return &root_dev; } -/** - * @brief Exports device MSH commands. - */ -MR_MSH_CMD_EXPORT(dlist, msh_cmd_dlist, "list all devices."); - -#endif /* MR_USING_MSH */ +#endif /* defined(MR_USING_MSH) && defined(MR_USING_MSH_DEV_CMD) */