device-remove.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * Device manager
  3. *
  4. * Copyright (c) 2014 Google, Inc
  5. *
  6. * (C) Copyright 2012
  7. * Pavel Herrmann <morpheus.ibis@gmail.com>
  8. *
  9. * SPDX-License-Identifier: GPL-2.0+
  10. */
  11. #include <common.h>
  12. #include <errno.h>
  13. #include <malloc.h>
  14. #include <dm/device.h>
  15. #include <dm/device-internal.h>
  16. #include <dm/uclass.h>
  17. #include <dm/uclass-internal.h>
  18. #include <dm/util.h>
  19. int device_unbind_children(struct udevice *dev)
  20. {
  21. struct udevice *pos, *n;
  22. int ret, saved_ret = 0;
  23. assert(dev);
  24. list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
  25. ret = device_unbind(pos);
  26. if (ret && !saved_ret)
  27. saved_ret = ret;
  28. }
  29. return saved_ret;
  30. }
  31. int device_remove_children(struct udevice *dev)
  32. {
  33. struct udevice *pos, *n;
  34. int ret;
  35. assert(dev);
  36. list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
  37. ret = device_remove(pos);
  38. if (ret)
  39. return ret;
  40. }
  41. return 0;
  42. }
  43. int device_unbind(struct udevice *dev)
  44. {
  45. const struct driver *drv;
  46. int ret;
  47. if (!dev)
  48. return -EINVAL;
  49. if (dev->flags & DM_FLAG_ACTIVATED)
  50. return -EINVAL;
  51. drv = dev->driver;
  52. assert(drv);
  53. if (drv->unbind) {
  54. ret = drv->unbind(dev);
  55. if (ret)
  56. return ret;
  57. }
  58. ret = device_unbind_children(dev);
  59. if (ret)
  60. return ret;
  61. if (dev->flags & DM_FLAG_ALLOC_PDATA) {
  62. free(dev->platdata);
  63. dev->platdata = NULL;
  64. }
  65. if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
  66. free(dev->uclass_platdata);
  67. dev->uclass_platdata = NULL;
  68. }
  69. if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
  70. free(dev->parent_platdata);
  71. dev->parent_platdata = NULL;
  72. }
  73. ret = uclass_unbind_device(dev);
  74. if (ret)
  75. return ret;
  76. if (dev->parent)
  77. list_del(&dev->sibling_node);
  78. free(dev);
  79. return 0;
  80. }
  81. /**
  82. * device_free() - Free memory buffers allocated by a device
  83. * @dev: Device that is to be started
  84. */
  85. void device_free(struct udevice *dev)
  86. {
  87. int size;
  88. if (dev->driver->priv_auto_alloc_size) {
  89. free(dev->priv);
  90. dev->priv = NULL;
  91. }
  92. size = dev->uclass->uc_drv->per_device_auto_alloc_size;
  93. if (size) {
  94. free(dev->uclass_priv);
  95. dev->uclass_priv = NULL;
  96. }
  97. if (dev->parent) {
  98. size = dev->parent->driver->per_child_auto_alloc_size;
  99. if (!size) {
  100. size = dev->parent->uclass->uc_drv->
  101. per_child_auto_alloc_size;
  102. }
  103. if (size) {
  104. free(dev->parent_priv);
  105. dev->parent_priv = NULL;
  106. }
  107. }
  108. }
  109. int device_remove(struct udevice *dev)
  110. {
  111. const struct driver *drv;
  112. int ret;
  113. if (!dev)
  114. return -EINVAL;
  115. if (!(dev->flags & DM_FLAG_ACTIVATED))
  116. return 0;
  117. drv = dev->driver;
  118. assert(drv);
  119. ret = uclass_pre_remove_device(dev);
  120. if (ret)
  121. return ret;
  122. ret = device_remove_children(dev);
  123. if (ret)
  124. goto err;
  125. if (drv->remove) {
  126. ret = drv->remove(dev);
  127. if (ret)
  128. goto err_remove;
  129. }
  130. if (dev->parent && dev->parent->driver->child_post_remove) {
  131. ret = dev->parent->driver->child_post_remove(dev);
  132. if (ret) {
  133. dm_warn("%s: Device '%s' failed child_post_remove()",
  134. __func__, dev->name);
  135. }
  136. }
  137. device_free(dev);
  138. dev->seq = -1;
  139. dev->flags &= ~DM_FLAG_ACTIVATED;
  140. return ret;
  141. err_remove:
  142. /* We can't put the children back */
  143. dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
  144. __func__, dev->name);
  145. err:
  146. ret = uclass_post_probe_device(dev);
  147. if (ret) {
  148. dm_warn("%s: Device '%s' failed to post_probe on error path\n",
  149. __func__, dev->name);
  150. }
  151. return ret;
  152. }