external_notify.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2016-2023 Samsung Electronics Co. Ltd.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. */
  10. /* usb notify layer v4.0 */
  11. #define pr_fmt(fmt) "usb_notify: " fmt
  12. #include <linux/module.h>
  13. #include <linux/kernel.h>
  14. #include <linux/err.h>
  15. #include <linux/usb.h>
  16. #include <linux/usb_notify.h>
  17. struct external_notify_struct {
  18. struct blocking_notifier_head notifier_call_chain;
  19. int call_chain_init;
  20. };
  21. #define SET_EXTERNAL_NOTIFY_BLOCK(nb, fn, dev) do { \
  22. (nb)->notifier_call = (fn); \
  23. (nb)->priority = (dev); \
  24. } while (0)
  25. #define DESTROY_EXTERNAL_NOTIFY_BLOCK(nb) \
  26. SET_EXTERNAL_NOTIFY_BLOCK(nb, NULL, -1)
  27. static struct external_notify_struct external_notifier;
  28. static const char *cmd_string(unsigned long cmd)
  29. {
  30. switch (cmd) {
  31. case EXTERNAL_NOTIFY_3S_NODEVICE:
  32. return "3s_no_device";
  33. case EXTERNAL_NOTIFY_DEVICE_CONNECT:
  34. return "device_connect";
  35. case EXTERNAL_NOTIFY_HOSTBLOCK_PRE:
  36. return "host_block_pre";
  37. case EXTERNAL_NOTIFY_HOSTBLOCK_POST:
  38. return "host_block_post";
  39. case EXTERNAL_NOTIFY_MDMBLOCK_PRE:
  40. return "mdm_block_pre";
  41. case EXTERNAL_NOTIFY_MDMBLOCK_POST:
  42. return "mdm_block_post";
  43. case EXTERNAL_NOTIFY_POWERROLE:
  44. return "power_role_notify";
  45. case EXTERNAL_NOTIFY_DEVICEADD:
  46. return "host_mode_device_added";
  47. case EXTERNAL_NOTIFY_HOSTBLOCK_EARLY:
  48. return "host_block_pre_fast";
  49. case EXTERNAL_NOTIFY_VBUS_RESET:
  50. return "vbus_reset";
  51. case EXTERNAL_NOTIFY_POSSIBLE_USB:
  52. return "possible_usb";
  53. default:
  54. return "undefined";
  55. }
  56. }
  57. static const char *listener_string(int listener)
  58. {
  59. switch (listener) {
  60. case EXTERNAL_NOTIFY_DEV_MUIC:
  61. return "muic";
  62. case EXTERNAL_NOTIFY_DEV_CHARGER:
  63. return "charger";
  64. case EXTERNAL_NOTIFY_DEV_PDIC:
  65. return "pdic";
  66. case EXTERNAL_NOTIFY_DEV_MANAGER:
  67. return "manager";
  68. default:
  69. return "undefined";
  70. }
  71. }
  72. static int create_external_notify(void)
  73. {
  74. if (!external_notifier.call_chain_init) {
  75. unl_info("%s\n", __func__);
  76. BLOCKING_INIT_NOTIFIER_HEAD
  77. (&(external_notifier.notifier_call_chain));
  78. external_notifier.call_chain_init = 1;
  79. }
  80. return 0;
  81. }
  82. int usb_external_notify_register(struct notifier_block *nb,
  83. notifier_fn_t notifier, int listener)
  84. {
  85. int ret = 0;
  86. unl_info("%s: listener=(%s)%d register\n", __func__,
  87. listener_string(listener), listener);
  88. create_external_notify();
  89. SET_EXTERNAL_NOTIFY_BLOCK(nb, notifier, listener);
  90. ret = blocking_notifier_chain_register
  91. (&(external_notifier.notifier_call_chain), nb);
  92. if (ret < 0)
  93. unl_err("%s: blocking_notifier_chain_register error(%d)\n",
  94. __func__, ret);
  95. return ret;
  96. }
  97. EXPORT_SYMBOL(usb_external_notify_register);
  98. int usb_external_notify_unregister(struct notifier_block *nb)
  99. {
  100. int ret = 0;
  101. unl_info("%s: listener=(%s)%d unregister\n", __func__,
  102. listener_string(nb->priority),
  103. nb->priority);
  104. ret = blocking_notifier_chain_unregister
  105. (&(external_notifier.notifier_call_chain), nb);
  106. if (ret < 0)
  107. unl_err("%s: blocking_notifier_chain_unregister error(%d)\n",
  108. __func__, ret);
  109. DESTROY_EXTERNAL_NOTIFY_BLOCK(nb);
  110. return ret;
  111. }
  112. EXPORT_SYMBOL(usb_external_notify_unregister);
  113. int send_external_notify(unsigned long cmd, int data)
  114. {
  115. int ret = 0;
  116. unl_info("%s: cmd=%s(%lu), data=%d\n", __func__, cmd_string(cmd),
  117. cmd, data);
  118. create_external_notify();
  119. ret = blocking_notifier_call_chain
  120. (&(external_notifier.notifier_call_chain),
  121. cmd, (void *)&(data));
  122. switch (ret) {
  123. case NOTIFY_STOP_MASK:
  124. case NOTIFY_BAD:
  125. unl_err("%s: notify error occur(0x%x)\n", __func__, ret);
  126. break;
  127. case NOTIFY_DONE:
  128. case NOTIFY_OK:
  129. unl_info("%s: notify done(0x%x)\n", __func__, ret);
  130. break;
  131. default:
  132. unl_info("%s: notify status unknown(0x%x)\n", __func__, ret);
  133. break;
  134. }
  135. return ret;
  136. }
  137. EXPORT_SYMBOL(send_external_notify);
  138. void external_notifier_init(void)
  139. {
  140. unl_info("%s\n", __func__);
  141. create_external_notify();
  142. }
  143. EXPORT_SYMBOL(external_notifier_init);