diff --git a/include/rtdef.h b/include/rtdef.h index 27b2b21e3c87ede8c3f1de4f7d4add7aeaf4838b..bdfe3cdff09563fec26409ca876037d9af9637fc 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -1093,7 +1093,10 @@ typedef struct rt_wqueue rt_wqueue_t; struct rt_device { struct rt_object parent; /**< inherit from rt_object */ - +#ifdef RT_USING_DM + const struct rt_driver *drv; + void *dtb_node; +#endif enum rt_device_class_type type; /**< device type */ rt_uint16_t flag; /**< device flag */ rt_uint16_t open_flag; /**< device open flag */ @@ -1125,6 +1128,32 @@ struct rt_device void *user_data; /**< device private data */ }; +#define RT_DRIVER_MATCH_DTS (1<<0) +struct rt_device_id +{ + const char *compatible; + void *data; +}; + +struct rt_driver +{ +#ifdef RT_USING_DEVICE_OPS + const struct rt_device_ops *dev_ops; +#endif + const struct filesystem_ops *fops; + const char *name; + enum rt_device_class_type dev_type; + int device_priv_data_size; + int device_size; + int flag; + const struct rt_device_id *dev_match; + int (*probe)(struct rt_device *dev); + int (*probe_init)(struct rt_device *dev); + int (*remove)(struct rt_device *dev); + const void *ops; /* driver-specific operations */ +}; +typedef struct rt_driver *rt_driver_t; + /** * Notify structure */ diff --git a/include/rtthread.h b/include/rtthread.h index 4581cb1f22f57a026c20c160c70f16c7d0b0b877..44768567ccd055a71868ce30a770893967f49ace 100644 --- a/include/rtthread.h +++ b/include/rtthread.h @@ -24,7 +24,6 @@ #include #include #include - #ifdef __cplusplus extern "C" { #endif @@ -517,7 +516,14 @@ rt_size_t rt_device_write(rt_device_t dev, const void *buffer, rt_size_t size); rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg); +#ifdef RT_USING_DM +rt_err_t rt_device_bind_driver(rt_device_t device, rt_driver_t driver, void *node); +rt_device_t rt_device_create_since_driver(rt_driver_t drv,int device_id); +rt_err_t rt_device_probe_and_init(rt_device_t device); +rt_err_t rt_driver_match_with_id(const rt_driver_t drv,int device_id); +rt_err_t rt_driver_match_with_dtb(const rt_driver_t drv,void *from_node,int max_dev_num); +#endif /**@}*/ #endif diff --git a/src/Kconfig b/src/Kconfig index fd59cdd34d0d948afd136a2d859fceef85d44f59..90ab1840d9684dc04c1c25a8669214727714f6a8 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -347,4 +347,8 @@ config RT_VER_NUM help RT-Thread version number +config RT_USING_DM + bool "Enable rt device driver model" + default n + endmenu diff --git a/src/SConscript b/src/SConscript index 82c3b8aaf1b5435709a35175ad9e881718902f58..bf59d0bc939e78ac63dfa3cdc608dc8217f856fa 100644 --- a/src/SConscript +++ b/src/SConscript @@ -29,6 +29,9 @@ if GetDepend('RT_USING_DEVICE') == False: if GetDepend('RT_USING_SMP') == False: SrcRemove(src, ['cpu.c']) +if GetDepend('RT_USING_DM') == False: + SrcRemove(src, ['driver.c']) + group = DefineGroup('Kernel', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/src/device.c b/src/device.c index 32c06b380c69dfccaba1025f50a72a82d85f8fb5..88c7680a4879dbf5805427934b55c03737868628 100644 --- a/src/device.c +++ b/src/device.c @@ -477,4 +477,97 @@ rt_device_set_tx_complete(rt_device_t dev, } RTM_EXPORT(rt_device_set_tx_complete); +#ifdef RT_USING_DM +/** + * This function bind drvier and device + * + * @param driver the pointer of driver structure + * @param device the pointer of device structure + * @param node the pointer of fdt node structure + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_device_bind_driver(rt_device_t device, rt_driver_t driver, void *node) +{ + if((!driver) || (!device)) + { + return -RT_EINVAL; + } + + device->drv = driver; +#ifdef RT_USING_DEVICE_OPS + device->ops = driver->dev_ops; +#endif + device->dtb_node = node; + + return RT_EOK; +} +RTM_EXPORT(rt_device_bind_driver); + +/** + * This function create rt_device according to driver infomation + * + * @param drv the pointer of driver structure + * @param device_id specify the ID of the rt_device + * + * @return the error code, RT_EOK on successfully. + */ +rt_device_t rt_device_create_since_driver(rt_driver_t drv,int device_id) +{ + rt_device_t device; + if (!drv) + { + return RT_NULL; + } + + device = (rt_device_t)rt_calloc(1,drv->device_size); + if(device == RT_NULL) + { + return RT_NULL; + } + if(drv->device_priv_data_size != 0) + { + device->user_data = (void *)(rt_calloc(1,drv->device_priv_data_size)); + if(device->user_data == RT_NULL) + { + rt_free(device); + return RT_NULL; + } + } + + device->device_id = device_id; + rt_snprintf(device->parent.name, sizeof(device->parent.name), "%s%d", drv->name, device_id); + return device; +} +RTM_EXPORT(rt_device_create_since_driver); + +/** + * This function rt_device probe and init + * + * @param device the pointer of rt_device structure + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_device_probe_and_init(rt_device_t device) +{ + int ret = -RT_ERROR; + if (!device) + { + return -RT_EINVAL; + } + if(!device->drv) + { + return -RT_ERROR; + } + if(device->drv->probe) + { + ret = device->drv->probe((rt_device_t)device); + } + if(device->drv->probe_init) + { + ret = device->drv->probe_init((rt_device_t)device); + } + return ret; +} +RTM_EXPORT(rt_device_probe_and_init); +#endif #endif diff --git a/src/driver.c b/src/driver.c new file mode 100644 index 0000000000000000000000000000000000000000..9562168476eff5796046118de5ae1ef0480eacf6 --- /dev/null +++ b/src/driver.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#ifdef PKG_USING_FDT +#include +#endif +#if defined(RT_USING_POSIX) +#include /* for wqueue_init */ +#endif + +/** + * This function driver device match with id + * + * @param drv the pointer of driver structure + * @param device_id the id of the device + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_driver_match_with_id(const rt_driver_t drv,int device_id) +{ + rt_device_t device; + int ret; + if (!drv) + { + return -RT_EINVAL; + } + device = rt_device_create_since_driver(drv,device_id); + if(!device) + { + return -RT_ERROR; + } + ret = rt_device_bind_driver(device,drv,RT_NULL); + if(ret != 0) + { + return -RT_ERROR; + } + ret = rt_device_probe_and_init(device); + if(ret != 0) + { + return -RT_ERROR; + } + return ret; +} + +RTM_EXPORT(rt_driver_match_with_id); + +#ifdef PKG_USING_FDT +/** + * This function driver device match with dtb_node + * + * @param drv the pointer of driver structure + * @param from_node dtb node entry + * @param max_dev_num the max device support + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_driver_match_with_dtb(const rt_driver_t drv,void *from_node,int max_dev_num) +{ + struct dtb_node** node_list; + rt_device_t device; + int ret,i; + int active_dev_num = 0; + if ((!drv)||(!drv->dev_match)||(!drv->dev_match->compatible)||(!from_node)) + { + return -RT_EINVAL; + } + + node_list = rt_calloc(max_dev_num,sizeof(void *)); + if(!node_list) + { + return -RT_ERROR; + } + + ret = dtb_node_find_all_active_compatible_node(from_node,drv->dev_match->compatible,node_list,max_dev_num,&active_dev_num); + if((ret != 0) || (!active_dev_num)) + { + return -RT_ERROR; + } + + for(i = 0; i < active_dev_num; i ++) + { + device = rt_device_create_since_driver(drv,i); + if(!device) + { + return -RT_ERROR; + } + + ret = rt_device_bind_driver(device,drv,node_list[i]); + if(ret != 0) + { + return -RT_ERROR; + } + ret = rt_device_probe_and_init(device); + if(ret != 0) + { + return -RT_ERROR; + } + } + rt_free(node_list); + return ret; +} + +RTM_EXPORT(rt_driver_match_with_dtb); +#endif +