1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2022-10-13     flybreak     the first version
9  * 2023-04-12     ErikChan     support rt_bus
10  */
11 
12 #include <rtthread.h>
13 
14 #include <string.h>
15 #include <stdlib.h>
16 
17 #define DBG_TAG "dev_bus"
18 #define DBG_LVL DBG_INFO
19 #include <rtdbg.h>
20 
21 #ifdef RT_USING_DEV_BUS
22 
23 #if defined(RT_USING_POSIX_DEVIO)
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <poll.h>
27 #include <sys/ioctl.h>
28 #include <dfs_file.h>
29 
bus_fops_open(struct dfs_file * fd)30 static int bus_fops_open(struct dfs_file *fd)
31 {
32     LOG_D("bus fops open");
33     return 0;
34 }
35 
bus_fops_close(struct dfs_file * fd)36 static int bus_fops_close(struct dfs_file *fd)
37 {
38     LOG_D("bus fops close");
39     return 0;
40 }
41 
42 static const struct dfs_file_ops bus_fops =
43 {
44     bus_fops_open,
45     bus_fops_close,
46     RT_NULL,
47     RT_NULL,
48     RT_NULL,
49     RT_NULL,
50     RT_NULL,
51     RT_NULL,
52     RT_NULL,
53 };
54 #endif
55 
rt_device_bus_create(char * name,int attach_size)56 rt_device_t rt_device_bus_create(char *name, int attach_size)
57 {
58     rt_err_t result = RT_EOK;
59     rt_device_t dev = rt_device_create(RT_Device_Class_Bus, 0);
60 
61     result = rt_device_register(dev, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE);
62     if (result < 0)
63     {
64         rt_kprintf("dev bus [%s] register failed!, ret=%d\n", name, result);
65         return RT_NULL;
66     }
67 #if defined(RT_USING_POSIX_DEVIO)
68     dev->fops = &bus_fops;
69 #endif
70 
71     LOG_D("bus create");
72     return dev;
73 }
74 
rt_device_bus_destroy(rt_device_t dev)75 rt_err_t rt_device_bus_destroy(rt_device_t dev)
76 {
77     rt_device_unregister(dev);
78     dev->parent.type = RT_Object_Class_Device;
79     rt_device_destroy(dev);
80     LOG_D("bus destroy");
81     return RT_EOK;
82 }
83 
84 #endif
85 
86 #ifdef RT_USING_DM
87 #include <drivers/core/bus.h>
88 
89 static RT_DEFINE_SPINLOCK(bus_lock);
90 static rt_list_t bus_nodes = RT_LIST_OBJECT_INIT(bus_nodes);
91 
_dm_bus_lock(struct rt_spinlock * spinlock)92 static void _dm_bus_lock(struct rt_spinlock *spinlock)
93 {
94     rt_hw_spin_lock(&spinlock->lock);
95 }
96 
_dm_bus_unlock(struct rt_spinlock * spinlock)97 static void _dm_bus_unlock(struct rt_spinlock *spinlock)
98 {
99     rt_hw_spin_unlock(&spinlock->lock);
100 }
101 
102 /**
103  *  @brief This function loop the dev_list of the bus, and call fn in each loop
104  *
105  *  @param bus the target bus
106  *
107  *  @param data the data push when call fn
108  *
109  *  @param fn  the function callback in each loop
110  *
111  *  @return the error code, RT_EOK on added successfully.
112  */
rt_bus_for_each_dev(rt_bus_t bus,void * data,int (* fn)(rt_device_t dev,void *))113 rt_err_t rt_bus_for_each_dev(rt_bus_t bus, void *data, int (*fn)(rt_device_t dev, void *))
114 {
115     rt_device_t dev;
116     rt_err_t err = -RT_EEMPTY;
117     rt_list_t *dev_list;
118     struct rt_spinlock *dev_lock;
119 
120     RT_ASSERT(bus != RT_NULL);
121 
122     dev_list = &bus->dev_list;
123     dev_lock = &bus->dev_lock;
124 
125     _dm_bus_lock(dev_lock);
126     dev = rt_list_entry(dev_list->next, struct rt_device, node);
127     _dm_bus_unlock(dev_lock);
128 
129     while (&dev->node != dev_list)
130     {
131         if (!fn(dev, data))
132         {
133             err = RT_EOK;
134 
135             break;
136         }
137 
138         _dm_bus_lock(dev_lock);
139         dev = rt_list_entry(dev->node.next, struct rt_device, node);
140         _dm_bus_unlock(dev_lock);
141     }
142 
143     return err;
144 }
145 
146 /**
147  *  @brief This function loop the drv_list of the bus, and call fn in each loop
148  *
149  *  @param bus the target bus
150  *
151  *  @param data the data push when call fn
152  *
153  *  @param fn  the function callback in each loop
154  *
155  *  @return the error code, RT_EOK on added successfully.
156  */
rt_bus_for_each_drv(rt_bus_t bus,void * data,int (* fn)(rt_driver_t drv,void *))157 rt_err_t rt_bus_for_each_drv(rt_bus_t bus, void *data, int (*fn)(rt_driver_t drv, void *))
158 {
159     rt_driver_t drv;
160     rt_err_t err = -RT_EEMPTY;
161     rt_list_t *drv_list;
162     struct rt_spinlock *drv_lock;
163 
164     RT_ASSERT(bus != RT_NULL);
165 
166     drv_list = &bus->drv_list;
167     drv_lock = &bus->drv_lock;
168 
169     _dm_bus_lock(drv_lock);
170     drv = rt_list_entry(drv_list->next, struct rt_driver, node);
171     _dm_bus_unlock(drv_lock);
172 
173     while (&drv->node != drv_list)
174     {
175         if (!fn(drv, data))
176         {
177             err = RT_EOK;
178 
179             break;
180         }
181 
182         _dm_bus_lock(drv_lock);
183         drv = rt_list_entry(drv->node.next, struct rt_driver, node);
184         _dm_bus_unlock(drv_lock);
185     }
186 
187     return err;
188 }
189 
bus_probe(rt_driver_t drv,rt_device_t dev)190 static rt_err_t bus_probe(rt_driver_t drv, rt_device_t dev)
191 {
192     rt_bus_t bus = drv->bus;
193     rt_err_t err = -RT_EEMPTY;
194 
195     if (!bus)
196     {
197         bus = dev->bus;
198     }
199 
200     if (!dev->drv && bus->match(drv, dev))
201     {
202         dev->drv = drv;
203 
204         err = bus->probe(dev);
205 
206         if (err)
207         {
208             dev->drv = RT_NULL;
209         }
210     }
211 
212     return err;
213 }
214 
bus_probe_driver(rt_device_t dev,void * drv_ptr)215 static int bus_probe_driver(rt_device_t dev, void *drv_ptr)
216 {
217     bus_probe(drv_ptr, dev);
218 
219     /*
220      * The driver is shared by multiple devices,
221      * so we always return the '1' to enumerate all devices.
222      */
223     return 1;
224 }
225 
bus_probe_device(rt_driver_t drv,void * dev_ptr)226 static int bus_probe_device(rt_driver_t drv, void *dev_ptr)
227 {
228     rt_err_t err;
229 
230     err = bus_probe(drv, dev_ptr);
231 
232     if (!err)
233     {
234         rt_bus_t bus = drv->bus;
235 
236         _dm_bus_lock(&bus->drv_lock);
237         ++drv->ref_count;
238         _dm_bus_unlock(&bus->drv_lock);
239     }
240 
241     return err;
242 }
243 
244 /**
245  *  @brief This function add a driver to the drv_list of a specific bus
246  *
247  *  @param bus the bus to add
248  *
249  *  @param drv the driver to be added
250  *
251  *  @return the error code, RT_EOK on added successfully.
252  */
rt_bus_add_driver(rt_bus_t bus,rt_driver_t drv)253 rt_err_t rt_bus_add_driver(rt_bus_t bus, rt_driver_t drv)
254 {
255     RT_ASSERT(bus != RT_NULL);
256     RT_ASSERT(drv != RT_NULL);
257 
258     drv->bus = bus;
259     rt_list_init(&drv->node);
260 
261     _dm_bus_lock(&bus->drv_lock);
262     rt_list_insert_before(&bus->drv_list, &drv->node);
263     _dm_bus_unlock(&bus->drv_lock);
264 
265     rt_bus_for_each_dev(bus, drv, bus_probe_driver);
266 
267     return RT_EOK;
268 }
269 
270 /**
271  *  @brief This function add a device to the dev_list of a specific bus
272  *
273  *  @param bus the bus to add
274  *
275  *  @param dev the device to be added
276  *
277  *  @return the error code, RT_EOK on added successfully.
278  */
rt_bus_add_device(rt_bus_t bus,rt_device_t dev)279 rt_err_t rt_bus_add_device(rt_bus_t bus, rt_device_t dev)
280 {
281     RT_ASSERT(bus != RT_NULL);
282     RT_ASSERT(dev != RT_NULL);
283 
284     dev->bus = bus;
285     rt_list_init(&dev->node);
286 
287     _dm_bus_lock(&bus->dev_lock);
288     rt_list_insert_before(&bus->dev_list, &dev->node);
289     _dm_bus_unlock(&bus->dev_lock);
290 
291     rt_bus_for_each_drv(bus, dev, bus_probe_device);
292 
293     return RT_EOK;
294 }
295 
296 /**
297  *  @brief This function remove a driver from bus
298  *
299  *  @param drv the driver to be removed
300  *
301  *  @return the error code, RT_EOK on added successfully.
302  */
rt_bus_remove_driver(rt_driver_t drv)303 rt_err_t rt_bus_remove_driver(rt_driver_t drv)
304 {
305     rt_err_t err;
306     rt_bus_t bus;
307 
308     RT_ASSERT(drv != RT_NULL);
309     RT_ASSERT(drv->bus != RT_NULL);
310 
311     bus = drv->bus;
312 
313     LOG_D("Bus(%s) remove driver %s", bus->name, drv->parent.name);
314 
315     _dm_bus_lock(&bus->drv_lock);
316 
317     if (drv->ref_count)
318     {
319         err = -RT_EBUSY;
320     }
321     else
322     {
323         rt_list_remove(&drv->node);
324         err = RT_EOK;
325     }
326 
327     _dm_bus_unlock(&bus->drv_lock);
328 
329     return err;
330 }
331 
332 /**
333  *  @brief This function remove a device from bus
334  *
335  *  @param dev the device to be removed
336  *
337  *  @return the error code, RT_EOK on added successfully.
338  */
rt_bus_remove_device(rt_device_t dev)339 rt_err_t rt_bus_remove_device(rt_device_t dev)
340 {
341     rt_bus_t bus;
342     rt_driver_t drv;
343     rt_err_t err = RT_EOK;
344 
345     RT_ASSERT(dev != RT_NULL);
346     RT_ASSERT(dev->bus != RT_NULL);
347 
348     bus = dev->bus;
349     drv = dev->drv;
350 
351     LOG_D("Bus(%s) remove device %s", bus->name, dev->parent.name);
352 
353     _dm_bus_lock(&bus->dev_lock);
354     rt_list_remove(&dev->node);
355     _dm_bus_unlock(&bus->dev_lock);
356 
357     if (dev->bus->remove)
358     {
359         err = dev->bus->remove(dev);
360     }
361     else if (drv)
362     {
363         if (drv->remove)
364         {
365             err = drv->remove(dev);
366         }
367 
368         /* device and driver are in the same bus */
369         _dm_bus_lock(&bus->drv_lock);
370         --drv->ref_count;
371         _dm_bus_unlock(&bus->drv_lock);
372     }
373 
374     return err;
375 }
376 
377 struct bus_shutdown_info
378 {
379     rt_bus_t bus;
380 
381     rt_err_t err;
382 };
383 
device_shutdown(rt_device_t dev,void * info_ptr)384 static int device_shutdown(rt_device_t dev, void *info_ptr)
385 {
386     rt_bus_t bus;
387     rt_err_t err = RT_EOK;
388     struct bus_shutdown_info *info = info_ptr;
389 
390     bus = info->bus;
391 
392     if (bus->shutdown)
393     {
394         LOG_D("Device(%s) shutdown", dev->parent.name);
395         err = bus->shutdown(dev);
396         LOG_D("  Result: %s", rt_strerror(err));
397     }
398     else if (dev->drv && dev->drv->shutdown)
399     {
400         LOG_D("Device(%s) shutdown", dev->parent.name);
401         err = dev->drv->shutdown(dev);
402         LOG_D("  Result: %s", rt_strerror(err));
403     }
404 
405     if (err)
406     {
407         /* Only get the last one while system not crash */
408         info->err = err;
409     }
410 
411     /* Go on, we want to ask all devices to shutdown */
412     return 1;
413 }
414 
415 /**
416  *  @brief This function call all buses' shutdown
417  *
418  *  @return the error code, RT_EOK on shutdown successfully.
419  */
rt_bus_shutdown(void)420 rt_err_t rt_bus_shutdown(void)
421 {
422     rt_bus_t bus = RT_NULL;
423     struct bus_shutdown_info info =
424     {
425         .err = RT_EOK,
426     };
427 
428     _dm_bus_lock(&bus_lock);
429 
430     rt_list_for_each_entry(bus, &bus_nodes, list)
431     {
432         info.bus = bus;
433         rt_bus_for_each_dev(bus, &info, device_shutdown);
434     }
435 
436     _dm_bus_unlock(&bus_lock);
437 
438     return info.err;
439 }
440 
441 /**
442  *  @brief This function find a bus by name
443  *  @param bus the name to be finded
444  *
445  *  @return the bus finded by name.
446  */
rt_bus_find_by_name(const char * name)447 rt_bus_t rt_bus_find_by_name(const char *name)
448 {
449     rt_bus_t bus = RT_NULL;
450 
451     RT_ASSERT(name != RT_NULL);
452 
453     _dm_bus_lock(&bus_lock);
454 
455     rt_list_for_each_entry(bus, &bus_nodes, list)
456     {
457         if (!rt_strncmp(bus->name, name, RT_NAME_MAX))
458         {
459             break;
460         }
461     }
462 
463     _dm_bus_unlock(&bus_lock);
464 
465     return bus;
466 }
467 
468 /**
469  *  @brief This function transfer dev_list and drv_list to the other bus
470  *
471  *  @param new_bus the bus to transfer
472  *
473  *  @param dev the target device
474  *
475  *  @return the error code, RT_EOK on added successfully.
476  */
rt_bus_reload_driver_device(rt_bus_t new_bus,rt_device_t dev)477 rt_err_t rt_bus_reload_driver_device(rt_bus_t new_bus, rt_device_t dev)
478 {
479     rt_bus_t old_bus;
480 
481     RT_ASSERT(new_bus != RT_NULL);
482     RT_ASSERT(dev != RT_NULL);
483     RT_ASSERT(dev->bus != RT_NULL);
484     RT_ASSERT(dev->bus != new_bus);
485 
486     old_bus = dev->bus;
487 
488     _dm_bus_lock(&old_bus->dev_lock);
489     rt_list_remove(&dev->node);
490     _dm_bus_unlock(&old_bus->dev_lock);
491 
492     return rt_bus_add_device(new_bus, dev);
493 }
494 
495 /**
496  *  @brief This function register a bus
497  *  @param bus the bus to be registered
498  *
499  *  @return the error code, RT_EOK on registeration successfully.
500  */
rt_bus_register(rt_bus_t bus)501 rt_err_t rt_bus_register(rt_bus_t bus)
502 {
503     RT_ASSERT(bus != RT_NULL);
504 
505     rt_list_init(&bus->list);
506     rt_list_init(&bus->dev_list);
507     rt_list_init(&bus->drv_list);
508 
509     rt_spin_lock_init(&bus->dev_lock);
510     rt_spin_lock_init(&bus->drv_lock);
511 
512     _dm_bus_lock(&bus_lock);
513 
514     rt_list_insert_before(&bus_nodes, &bus->list);
515 
516     _dm_bus_unlock(&bus_lock);
517 
518     return RT_EOK;
519 }
520 #endif
521