diff options
| author | Bernard Xiong <[email protected]> | 2023-06-22 14:16:03 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-06-22 14:16:03 +0800 |
| commit | e3f068f05834d433e9748d031a02bc03266bdafd (patch) | |
| tree | 96e55c65d0d19190d9f81c09179ab5f2e2cfa0a4 /components/drivers | |
| parent | d1ed0f7ddb97cda805fd56714cc3fc93cc51599b (diff) | |
[DeviceDrivers] prepare for device driver v2.0 (#7697)
Diffstat (limited to 'components/drivers')
| -rw-r--r-- | components/drivers/core/SConscript | 15 | ||||
| -rw-r--r-- | components/drivers/core/bus.c (renamed from components/drivers/misc/rt_dev_bus.c) | 0 | ||||
| -rw-r--r-- | components/drivers/core/device.c | 547 | ||||
| -rw-r--r-- | components/drivers/core/driver.c | 113 | ||||
| -rw-r--r-- | components/drivers/misc/SConscript | 3 |
5 files changed, 675 insertions, 3 deletions
diff --git a/components/drivers/core/SConscript b/components/drivers/core/SConscript new file mode 100644 index 0000000000..4aac2b7166 --- /dev/null +++ b/components/drivers/core/SConscript @@ -0,0 +1,15 @@ +from building import * + +cwd = GetCurrentDir() +src = ['device.c'] +CPPPATH = [cwd + '/../include'] + +if GetDepend(['RT_USING_DEV_BUS']): + src = src + ['bus.c'] + +if GetDepend(['RT_USING_DM']): + src = src + ['driver.c'] + +group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/misc/rt_dev_bus.c b/components/drivers/core/bus.c index fd2fbb8e3e..fd2fbb8e3e 100644 --- a/components/drivers/misc/rt_dev_bus.c +++ b/components/drivers/core/bus.c diff --git a/components/drivers/core/device.c b/components/drivers/core/device.c new file mode 100644 index 0000000000..47482b50d3 --- /dev/null +++ b/components/drivers/core/device.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2007-01-21 Bernard the first version + * 2010-05-04 Bernard add rt_device_init implementation + * 2012-10-20 Bernard add device check in register function, + * provided by Rob <[email protected]> + * 2012-12-25 Bernard return RT_EOK if the device interface not exist. + * 2013-07-09 Grissiom add ref_count support + * 2016-04-02 Bernard fix the open_flag initialization issue. + * 2021-03-19 Meco Man remove rt_device_init_all() + */ + +#include <rtthread.h> +#ifdef RT_USING_POSIX_DEVIO +#include <rtdevice.h> /* for wqueue_init */ +#endif /* RT_USING_POSIX_DEVIO */ + +#ifdef RT_USING_DEVICE + +#ifdef RT_USING_DEVICE_OPS +#define device_init (dev->ops->init) +#define device_open (dev->ops->open) +#define device_close (dev->ops->close) +#define device_read (dev->ops->read) +#define device_write (dev->ops->write) +#define device_control (dev->ops->control) +#else +#define device_init (dev->init) +#define device_open (dev->open) +#define device_close (dev->close) +#define device_read (dev->read) +#define device_write (dev->write) +#define device_control (dev->control) +#endif /* RT_USING_DEVICE_OPS */ + +/** + * @brief This function registers a device driver with a specified name. + * + * @param dev is the pointer of device driver structure. + * + * @param name is the device driver's name. + * + * @param flags is the capabilities flag of device. + * + * @return the error code, RT_EOK on initialization successfully. + */ +rt_err_t rt_device_register(rt_device_t dev, + const char *name, + rt_uint16_t flags) +{ + if (dev == RT_NULL) + return -RT_ERROR; + + if (rt_device_find(name) != RT_NULL) + return -RT_ERROR; + + rt_object_init(&(dev->parent), RT_Object_Class_Device, name); + dev->flag = flags; + dev->ref_count = 0; + dev->open_flag = 0; + +#ifdef RT_USING_POSIX_DEVIO + dev->fops = RT_NULL; + rt_wqueue_init(&(dev->wait_queue)); +#endif /* RT_USING_POSIX_DEVIO */ + + return RT_EOK; +} +RTM_EXPORT(rt_device_register); + +/** + * @brief This function removes a previously registered device driver. + * + * @param dev is the pointer of device driver structure. + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_device_unregister(rt_device_t dev) +{ + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + RT_ASSERT(rt_object_is_systemobject(&dev->parent)); + + rt_object_detach(&(dev->parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_device_unregister); + +/** + * @brief This function finds a device driver by specified name. + * + * @param name is the device driver's name. + * + * @return the registered device driver on successful, or RT_NULL on failure. + */ +rt_device_t rt_device_find(const char *name) +{ + return (rt_device_t)rt_object_find(name, RT_Object_Class_Device); +} +RTM_EXPORT(rt_device_find); + +#ifdef RT_USING_HEAP +/** + * @brief This function creates a device object with user data size. + * + * @param type is the type of the device object. + * + * @param attach_size is the size of user data. + * + * @return the allocated device object, or RT_NULL when failed. + */ +rt_device_t rt_device_create(int type, int attach_size) +{ + int size; + rt_device_t device; + + size = RT_ALIGN(sizeof(struct rt_device), RT_ALIGN_SIZE); + attach_size = RT_ALIGN(attach_size, RT_ALIGN_SIZE); + /* use the total size */ + size += attach_size; + + device = (rt_device_t)rt_malloc(size); + if (device) + { + rt_memset(device, 0x0, sizeof(struct rt_device)); + device->type = (enum rt_device_class_type)type; + } + + return device; +} +RTM_EXPORT(rt_device_create); + +/** + * @brief This function destroy the specific device object. + * + * @param dev is a specific device object. + */ +void rt_device_destroy(rt_device_t dev) +{ + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + RT_ASSERT(rt_object_is_systemobject(&dev->parent) == RT_FALSE); + + rt_object_detach(&(dev->parent)); + + /* release this device object */ + rt_free(dev); +} +RTM_EXPORT(rt_device_destroy); +#endif /* RT_USING_HEAP */ + +/** + * @brief This function will initialize the specified device. + * + * @param dev is the pointer of device driver structure. + * + * @return the result, RT_EOK on successfully. + */ +rt_err_t rt_device_init(rt_device_t dev) +{ + rt_err_t result = RT_EOK; + + RT_ASSERT(dev != RT_NULL); + + /* get device_init handler */ + if (device_init != RT_NULL) + { + if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) + { + result = device_init(dev); + if (result != RT_EOK) + { + RT_DEBUG_LOG(RT_DEBUG_DEVICE, ("To initialize device:%s failed. The error code is %d\n", + dev->parent.name, result)); + } + else + { + dev->flag |= RT_DEVICE_FLAG_ACTIVATED; + } + } + } + + return result; +} + +/** + * @brief This function will open a device. + * + * @param dev is the pointer of device driver structure. + * + * @param oflag is the flags for device open. + * + * @return the result, RT_EOK on successfully. + */ +rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag) +{ + rt_err_t result = RT_EOK; + + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + /* if device is not initialized, initialize it. */ + if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) + { + if (device_init != RT_NULL) + { + result = device_init(dev); + if (result != RT_EOK) + { + RT_DEBUG_LOG(RT_DEBUG_DEVICE, ("To initialize device:%s failed. The error code is %d\n", + dev->parent.name, result)); + + return result; + } + } + + dev->flag |= RT_DEVICE_FLAG_ACTIVATED; + } + + /* device is a stand alone device and opened */ + if ((dev->flag & RT_DEVICE_FLAG_STANDALONE) && + (dev->open_flag & RT_DEVICE_OFLAG_OPEN)) + { + return -RT_EBUSY; + } + + /* device is not opened or opened by other oflag, call device_open interface */ + if (!(dev->open_flag & RT_DEVICE_OFLAG_OPEN) || + ((dev->open_flag & RT_DEVICE_OFLAG_MASK) != (oflag & RT_DEVICE_OFLAG_MASK))) + { + if (device_open != RT_NULL) + { + result = device_open(dev, oflag); + } + else + { + /* set open flag */ + dev->open_flag = (oflag & RT_DEVICE_OFLAG_MASK); + } + } + + /* set open flag */ + if (result == RT_EOK || result == -RT_ENOSYS) + { + dev->open_flag |= RT_DEVICE_OFLAG_OPEN; + + dev->ref_count++; + /* don't let bad things happen silently. If you are bitten by this assert, + * please set the ref_count to a bigger type. */ + RT_ASSERT(dev->ref_count != 0); + } + + return result; +} +RTM_EXPORT(rt_device_open); + +/** + * @brief This function will close a device. + * + * @param dev is the pointer of device driver structure. + * + * @return the result, RT_EOK on successfully. + */ +rt_err_t rt_device_close(rt_device_t dev) +{ + rt_err_t result = RT_EOK; + + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + if (dev->ref_count == 0) + return -RT_ERROR; + + dev->ref_count--; + + if (dev->ref_count != 0) + return RT_EOK; + + /* call device_close interface */ + if (device_close != RT_NULL) + { + result = device_close(dev); + } + + /* set open flag */ + if (result == RT_EOK || result == -RT_ENOSYS) + dev->open_flag = RT_DEVICE_OFLAG_CLOSE; + + return result; +} +RTM_EXPORT(rt_device_close); + +/** + * @brief This function will read some data from a device. + * + * @param dev is the pointer of device driver structure. + * + * @param pos is the position when reading. + * + * @param buffer is a data buffer to save the read data. + * + * @param size is the size of buffer. + * + * @return the actually read size on successful, otherwise 0 will be returned. + * + * @note the unit of size/pos is a block for block device. + */ +rt_ssize_t rt_device_read(rt_device_t dev, + rt_off_t pos, + void *buffer, + rt_size_t size) +{ + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + if (dev->ref_count == 0) + { + rt_set_errno(-RT_ERROR); + return 0; + } + + /* call device_read interface */ + if (device_read != RT_NULL) + { + return device_read(dev, pos, buffer, size); + } + + /* set error code */ + rt_set_errno(-RT_ENOSYS); + + return 0; +} +RTM_EXPORT(rt_device_read); + +/** + * @brief This function will write some data to a device. + * + * @param dev is the pointer of device driver structure. + * + * @param pos is the position when writing. + * + * @param buffer is the data buffer to be written to device. + * + * @param size is the size of buffer. + * + * @return the actually written size on successful, otherwise 0 will be returned. + * + * @note the unit of size/pos is a block for block device. + */ +rt_ssize_t rt_device_write(rt_device_t dev, + rt_off_t pos, + const void *buffer, + rt_size_t size) +{ + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + if (dev->ref_count == 0) + { + rt_set_errno(-RT_ERROR); + return 0; + } + + /* call device_write interface */ + if (device_write != RT_NULL) + { + return device_write(dev, pos, buffer, size); + } + + /* set error code */ + rt_set_errno(-RT_ENOSYS); + + return 0; +} +RTM_EXPORT(rt_device_write); + +/** + * @brief This function will perform a variety of control functions on devices. + * + * @param dev is the pointer of device driver structure. + * + * @param cmd is the command sent to device. + * + * @param arg is the argument of command. + * + * @return the result, -RT_ENOSYS for failed. + */ +rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg) +{ + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + /* call device_write interface */ + if (device_control != RT_NULL) + { + return device_control(dev, cmd, arg); + } + + return -RT_ENOSYS; +} +RTM_EXPORT(rt_device_control); + +/** + * @brief This function will set the reception indication callback function. This callback function + * is invoked when this device receives data. + * + * @param dev is the pointer of device driver structure. + * + * @param rx_ind is the indication callback function. + * + * @return RT_EOK + */ +rt_err_t rt_device_set_rx_indicate(rt_device_t dev, + rt_err_t (*rx_ind)(rt_device_t dev, + rt_size_t size)) +{ + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + dev->rx_indicate = rx_ind; + + return RT_EOK; +} +RTM_EXPORT(rt_device_set_rx_indicate); + +/** + * @brief This function will set a callback function. The callback function + * will be called when device has written data to physical hardware. + * + * @param dev is the pointer of device driver structure. + * + * @param tx_done is the indication callback function. + * + * @return RT_EOK + */ +rt_err_t rt_device_set_tx_complete(rt_device_t dev, + rt_err_t (*tx_done)(rt_device_t dev, + void *buffer)) +{ + /* parameter check */ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + dev->tx_complete = tx_done; + + return RT_EOK; +} +RTM_EXPORT(rt_device_set_tx_complete); + +#ifdef RT_USING_DM +/** + * This function bind drvier and device + * + * @param device the pointer of device structure + * @param driver the pointer of driver 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; + } + 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 /* RT_USING_DM */ +#endif /* RT_USING_DEVICE */ diff --git a/components/drivers/core/driver.c b/components/drivers/core/driver.c new file mode 100644 index 0000000000..fb7b08c4e4 --- /dev/null +++ b/components/drivers/core/driver.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include <rtthread.h> + +#ifdef RT_USING_DM + +#ifdef RT_USING_FDT +#include <dtb_node.h> +#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 RT_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 total_dev_num = 0; + if ((!drv)||(!drv->dev_match)||(!drv->dev_match->compatible)||(!from_node)||(!drv->device_size)) + { + return -RT_EINVAL; + } + + node_list = rt_calloc(max_dev_num,sizeof(void *)); + if(!node_list) + { + return -RT_ERROR; + } + + ret = dtb_node_find_all_compatible_node(from_node,drv->dev_match->compatible,node_list,max_dev_num,&total_dev_num); + if((ret != 0) || (!total_dev_num)) + { + return -RT_ERROR; + } + + for(i = 0; i < total_dev_num; i ++) + { + if (!dtb_node_device_is_available(node_list[i])) + { + continue; + } + device = rt_device_create_since_driver(drv,i); + if(!device) + { + continue; + } + + ret = rt_device_bind_driver(device,drv,node_list[i]); + if(ret != 0) + { + continue; + } + ret = rt_device_probe_and_init(device); + if(ret != 0) + { + continue; + } + } + rt_free(node_list); + return ret; +} +RTM_EXPORT(rt_driver_match_with_dtb); +#endif /* RT_USING_FDT */ + +#endif /* RT_USING_DM */ + diff --git a/components/drivers/misc/SConscript b/components/drivers/misc/SConscript index f9fd17689e..927e662b19 100644 --- a/components/drivers/misc/SConscript +++ b/components/drivers/misc/SConscript @@ -23,9 +23,6 @@ if GetDepend(['RT_USING_PULSE_ENCODER']): if GetDepend(['RT_USING_INPUT_CAPTURE']): src = src + ['rt_inputcapture.c'] -if GetDepend(['RT_USING_DEV_BUS']): - src = src + ['rt_dev_bus.c'] - if GetDepend(['RT_USING_NULL']): src = src + ['rt_null.c'] |
