bus.c 10 KB

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