1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2007-01-21     Bernard      the first version
9  * 2010-05-04     Bernard      add rt_device_init implementation
10  * 2012-10-20     Bernard      add device check in register function,
11  *                             provided by Rob <rdent@iinet.net.au>
12  * 2012-12-25     Bernard      return RT_EOK if the device interface not exist.
13  * 2013-07-09     Grissiom     add ref_count support
14  * 2016-04-02     Bernard      fix the open_flag initialization issue.
15  * 2021-03-19     Meco Man     remove rt_device_init_all()
16  * 2024-09-15     milo         fix log format issue
17  *                             fix reopen with a different oflag issue
18  */
19 
20 #include <rtthread.h>
21 
22 #define DBG_TAG           "kernel.device"
23 #ifdef RT_DEBUG_DEVICE
24 #define DBG_LVL           DBG_LOG
25 #else
26 #define DBG_LVL           DBG_WARNING
27 #endif /* defined (RT_DEBUG_DEVICE) */
28 #include <rtdbg.h>
29 
30 #ifdef RT_USING_POSIX_DEVIO
31 #include <rtdevice.h> /* for wqueue_init */
32 #endif /* RT_USING_POSIX_DEVIO */
33 
34 #if defined (RT_USING_DFS_V2) && defined (RT_USING_DFS_DEVFS)
35 #include <devfs.h>
36 #endif /* RT_USING_DFS_V2  RT_USING_DFS_DEVFS */
37 
38 #ifdef RT_USING_DEVICE
39 
40 #ifdef RT_USING_DEVICE_OPS
41 #define device_init     (dev->ops ? dev->ops->init : RT_NULL)
42 #define device_open     (dev->ops ? dev->ops->open : RT_NULL)
43 #define device_close    (dev->ops ? dev->ops->close : RT_NULL)
44 #define device_read     (dev->ops ? dev->ops->read : RT_NULL)
45 #define device_write    (dev->ops ? dev->ops->write : RT_NULL)
46 #define device_control  (dev->ops ? dev->ops->control : RT_NULL)
47 #else
48 #define device_init     (dev->init)
49 #define device_open     (dev->open)
50 #define device_close    (dev->close)
51 #define device_read     (dev->read)
52 #define device_write    (dev->write)
53 #define device_control  (dev->control)
54 #endif /* RT_USING_DEVICE_OPS */
55 
56 /**
57  * @brief This function registers a device driver with a specified name.
58  *
59  * @param dev is the pointer of device driver structure.
60  *
61  * @param name is the device driver's name.
62  *
63  * @param flags is the capabilities flag of device.
64  *
65  * @return the error code, RT_EOK on initialization successfully.
66  */
rt_device_register(rt_device_t dev,const char * name,rt_uint16_t flags)67 rt_err_t rt_device_register(rt_device_t dev,
68                             const char *name,
69                             rt_uint16_t flags)
70 {
71     if (dev == RT_NULL)
72         return -RT_ERROR;
73 
74     if (rt_device_find(name) != RT_NULL)
75         return -RT_ERROR;
76 
77     rt_object_init(&(dev->parent), RT_Object_Class_Device, name);
78     dev->flag = flags;
79     dev->ref_count = 0;
80     dev->open_flag = 0;
81 
82 #ifdef RT_USING_POSIX_DEVIO
83     dev->fops = RT_NULL;
84     rt_wqueue_init(&(dev->wait_queue));
85 #endif /* RT_USING_POSIX_DEVIO */
86 
87 #if defined (RT_USING_DFS_V2) && defined (RT_USING_DFS_DEVFS)
88     dfs_devfs_device_add(dev);
89 #endif /* RT_USING_DFS_V2 */
90 
91     return RT_EOK;
92 }
93 RTM_EXPORT(rt_device_register);
94 
95 /**
96  * @brief This function removes a previously registered device driver.
97  *
98  * @param dev is the pointer of device driver structure.
99  *
100  * @return the error code, RT_EOK on successfully.
101  */
rt_device_unregister(rt_device_t dev)102 rt_err_t rt_device_unregister(rt_device_t dev)
103 {
104     /* parameter check */
105     RT_ASSERT(dev != RT_NULL);
106     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
107     RT_ASSERT(rt_object_is_systemobject(&dev->parent));
108 
109     rt_object_detach(&(dev->parent));
110 
111     return RT_EOK;
112 }
113 RTM_EXPORT(rt_device_unregister);
114 
115 /**
116  * @brief This function finds a device driver by specified name.
117  *
118  * @param name is the device driver's name.
119  *
120  * @return the registered device driver on successful, or RT_NULL on failure.
121  */
rt_device_find(const char * name)122 rt_device_t rt_device_find(const char *name)
123 {
124     return (rt_device_t)rt_object_find(name, RT_Object_Class_Device);
125 }
126 RTM_EXPORT(rt_device_find);
127 
128 #ifdef RT_USING_HEAP
129 /**
130  * @brief This function creates a device object with user data size.
131  *
132  * @param type is the type of the device object.
133  *
134  * @param attach_size is the size of user data.
135  *
136  * @return the allocated device object, or RT_NULL when failed.
137  */
rt_device_create(int type,int attach_size)138 rt_device_t rt_device_create(int type, int attach_size)
139 {
140     int size;
141     rt_device_t device;
142 
143     size = RT_ALIGN(sizeof(struct rt_device), RT_ALIGN_SIZE);
144     attach_size = RT_ALIGN(attach_size, RT_ALIGN_SIZE);
145     /* use the total size */
146     size += attach_size;
147 
148     device = (rt_device_t)rt_malloc(size);
149     if (device)
150     {
151         rt_memset(device, 0x0, sizeof(struct rt_device));
152         device->type = (enum rt_device_class_type)type;
153     }
154 
155     return device;
156 }
157 RTM_EXPORT(rt_device_create);
158 
159 /**
160  * @brief This function destroy the specific device object.
161  *
162  * @param dev is a specific device object.
163  */
rt_device_destroy(rt_device_t dev)164 void rt_device_destroy(rt_device_t dev)
165 {
166     /* parameter check */
167     RT_ASSERT(dev != RT_NULL);
168     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Null);
169     RT_ASSERT(rt_object_is_systemobject(&dev->parent) == RT_FALSE);
170 
171     rt_object_detach(&(dev->parent));
172 
173     /* release this device object */
174     rt_free(dev);
175 }
176 RTM_EXPORT(rt_device_destroy);
177 #endif /* RT_USING_HEAP */
178 
179 /**
180  * @brief This function will initialize the specified device.
181  *
182  * @param dev is the pointer of device driver structure.
183  *
184  * @return the result, RT_EOK on successfully.
185  */
rt_device_init(rt_device_t dev)186 rt_err_t rt_device_init(rt_device_t dev)
187 {
188     rt_err_t result = RT_EOK;
189 
190     RT_ASSERT(dev != RT_NULL);
191 
192     /* get device_init handler */
193     if (device_init != RT_NULL)
194     {
195         if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
196         {
197             result = device_init(dev);
198             if (result != RT_EOK)
199             {
200                 LOG_E("To initialize device:%.*s failed. The error code is %d",
201                       RT_NAME_MAX, dev->parent.name, result);
202             }
203             else
204             {
205                 dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
206             }
207         }
208     }
209 
210     return result;
211 }
212 
213 /**
214  * @brief This function will open a device.
215  *
216  * @param dev is the pointer of device driver structure.
217  *
218  * @param oflag is the flags for device open.
219  *
220  * @return the result, RT_EOK on successfully.
221  */
rt_device_open(rt_device_t dev,rt_uint16_t oflag)222 rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag)
223 {
224     rt_err_t result = RT_EOK;
225 
226     /* parameter check */
227     RT_ASSERT(dev != RT_NULL);
228     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
229 
230     /* if device is not initialized, initialize it. */
231     if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
232     {
233         if (device_init != RT_NULL)
234         {
235             result = device_init(dev);
236             if (result != RT_EOK)
237             {
238                 LOG_E("To initialize device:%.*s failed. The error code is %d",
239                       RT_NAME_MAX, dev->parent.name, result);
240 
241                 return result;
242             }
243         }
244 
245         dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
246     }
247 
248     /* device is a stand alone device and opened */
249     if ((dev->flag & RT_DEVICE_FLAG_STANDALONE) &&
250         (dev->open_flag & RT_DEVICE_OFLAG_OPEN))
251     {
252         return -RT_EBUSY;
253     }
254 
255     /* device is not opened or opened by other oflag, call device_open interface */
256     if (!(dev->open_flag & RT_DEVICE_OFLAG_OPEN) ||
257          ((dev->open_flag & RT_DEVICE_OFLAG_MASK) != ((oflag & RT_DEVICE_OFLAG_MASK) | RT_DEVICE_OFLAG_OPEN)))
258     {
259         if (device_open != RT_NULL)
260         {
261             result = device_open(dev, oflag);
262         }
263         else
264         {
265             /* set open flag */
266             dev->open_flag = (oflag & RT_DEVICE_OFLAG_MASK);
267         }
268     }
269 
270     /* set open flag */
271     if (result == RT_EOK || result == -RT_ENOSYS)
272     {
273         dev->open_flag |= RT_DEVICE_OFLAG_OPEN;
274 
275         dev->ref_count++;
276         /* don't let bad things happen silently. If you are bitten by this assert,
277         * please set the ref_count to a bigger type. */
278         RT_ASSERT(dev->ref_count != 0);
279     }
280 
281     return result;
282 }
283 RTM_EXPORT(rt_device_open);
284 
285 /**
286  * @brief This function will close a device.
287  *
288  * @param dev is the pointer of device driver structure.
289  *
290  * @return the result, RT_EOK on successfully.
291  */
rt_device_close(rt_device_t dev)292 rt_err_t rt_device_close(rt_device_t dev)
293 {
294     rt_err_t result = RT_EOK;
295 
296     /* parameter check */
297     RT_ASSERT(dev != RT_NULL);
298     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
299 
300     if (dev->ref_count == 0)
301         return -RT_ERROR;
302 
303     dev->ref_count--;
304 
305     if (dev->ref_count != 0)
306         return RT_EOK;
307 
308     /* call device_close interface */
309     if (device_close != RT_NULL)
310     {
311         result = device_close(dev);
312     }
313 
314     /* set open flag */
315     if (result == RT_EOK || result == -RT_ENOSYS)
316         dev->open_flag = RT_DEVICE_OFLAG_CLOSE;
317 
318     return result;
319 }
320 RTM_EXPORT(rt_device_close);
321 
322 /**
323  * @brief This function will read some data from a device.
324  *
325  * @param dev is the pointer of device driver structure.
326  *
327  * @param pos is the position when reading.
328  *
329  * @param buffer is a data buffer to save the read data.
330  *
331  * @param size is the size of buffer.
332  *
333  * @return the actually read size on successful, otherwise 0 will be returned.
334  *
335  * @note the unit of size/pos is a block for block device.
336  */
rt_device_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)337 rt_ssize_t rt_device_read(rt_device_t dev,
338                          rt_off_t    pos,
339                          void       *buffer,
340                          rt_size_t   size)
341 {
342     /* parameter check */
343     RT_ASSERT(dev != RT_NULL);
344     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
345 
346     if (dev->ref_count == 0)
347     {
348         rt_set_errno(-RT_ERROR);
349         return 0;
350     }
351 
352     /* call device_read interface */
353     if (device_read != RT_NULL)
354     {
355         return device_read(dev, pos, buffer, size);
356     }
357 
358     /* set error code */
359     rt_set_errno(-RT_ENOSYS);
360 
361     return 0;
362 }
363 RTM_EXPORT(rt_device_read);
364 
365 /**
366  * @brief This function will write some data to a device.
367  *
368  * @param dev is the pointer of device driver structure.
369  *
370  * @param pos is the position when writing.
371  *
372  * @param buffer is the data buffer to be written to device.
373  *
374  * @param size is the size of buffer.
375  *
376  * @return the actually written size on successful, otherwise 0 will be returned.
377  *
378  * @note the unit of size/pos is a block for block device.
379  */
rt_device_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)380 rt_ssize_t rt_device_write(rt_device_t dev,
381                           rt_off_t    pos,
382                           const void *buffer,
383                           rt_size_t   size)
384 {
385     /* parameter check */
386     RT_ASSERT(dev != RT_NULL);
387     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
388 
389     if (dev->ref_count == 0)
390     {
391         rt_set_errno(-RT_ERROR);
392         return 0;
393     }
394 
395     /* call device_write interface */
396     if (device_write != RT_NULL)
397     {
398         return device_write(dev, pos, buffer, size);
399     }
400 
401     /* set error code */
402     rt_set_errno(-RT_ENOSYS);
403 
404     return 0;
405 }
406 RTM_EXPORT(rt_device_write);
407 
408 /**
409  * @brief This function will perform a variety of control functions on devices.
410  *
411  * @param dev is the pointer of device driver structure.
412  *
413  * @param cmd is the command sent to device.
414  *
415  * @param arg is the argument of command.
416  *
417  * @return the result, -RT_ENOSYS for failed.
418  */
rt_device_control(rt_device_t dev,int cmd,void * arg)419 rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg)
420 {
421     /* parameter check */
422     RT_ASSERT(dev != RT_NULL);
423     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
424 
425     /* call device_write interface */
426     if (device_control != RT_NULL)
427     {
428         return device_control(dev, cmd, arg);
429     }
430 
431     return -RT_ENOSYS;
432 }
433 RTM_EXPORT(rt_device_control);
434 
435 /**
436  * @brief This function will set the reception indication callback function. This callback function
437  *        is invoked when this device receives data.
438  *
439  * @param dev is the pointer of device driver structure.
440  *
441  * @param rx_ind is the indication callback function.
442  *
443  * @return RT_EOK
444  */
rt_device_set_rx_indicate(rt_device_t dev,rt_err_t (* rx_ind)(rt_device_t dev,rt_size_t size))445 rt_err_t rt_device_set_rx_indicate(rt_device_t dev,
446                                    rt_err_t (*rx_ind)(rt_device_t dev,
447                                    rt_size_t size))
448 {
449     /* parameter check */
450     RT_ASSERT(dev != RT_NULL);
451     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
452 
453     dev->rx_indicate = rx_ind;
454 
455     return RT_EOK;
456 }
457 RTM_EXPORT(rt_device_set_rx_indicate);
458 
459 /**
460  * @brief This function will set a callback function. The callback function
461  *        will be called when device has written data to physical hardware.
462  *
463  * @param dev is the pointer of device driver structure.
464  *
465  * @param tx_done is the indication callback function.
466  *
467  * @return RT_EOK
468  */
rt_device_set_tx_complete(rt_device_t dev,rt_err_t (* tx_done)(rt_device_t dev,void * buffer))469 rt_err_t rt_device_set_tx_complete(rt_device_t dev,
470                                    rt_err_t (*tx_done)(rt_device_t dev,
471                                    void *buffer))
472 {
473     /* parameter check */
474     RT_ASSERT(dev != RT_NULL);
475     RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device);
476 
477     dev->tx_complete = tx_done;
478 
479     return RT_EOK;
480 }
481 RTM_EXPORT(rt_device_set_tx_complete);
482 
483 #endif /* RT_USING_DEVICE */
484