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