sof-client.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. //
  3. // Copyright(c) 2022 Intel Corporation
  4. //
  5. // Authors: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
  6. // Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
  7. //
  8. #include <linux/debugfs.h>
  9. #include <linux/errno.h>
  10. #include <linux/list.h>
  11. #include <linux/module.h>
  12. #include <linux/mutex.h>
  13. #include <linux/slab.h>
  14. #include <sound/sof/ipc4/header.h>
  15. #include "ops.h"
  16. #include "sof-client.h"
  17. #include "sof-priv.h"
  18. #include "ipc3-priv.h"
  19. #include "ipc4-priv.h"
  20. /**
  21. * struct sof_ipc_event_entry - IPC client event description
  22. * @ipc_msg_type: IPC msg type of the event the client is interested
  23. * @cdev: sof_client_dev of the requesting client
  24. * @callback: Callback function of the client
  25. * @list: item in SOF core client event list
  26. */
  27. struct sof_ipc_event_entry {
  28. u32 ipc_msg_type;
  29. struct sof_client_dev *cdev;
  30. sof_client_event_callback callback;
  31. struct list_head list;
  32. };
  33. /**
  34. * struct sof_state_event_entry - DSP panic event subscription entry
  35. * @cdev: sof_client_dev of the requesting client
  36. * @callback: Callback function of the client
  37. * @list: item in SOF core client event list
  38. */
  39. struct sof_state_event_entry {
  40. struct sof_client_dev *cdev;
  41. sof_client_fw_state_callback callback;
  42. struct list_head list;
  43. };
  44. /**
  45. * struct sof_client_dev_entry - client device entry for internal management use
  46. * @sdev: pointer to SOF core device struct
  47. * @list: item in SOF core client dev list
  48. * @client_dev: SOF client device
  49. */
  50. struct sof_client_dev_entry {
  51. struct snd_sof_dev *sdev;
  52. struct list_head list;
  53. struct sof_client_dev client_dev;
  54. };
  55. #define cdev_to_centry(cdev) \
  56. container_of(cdev, struct sof_client_dev_entry, client_dev)
  57. static void sof_client_auxdev_release(struct device *dev)
  58. {
  59. struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
  60. struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
  61. struct sof_client_dev_entry *centry = cdev_to_centry(cdev);
  62. kfree(cdev->auxdev.dev.platform_data);
  63. kfree(centry);
  64. }
  65. static int sof_client_dev_add_data(struct sof_client_dev *cdev, const void *data,
  66. size_t size)
  67. {
  68. void *d = NULL;
  69. if (data) {
  70. d = kmemdup(data, size, GFP_KERNEL);
  71. if (!d)
  72. return -ENOMEM;
  73. }
  74. cdev->auxdev.dev.platform_data = d;
  75. return 0;
  76. }
  77. #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST)
  78. static int sof_register_ipc_flood_test(struct snd_sof_dev *sdev)
  79. {
  80. int ret = 0;
  81. int i;
  82. if (sdev->pdata->ipc_type != SOF_IPC_TYPE_3)
  83. return 0;
  84. for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++) {
  85. ret = sof_client_dev_register(sdev, "ipc_flood", i, NULL, 0);
  86. if (ret < 0)
  87. break;
  88. }
  89. if (ret) {
  90. for (; i >= 0; --i)
  91. sof_client_dev_unregister(sdev, "ipc_flood", i);
  92. }
  93. return ret;
  94. }
  95. static void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev)
  96. {
  97. int i;
  98. for (i = 0; i < CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST_NUM; i++)
  99. sof_client_dev_unregister(sdev, "ipc_flood", i);
  100. }
  101. #else
  102. static inline int sof_register_ipc_flood_test(struct snd_sof_dev *sdev)
  103. {
  104. return 0;
  105. }
  106. static inline void sof_unregister_ipc_flood_test(struct snd_sof_dev *sdev) {}
  107. #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST */
  108. #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR)
  109. static int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev)
  110. {
  111. return sof_client_dev_register(sdev, "msg_injector", 0, NULL, 0);
  112. }
  113. static void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev)
  114. {
  115. sof_client_dev_unregister(sdev, "msg_injector", 0);
  116. }
  117. #else
  118. static inline int sof_register_ipc_msg_injector(struct snd_sof_dev *sdev)
  119. {
  120. return 0;
  121. }
  122. static inline void sof_unregister_ipc_msg_injector(struct snd_sof_dev *sdev) {}
  123. #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_MSG_INJECTOR */
  124. #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_KERNEL_INJECTOR)
  125. static int sof_register_ipc_kernel_injector(struct snd_sof_dev *sdev)
  126. {
  127. /* Only IPC3 supported right now */
  128. if (sdev->pdata->ipc_type != SOF_IPC_TYPE_3)
  129. return 0;
  130. return sof_client_dev_register(sdev, "kernel_injector", 0, NULL, 0);
  131. }
  132. static void sof_unregister_ipc_kernel_injector(struct snd_sof_dev *sdev)
  133. {
  134. sof_client_dev_unregister(sdev, "kernel_injector", 0);
  135. }
  136. #else
  137. static inline int sof_register_ipc_kernel_injector(struct snd_sof_dev *sdev)
  138. {
  139. return 0;
  140. }
  141. static inline void sof_unregister_ipc_kernel_injector(struct snd_sof_dev *sdev) {}
  142. #endif /* CONFIG_SND_SOC_SOF_DEBUG_IPC_KERNEL_INJECTOR */
  143. int sof_register_clients(struct snd_sof_dev *sdev)
  144. {
  145. int ret;
  146. if (sdev->dspless_mode_selected)
  147. return 0;
  148. /* Register platform independent client devices */
  149. ret = sof_register_ipc_flood_test(sdev);
  150. if (ret) {
  151. dev_err(sdev->dev, "IPC flood test client registration failed\n");
  152. return ret;
  153. }
  154. ret = sof_register_ipc_msg_injector(sdev);
  155. if (ret) {
  156. dev_err(sdev->dev, "IPC message injector client registration failed\n");
  157. goto err_msg_injector;
  158. }
  159. ret = sof_register_ipc_kernel_injector(sdev);
  160. if (ret) {
  161. dev_err(sdev->dev, "IPC kernel injector client registration failed\n");
  162. goto err_kernel_injector;
  163. }
  164. /* Platform dependent client device registration */
  165. if (sof_ops(sdev) && sof_ops(sdev)->register_ipc_clients)
  166. ret = sof_ops(sdev)->register_ipc_clients(sdev);
  167. if (!ret)
  168. return 0;
  169. sof_unregister_ipc_kernel_injector(sdev);
  170. err_kernel_injector:
  171. sof_unregister_ipc_msg_injector(sdev);
  172. err_msg_injector:
  173. sof_unregister_ipc_flood_test(sdev);
  174. return ret;
  175. }
  176. void sof_unregister_clients(struct snd_sof_dev *sdev)
  177. {
  178. if (sof_ops(sdev) && sof_ops(sdev)->unregister_ipc_clients)
  179. sof_ops(sdev)->unregister_ipc_clients(sdev);
  180. sof_unregister_ipc_kernel_injector(sdev);
  181. sof_unregister_ipc_msg_injector(sdev);
  182. sof_unregister_ipc_flood_test(sdev);
  183. }
  184. int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id,
  185. const void *data, size_t size)
  186. {
  187. struct sof_client_dev_entry *centry;
  188. struct auxiliary_device *auxdev;
  189. struct sof_client_dev *cdev;
  190. int ret;
  191. centry = kzalloc(sizeof(*centry), GFP_KERNEL);
  192. if (!centry)
  193. return -ENOMEM;
  194. cdev = &centry->client_dev;
  195. centry->sdev = sdev;
  196. auxdev = &cdev->auxdev;
  197. auxdev->name = name;
  198. auxdev->dev.parent = sdev->dev;
  199. auxdev->dev.release = sof_client_auxdev_release;
  200. auxdev->id = id;
  201. ret = sof_client_dev_add_data(cdev, data, size);
  202. if (ret < 0)
  203. goto err_dev_add_data;
  204. ret = auxiliary_device_init(auxdev);
  205. if (ret < 0) {
  206. dev_err(sdev->dev, "failed to initialize client dev %s.%d\n", name, id);
  207. goto err_dev_init;
  208. }
  209. ret = auxiliary_device_add(&cdev->auxdev);
  210. if (ret < 0) {
  211. dev_err(sdev->dev, "failed to add client dev %s.%d\n", name, id);
  212. /*
  213. * sof_client_auxdev_release() will be invoked to free up memory
  214. * allocations through put_device()
  215. */
  216. auxiliary_device_uninit(&cdev->auxdev);
  217. return ret;
  218. }
  219. /* add to list of SOF client devices */
  220. scoped_guard(mutex, &sdev->ipc_client_mutex)
  221. list_add(&centry->list, &sdev->ipc_client_list);
  222. return 0;
  223. err_dev_init:
  224. kfree(cdev->auxdev.dev.platform_data);
  225. err_dev_add_data:
  226. kfree(centry);
  227. return ret;
  228. }
  229. EXPORT_SYMBOL_NS_GPL(sof_client_dev_register, "SND_SOC_SOF_CLIENT");
  230. void sof_client_dev_unregister(struct snd_sof_dev *sdev, const char *name, u32 id)
  231. {
  232. struct sof_client_dev_entry *centry;
  233. guard(mutex)(&sdev->ipc_client_mutex);
  234. /*
  235. * sof_client_auxdev_release() will be invoked to free up memory
  236. * allocations through put_device()
  237. */
  238. list_for_each_entry(centry, &sdev->ipc_client_list, list) {
  239. struct sof_client_dev *cdev = &centry->client_dev;
  240. if (!strcmp(cdev->auxdev.name, name) && cdev->auxdev.id == id) {
  241. list_del(&centry->list);
  242. auxiliary_device_delete(&cdev->auxdev);
  243. auxiliary_device_uninit(&cdev->auxdev);
  244. break;
  245. }
  246. }
  247. }
  248. EXPORT_SYMBOL_NS_GPL(sof_client_dev_unregister, "SND_SOC_SOF_CLIENT");
  249. int sof_client_ipc_tx_message(struct sof_client_dev *cdev, void *ipc_msg,
  250. void *reply_data, size_t reply_bytes)
  251. {
  252. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  253. if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
  254. struct sof_ipc_cmd_hdr *hdr = ipc_msg;
  255. return sof_ipc_tx_message(sdev->ipc, ipc_msg, hdr->size,
  256. reply_data, reply_bytes);
  257. } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
  258. struct sof_ipc4_msg *msg = ipc_msg;
  259. return sof_ipc_tx_message(sdev->ipc, ipc_msg, msg->data_size,
  260. reply_data, reply_bytes);
  261. }
  262. return -EINVAL;
  263. }
  264. EXPORT_SYMBOL_NS_GPL(sof_client_ipc_tx_message, "SND_SOC_SOF_CLIENT");
  265. int sof_client_ipc_rx_message(struct sof_client_dev *cdev, void *ipc_msg, void *msg_buf)
  266. {
  267. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  268. if (IS_ENABLED(CONFIG_SND_SOC_SOF_IPC3) &&
  269. sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
  270. struct sof_ipc_cmd_hdr *hdr = ipc_msg;
  271. if (hdr->size < sizeof(hdr)) {
  272. dev_err(sdev->dev, "The received message size is invalid\n");
  273. return -EINVAL;
  274. }
  275. sof_ipc3_do_rx_work(sdev, ipc_msg, msg_buf);
  276. return 0;
  277. }
  278. return -EOPNOTSUPP;
  279. }
  280. EXPORT_SYMBOL_NS_GPL(sof_client_ipc_rx_message, "SND_SOC_SOF_CLIENT");
  281. int sof_client_ipc_set_get_data(struct sof_client_dev *cdev, void *ipc_msg,
  282. bool set)
  283. {
  284. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  285. if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
  286. struct sof_ipc_cmd_hdr *hdr = ipc_msg;
  287. return sof_ipc_set_get_data(sdev->ipc, ipc_msg, hdr->size, set);
  288. } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
  289. struct sof_ipc4_msg *msg = ipc_msg;
  290. return sof_ipc_set_get_data(sdev->ipc, ipc_msg, msg->data_size,
  291. set);
  292. }
  293. return -EINVAL;
  294. }
  295. EXPORT_SYMBOL_NS_GPL(sof_client_ipc_set_get_data, "SND_SOC_SOF_CLIENT");
  296. #ifdef CONFIG_SND_SOC_SOF_IPC4
  297. struct sof_ipc4_fw_module *sof_client_ipc4_find_module(struct sof_client_dev *c, const guid_t *uuid)
  298. {
  299. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(c);
  300. if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4)
  301. return sof_ipc4_find_module_by_uuid(sdev, uuid);
  302. dev_err(sdev->dev, "Only supported with IPC4\n");
  303. return NULL;
  304. }
  305. EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_module, "SND_SOC_SOF_CLIENT");
  306. struct snd_sof_widget *sof_client_ipc4_find_swidget_by_id(struct sof_client_dev *cdev,
  307. u32 module_id, int instance_id)
  308. {
  309. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  310. if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4)
  311. return sof_ipc4_find_swidget_by_ids(sdev, module_id, instance_id);
  312. dev_err(sdev->dev, "Only supported with IPC4\n");
  313. return NULL;
  314. }
  315. EXPORT_SYMBOL_NS_GPL(sof_client_ipc4_find_swidget_by_id, "SND_SOC_SOF_CLIENT");
  316. #endif
  317. int sof_suspend_clients(struct snd_sof_dev *sdev, pm_message_t state)
  318. {
  319. const struct auxiliary_driver *adrv;
  320. struct sof_client_dev_entry *centry;
  321. guard(mutex)(&sdev->ipc_client_mutex);
  322. list_for_each_entry(centry, &sdev->ipc_client_list, list) {
  323. struct sof_client_dev *cdev = &centry->client_dev;
  324. /* Skip devices without loaded driver */
  325. if (!cdev->auxdev.dev.driver)
  326. continue;
  327. adrv = to_auxiliary_drv(cdev->auxdev.dev.driver);
  328. if (adrv->suspend)
  329. adrv->suspend(&cdev->auxdev, state);
  330. }
  331. return 0;
  332. }
  333. EXPORT_SYMBOL_NS_GPL(sof_suspend_clients, "SND_SOC_SOF_CLIENT");
  334. int sof_resume_clients(struct snd_sof_dev *sdev)
  335. {
  336. const struct auxiliary_driver *adrv;
  337. struct sof_client_dev_entry *centry;
  338. guard(mutex)(&sdev->ipc_client_mutex);
  339. list_for_each_entry(centry, &sdev->ipc_client_list, list) {
  340. struct sof_client_dev *cdev = &centry->client_dev;
  341. /* Skip devices without loaded driver */
  342. if (!cdev->auxdev.dev.driver)
  343. continue;
  344. adrv = to_auxiliary_drv(cdev->auxdev.dev.driver);
  345. if (adrv->resume)
  346. adrv->resume(&cdev->auxdev);
  347. }
  348. return 0;
  349. }
  350. EXPORT_SYMBOL_NS_GPL(sof_resume_clients, "SND_SOC_SOF_CLIENT");
  351. struct dentry *sof_client_get_debugfs_root(struct sof_client_dev *cdev)
  352. {
  353. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  354. return sdev->debugfs_root;
  355. }
  356. EXPORT_SYMBOL_NS_GPL(sof_client_get_debugfs_root, "SND_SOC_SOF_CLIENT");
  357. /* DMA buffer allocation in client drivers must use the core SOF device */
  358. struct device *sof_client_get_dma_dev(struct sof_client_dev *cdev)
  359. {
  360. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  361. return sdev->dev;
  362. }
  363. EXPORT_SYMBOL_NS_GPL(sof_client_get_dma_dev, "SND_SOC_SOF_CLIENT");
  364. const struct sof_ipc_fw_version *sof_client_get_fw_version(struct sof_client_dev *cdev)
  365. {
  366. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  367. return &sdev->fw_ready.version;
  368. }
  369. EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_version, "SND_SOC_SOF_CLIENT");
  370. size_t sof_client_get_ipc_max_payload_size(struct sof_client_dev *cdev)
  371. {
  372. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  373. return sdev->ipc->max_payload_size;
  374. }
  375. EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_max_payload_size, "SND_SOC_SOF_CLIENT");
  376. enum sof_ipc_type sof_client_get_ipc_type(struct sof_client_dev *cdev)
  377. {
  378. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  379. return sdev->pdata->ipc_type;
  380. }
  381. EXPORT_SYMBOL_NS_GPL(sof_client_get_ipc_type, "SND_SOC_SOF_CLIENT");
  382. int sof_client_boot_dsp(struct sof_client_dev *cdev)
  383. {
  384. return snd_sof_boot_dsp_firmware(sof_client_dev_to_sof_dev(cdev));
  385. }
  386. EXPORT_SYMBOL_NS_GPL(sof_client_boot_dsp, "SND_SOC_SOF_CLIENT");
  387. /* module refcount management of SOF core */
  388. int sof_client_core_module_get(struct sof_client_dev *cdev)
  389. {
  390. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  391. if (!try_module_get(sdev->dev->driver->owner))
  392. return -ENODEV;
  393. return 0;
  394. }
  395. EXPORT_SYMBOL_NS_GPL(sof_client_core_module_get, "SND_SOC_SOF_CLIENT");
  396. void sof_client_core_module_put(struct sof_client_dev *cdev)
  397. {
  398. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  399. module_put(sdev->dev->driver->owner);
  400. }
  401. EXPORT_SYMBOL_NS_GPL(sof_client_core_module_put, "SND_SOC_SOF_CLIENT");
  402. /* IPC event handling */
  403. void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf)
  404. {
  405. struct sof_ipc_event_entry *event;
  406. u32 msg_type;
  407. if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
  408. struct sof_ipc_cmd_hdr *hdr = msg_buf;
  409. msg_type = hdr->cmd & SOF_GLB_TYPE_MASK;
  410. } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
  411. struct sof_ipc4_msg *msg = msg_buf;
  412. msg_type = SOF_IPC4_NOTIFICATION_TYPE_GET(msg->primary);
  413. } else {
  414. dev_dbg_once(sdev->dev, "Not supported IPC version: %d\n",
  415. sdev->pdata->ipc_type);
  416. return;
  417. }
  418. guard(mutex)(&sdev->client_event_handler_mutex);
  419. list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) {
  420. if (event->ipc_msg_type == msg_type)
  421. event->callback(event->cdev, msg_buf);
  422. }
  423. }
  424. int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev,
  425. u32 ipc_msg_type,
  426. sof_client_event_callback callback)
  427. {
  428. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  429. struct sof_ipc_event_entry *event;
  430. if (!callback)
  431. return -EINVAL;
  432. if (sdev->pdata->ipc_type == SOF_IPC_TYPE_3) {
  433. if (!(ipc_msg_type & SOF_GLB_TYPE_MASK))
  434. return -EINVAL;
  435. } else if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
  436. if (!(ipc_msg_type & SOF_IPC4_NOTIFICATION_TYPE_MASK))
  437. return -EINVAL;
  438. } else {
  439. dev_warn(sdev->dev, "%s: Not supported IPC version: %d\n",
  440. __func__, sdev->pdata->ipc_type);
  441. return -EINVAL;
  442. }
  443. event = kmalloc_obj(*event);
  444. if (!event)
  445. return -ENOMEM;
  446. event->ipc_msg_type = ipc_msg_type;
  447. event->cdev = cdev;
  448. event->callback = callback;
  449. /* add to list of SOF client devices */
  450. guard(mutex)(&sdev->client_event_handler_mutex);
  451. list_add(&event->list, &sdev->ipc_rx_handler_list);
  452. return 0;
  453. }
  454. EXPORT_SYMBOL_NS_GPL(sof_client_register_ipc_rx_handler, "SND_SOC_SOF_CLIENT");
  455. void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev,
  456. u32 ipc_msg_type)
  457. {
  458. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  459. struct sof_ipc_event_entry *event;
  460. guard(mutex)(&sdev->ipc_client_mutex);
  461. list_for_each_entry(event, &sdev->ipc_rx_handler_list, list) {
  462. if (event->cdev == cdev && event->ipc_msg_type == ipc_msg_type) {
  463. list_del(&event->list);
  464. kfree(event);
  465. break;
  466. }
  467. }
  468. }
  469. EXPORT_SYMBOL_NS_GPL(sof_client_unregister_ipc_rx_handler, "SND_SOC_SOF_CLIENT");
  470. /*DSP state notification and query */
  471. void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev)
  472. {
  473. struct sof_state_event_entry *event;
  474. guard(mutex)(&sdev->ipc_client_mutex);
  475. list_for_each_entry(event, &sdev->fw_state_handler_list, list)
  476. event->callback(event->cdev, sdev->fw_state);
  477. }
  478. int sof_client_register_fw_state_handler(struct sof_client_dev *cdev,
  479. sof_client_fw_state_callback callback)
  480. {
  481. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  482. struct sof_state_event_entry *event;
  483. if (!callback)
  484. return -EINVAL;
  485. event = kmalloc_obj(*event);
  486. if (!event)
  487. return -ENOMEM;
  488. event->cdev = cdev;
  489. event->callback = callback;
  490. /* add to list of SOF client devices */
  491. guard(mutex)(&sdev->client_event_handler_mutex);
  492. list_add(&event->list, &sdev->fw_state_handler_list);
  493. return 0;
  494. }
  495. EXPORT_SYMBOL_NS_GPL(sof_client_register_fw_state_handler, "SND_SOC_SOF_CLIENT");
  496. void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev)
  497. {
  498. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  499. struct sof_state_event_entry *event;
  500. guard(mutex)(&sdev->ipc_client_mutex);
  501. list_for_each_entry(event, &sdev->fw_state_handler_list, list) {
  502. if (event->cdev == cdev) {
  503. list_del(&event->list);
  504. kfree(event);
  505. break;
  506. }
  507. }
  508. }
  509. EXPORT_SYMBOL_NS_GPL(sof_client_unregister_fw_state_handler, "SND_SOC_SOF_CLIENT");
  510. enum sof_fw_state sof_client_get_fw_state(struct sof_client_dev *cdev)
  511. {
  512. struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
  513. return sdev->fw_state;
  514. }
  515. EXPORT_SYMBOL_NS_GPL(sof_client_get_fw_state, "SND_SOC_SOF_CLIENT");
  516. struct snd_sof_dev *sof_client_dev_to_sof_dev(struct sof_client_dev *cdev)
  517. {
  518. struct sof_client_dev_entry *centry = cdev_to_centry(cdev);
  519. return centry->sdev;
  520. }
  521. EXPORT_SYMBOL_NS_GPL(sof_client_dev_to_sof_dev, "SND_SOC_SOF_CLIENT");