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