audio_pdr.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/module.h>
  6. #include <linux/slab.h>
  7. #include <soc/qcom/service-locator.h>
  8. #include <soc/qcom/service-notifier.h>
  9. #include "audio_pdr.h"
  10. static struct pd_qmi_client_data audio_pdr_services[AUDIO_PDR_DOMAIN_MAX] = {
  11. { /* AUDIO_PDR_DOMAIN_ADSP */
  12. .client_name = "audio_pdr_adsp",
  13. .service_name = "avs/audio"
  14. }
  15. };
  16. struct srcu_notifier_head audio_pdr_cb_list;
  17. static int audio_pdr_locator_callback(struct notifier_block *this,
  18. unsigned long opcode, void *data)
  19. {
  20. unsigned long pdr_state = AUDIO_PDR_FRAMEWORK_DOWN;
  21. if (opcode == LOCATOR_DOWN) {
  22. pr_debug("%s: Service %s is down!", __func__,
  23. audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
  24. service_name);
  25. goto done;
  26. }
  27. memcpy(&audio_pdr_services, data,
  28. sizeof(audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP]));
  29. if (audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].total_domains == 1) {
  30. pr_debug("%s: Service %s, returned total domains %d, ",
  31. __func__,
  32. audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
  33. audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
  34. total_domains);
  35. pdr_state = AUDIO_PDR_FRAMEWORK_UP;
  36. goto done;
  37. } else
  38. pr_err("%s: Service %s returned invalid total domains %d",
  39. __func__,
  40. audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
  41. audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
  42. total_domains);
  43. done:
  44. srcu_notifier_call_chain(&audio_pdr_cb_list, pdr_state, NULL);
  45. return NOTIFY_OK;
  46. }
  47. static struct notifier_block audio_pdr_locator_nb = {
  48. .notifier_call = audio_pdr_locator_callback,
  49. .priority = 0,
  50. };
  51. /**
  52. * audio_pdr_register -
  53. * register to PDR framework
  54. *
  55. * @nb: notifier block
  56. *
  57. * Returns 0 on success or error on failure
  58. */
  59. int audio_pdr_register(struct notifier_block *nb)
  60. {
  61. if (nb == NULL) {
  62. pr_err("%s: Notifier block is NULL\n", __func__);
  63. return -EINVAL;
  64. }
  65. return srcu_notifier_chain_register(&audio_pdr_cb_list, nb);
  66. }
  67. EXPORT_SYMBOL(audio_pdr_register);
  68. /**
  69. * audio_pdr_deregister -
  70. * Deregister from PDR framework
  71. *
  72. * @nb: notifier block
  73. *
  74. * Returns 0 on success or error on failure
  75. */
  76. int audio_pdr_deregister(struct notifier_block *nb)
  77. {
  78. if (nb == NULL) {
  79. pr_err("%s: Notifier block is NULL\n", __func__);
  80. return -EINVAL;
  81. }
  82. return srcu_notifier_chain_unregister(&audio_pdr_cb_list, nb);
  83. }
  84. EXPORT_SYMBOL(audio_pdr_deregister);
  85. void *audio_pdr_service_register(int domain_id,
  86. struct notifier_block *nb, int *curr_state)
  87. {
  88. void *handle;
  89. if ((domain_id < 0) ||
  90. (domain_id >= AUDIO_PDR_DOMAIN_MAX)) {
  91. pr_err("%s: Invalid service ID %d\n", __func__, domain_id);
  92. return ERR_PTR(-EINVAL);
  93. }
  94. handle = service_notif_register_notifier(
  95. audio_pdr_services[domain_id].domain_list[0].name,
  96. audio_pdr_services[domain_id].domain_list[0].instance_id,
  97. nb, curr_state);
  98. if (IS_ERR_OR_NULL(handle)) {
  99. pr_err("%s: Failed to register for service %s, instance %d\n",
  100. __func__,
  101. audio_pdr_services[domain_id].domain_list[0].name,
  102. audio_pdr_services[domain_id].domain_list[0].
  103. instance_id);
  104. }
  105. return handle;
  106. }
  107. EXPORT_SYMBOL(audio_pdr_service_register);
  108. int audio_pdr_service_deregister(void *service_handle,
  109. struct notifier_block *nb)
  110. {
  111. int ret;
  112. if (service_handle == NULL) {
  113. pr_err("%s: service handle is NULL\n", __func__);
  114. ret = -EINVAL;
  115. goto done;
  116. }
  117. ret = service_notif_unregister_notifier(
  118. service_handle, nb);
  119. if (ret < 0)
  120. pr_err("%s: Failed to deregister service ret %d\n",
  121. __func__, ret);
  122. done:
  123. return ret;
  124. }
  125. EXPORT_SYMBOL(audio_pdr_service_deregister);
  126. static int __init audio_pdr_subsys_init(void)
  127. {
  128. srcu_init_notifier_head(&audio_pdr_cb_list);
  129. return 0;
  130. }
  131. static int __init audio_pdr_late_init(void)
  132. {
  133. int ret;
  134. audio_pdr_subsys_init();
  135. ret = get_service_location(
  136. audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].client_name,
  137. audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
  138. &audio_pdr_locator_nb);
  139. if (ret < 0) {
  140. pr_err("%s get_service_location failed ret %d\n",
  141. __func__, ret);
  142. srcu_notifier_call_chain(&audio_pdr_cb_list,
  143. AUDIO_PDR_FRAMEWORK_DOWN, NULL);
  144. }
  145. return ret;
  146. }
  147. module_init(audio_pdr_late_init);
  148. static void __exit audio_pdr_late_exit(void)
  149. {
  150. }
  151. module_exit(audio_pdr_late_exit);
  152. MODULE_DESCRIPTION("PDR framework driver");
  153. MODULE_LICENSE("GPL v2");