1cac0b088SPeter Ujfalusi // SPDX-License-Identifier: GPL-2.0-only
2cac0b088SPeter Ujfalusi //
3cac0b088SPeter Ujfalusi // Copyright(c) 2022 Intel Corporation. All rights reserved.
4cac0b088SPeter Ujfalusi //
5cac0b088SPeter Ujfalusi // Author: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
6cac0b088SPeter Ujfalusi //
7cac0b088SPeter Ujfalusi
8cac0b088SPeter Ujfalusi #include <linux/auxiliary_bus.h>
9cac0b088SPeter Ujfalusi #include <linux/completion.h>
10cac0b088SPeter Ujfalusi #include <linux/debugfs.h>
11cac0b088SPeter Ujfalusi #include <linux/ktime.h>
12cac0b088SPeter Ujfalusi #include <linux/mod_devicetable.h>
13cac0b088SPeter Ujfalusi #include <linux/module.h>
14cac0b088SPeter Ujfalusi #include <linux/pm_runtime.h>
15cac0b088SPeter Ujfalusi #include <linux/slab.h>
16cac0b088SPeter Ujfalusi #include <linux/uaccess.h>
17cac0b088SPeter Ujfalusi #include <sound/sof/header.h>
18066c6762SPeter Ujfalusi #include <sound/sof/ipc4/header.h>
19cac0b088SPeter Ujfalusi
20cac0b088SPeter Ujfalusi #include "sof-client.h"
21cac0b088SPeter Ujfalusi
22cac0b088SPeter Ujfalusi #define SOF_IPC_CLIENT_SUSPEND_DELAY_MS 3000
23cac0b088SPeter Ujfalusi
24cac0b088SPeter Ujfalusi struct sof_msg_inject_priv {
25cac0b088SPeter Ujfalusi struct dentry *dfs_file;
26ef368c33SPeter Ujfalusi size_t max_msg_size;
27066c6762SPeter Ujfalusi enum sof_ipc_type ipc_type;
28cac0b088SPeter Ujfalusi
29cac0b088SPeter Ujfalusi void *tx_buffer;
30cac0b088SPeter Ujfalusi void *rx_buffer;
31cac0b088SPeter Ujfalusi };
32cac0b088SPeter Ujfalusi
sof_msg_inject_dfs_open(struct inode * inode,struct file * file)33cac0b088SPeter Ujfalusi static int sof_msg_inject_dfs_open(struct inode *inode, struct file *file)
34cac0b088SPeter Ujfalusi {
35cac0b088SPeter Ujfalusi struct sof_client_dev *cdev = inode->i_private;
36cac0b088SPeter Ujfalusi int ret;
37cac0b088SPeter Ujfalusi
38cac0b088SPeter Ujfalusi if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED)
39cac0b088SPeter Ujfalusi return -ENODEV;
40cac0b088SPeter Ujfalusi
41cac0b088SPeter Ujfalusi ret = debugfs_file_get(file->f_path.dentry);
42cac0b088SPeter Ujfalusi if (unlikely(ret))
43cac0b088SPeter Ujfalusi return ret;
44cac0b088SPeter Ujfalusi
45cac0b088SPeter Ujfalusi ret = simple_open(inode, file);
46cac0b088SPeter Ujfalusi if (ret)
47cac0b088SPeter Ujfalusi debugfs_file_put(file->f_path.dentry);
48cac0b088SPeter Ujfalusi
49cac0b088SPeter Ujfalusi return ret;
50cac0b088SPeter Ujfalusi }
51cac0b088SPeter Ujfalusi
sof_msg_inject_dfs_read(struct file * file,char __user * buffer,size_t count,loff_t * ppos)52cac0b088SPeter Ujfalusi static ssize_t sof_msg_inject_dfs_read(struct file *file, char __user *buffer,
53cac0b088SPeter Ujfalusi size_t count, loff_t *ppos)
54cac0b088SPeter Ujfalusi {
55cac0b088SPeter Ujfalusi struct sof_client_dev *cdev = file->private_data;
56cac0b088SPeter Ujfalusi struct sof_msg_inject_priv *priv = cdev->data;
57cac0b088SPeter Ujfalusi struct sof_ipc_reply *rhdr = priv->rx_buffer;
58cac0b088SPeter Ujfalusi
59cac0b088SPeter Ujfalusi if (!rhdr->hdr.size || !count || *ppos)
60cac0b088SPeter Ujfalusi return 0;
61cac0b088SPeter Ujfalusi
62cac0b088SPeter Ujfalusi if (count > rhdr->hdr.size)
63cac0b088SPeter Ujfalusi count = rhdr->hdr.size;
64cac0b088SPeter Ujfalusi
65cac0b088SPeter Ujfalusi if (copy_to_user(buffer, priv->rx_buffer, count))
66cac0b088SPeter Ujfalusi return -EFAULT;
67cac0b088SPeter Ujfalusi
68cac0b088SPeter Ujfalusi *ppos += count;
69cac0b088SPeter Ujfalusi return count;
70cac0b088SPeter Ujfalusi }
71cac0b088SPeter Ujfalusi
sof_msg_inject_ipc4_dfs_read(struct file * file,char __user * buffer,size_t count,loff_t * ppos)72066c6762SPeter Ujfalusi static ssize_t sof_msg_inject_ipc4_dfs_read(struct file *file,
73066c6762SPeter Ujfalusi char __user *buffer,
74066c6762SPeter Ujfalusi size_t count, loff_t *ppos)
75066c6762SPeter Ujfalusi {
76066c6762SPeter Ujfalusi struct sof_client_dev *cdev = file->private_data;
77066c6762SPeter Ujfalusi struct sof_msg_inject_priv *priv = cdev->data;
78066c6762SPeter Ujfalusi struct sof_ipc4_msg *ipc4_msg = priv->rx_buffer;
79c5003f08SPeter Ujfalusi size_t header_size = sizeof(ipc4_msg->header_u64);
80066c6762SPeter Ujfalusi size_t remaining;
81066c6762SPeter Ujfalusi
82066c6762SPeter Ujfalusi if (!ipc4_msg->header_u64 || !count || *ppos)
83066c6762SPeter Ujfalusi return 0;
84066c6762SPeter Ujfalusi
85c5003f08SPeter Ujfalusi /* we need space for the header at minimum (u64) */
86c5003f08SPeter Ujfalusi if (count < header_size)
87c5003f08SPeter Ujfalusi return -ENOSPC;
88c5003f08SPeter Ujfalusi
89c5003f08SPeter Ujfalusi remaining = header_size;
90066c6762SPeter Ujfalusi
91066c6762SPeter Ujfalusi /* Only get large config have payload */
92066c6762SPeter Ujfalusi if (SOF_IPC4_MSG_IS_MODULE_MSG(ipc4_msg->primary) &&
93066c6762SPeter Ujfalusi (SOF_IPC4_MSG_TYPE_GET(ipc4_msg->primary) == SOF_IPC4_MOD_LARGE_CONFIG_GET))
94066c6762SPeter Ujfalusi remaining += ipc4_msg->data_size;
95066c6762SPeter Ujfalusi
96066c6762SPeter Ujfalusi if (count > remaining)
97066c6762SPeter Ujfalusi count = remaining;
98c5003f08SPeter Ujfalusi else if (count < remaining)
99c5003f08SPeter Ujfalusi remaining = count;
100066c6762SPeter Ujfalusi
101066c6762SPeter Ujfalusi /* copy the header first */
102c5003f08SPeter Ujfalusi if (copy_to_user(buffer, &ipc4_msg->header_u64, header_size))
103066c6762SPeter Ujfalusi return -EFAULT;
104066c6762SPeter Ujfalusi
105c5003f08SPeter Ujfalusi *ppos += header_size;
106c5003f08SPeter Ujfalusi remaining -= header_size;
107066c6762SPeter Ujfalusi
108066c6762SPeter Ujfalusi if (!remaining)
109066c6762SPeter Ujfalusi return count;
110066c6762SPeter Ujfalusi
111066c6762SPeter Ujfalusi if (remaining > ipc4_msg->data_size)
112066c6762SPeter Ujfalusi remaining = ipc4_msg->data_size;
113066c6762SPeter Ujfalusi
114066c6762SPeter Ujfalusi /* Copy the payload */
115066c6762SPeter Ujfalusi if (copy_to_user(buffer + *ppos, ipc4_msg->data_ptr, remaining))
116066c6762SPeter Ujfalusi return -EFAULT;
117066c6762SPeter Ujfalusi
118066c6762SPeter Ujfalusi *ppos += remaining;
119066c6762SPeter Ujfalusi return count;
120066c6762SPeter Ujfalusi }
121066c6762SPeter Ujfalusi
sof_msg_inject_send_message(struct sof_client_dev * cdev)122a9aa3381SPeter Ujfalusi static int sof_msg_inject_send_message(struct sof_client_dev *cdev)
123a9aa3381SPeter Ujfalusi {
124a9aa3381SPeter Ujfalusi struct sof_msg_inject_priv *priv = cdev->data;
125a9aa3381SPeter Ujfalusi struct device *dev = &cdev->auxdev.dev;
126a9aa3381SPeter Ujfalusi int ret, err;
127a9aa3381SPeter Ujfalusi
128a9aa3381SPeter Ujfalusi ret = pm_runtime_resume_and_get(dev);
129a9aa3381SPeter Ujfalusi if (ret < 0 && ret != -EACCES) {
130a9aa3381SPeter Ujfalusi dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret);
131a9aa3381SPeter Ujfalusi return ret;
132a9aa3381SPeter Ujfalusi }
133a9aa3381SPeter Ujfalusi
134a9aa3381SPeter Ujfalusi /* send the message */
135a9aa3381SPeter Ujfalusi ret = sof_client_ipc_tx_message(cdev, priv->tx_buffer, priv->rx_buffer,
136a9aa3381SPeter Ujfalusi priv->max_msg_size);
137a9aa3381SPeter Ujfalusi if (ret)
138a9aa3381SPeter Ujfalusi dev_err(dev, "IPC message send failed: %d\n", ret);
139a9aa3381SPeter Ujfalusi
140a9aa3381SPeter Ujfalusi pm_runtime_mark_last_busy(dev);
141a9aa3381SPeter Ujfalusi err = pm_runtime_put_autosuspend(dev);
142a9aa3381SPeter Ujfalusi if (err < 0)
143a9aa3381SPeter Ujfalusi dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
144a9aa3381SPeter Ujfalusi
145a9aa3381SPeter Ujfalusi return ret;
146a9aa3381SPeter Ujfalusi }
147a9aa3381SPeter Ujfalusi
sof_msg_inject_dfs_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)148cac0b088SPeter Ujfalusi static ssize_t sof_msg_inject_dfs_write(struct file *file, const char __user *buffer,
149cac0b088SPeter Ujfalusi size_t count, loff_t *ppos)
150cac0b088SPeter Ujfalusi {
151cac0b088SPeter Ujfalusi struct sof_client_dev *cdev = file->private_data;
152cac0b088SPeter Ujfalusi struct sof_msg_inject_priv *priv = cdev->data;
153d9a251a0SDan Carpenter ssize_t size;
154a9aa3381SPeter Ujfalusi int ret;
155cac0b088SPeter Ujfalusi
156cac0b088SPeter Ujfalusi if (*ppos)
157cac0b088SPeter Ujfalusi return 0;
158cac0b088SPeter Ujfalusi
159ef368c33SPeter Ujfalusi size = simple_write_to_buffer(priv->tx_buffer, priv->max_msg_size,
160cac0b088SPeter Ujfalusi ppos, buffer, count);
161d9a251a0SDan Carpenter if (size < 0)
162d9a251a0SDan Carpenter return size;
163cac0b088SPeter Ujfalusi if (size != count)
164d9a251a0SDan Carpenter return -EFAULT;
165cac0b088SPeter Ujfalusi
166ef368c33SPeter Ujfalusi memset(priv->rx_buffer, 0, priv->max_msg_size);
167cac0b088SPeter Ujfalusi
168a9aa3381SPeter Ujfalusi ret = sof_msg_inject_send_message(cdev);
169cac0b088SPeter Ujfalusi
170a9aa3381SPeter Ujfalusi /* return the error code if test failed */
171a9aa3381SPeter Ujfalusi if (ret < 0)
172a9aa3381SPeter Ujfalusi size = ret;
173a9aa3381SPeter Ujfalusi
174a9aa3381SPeter Ujfalusi return size;
175cac0b088SPeter Ujfalusi };
176cac0b088SPeter Ujfalusi
sof_msg_inject_ipc4_dfs_write(struct file * file,const char __user * buffer,size_t count,loff_t * ppos)177066c6762SPeter Ujfalusi static ssize_t sof_msg_inject_ipc4_dfs_write(struct file *file,
178066c6762SPeter Ujfalusi const char __user *buffer,
179066c6762SPeter Ujfalusi size_t count, loff_t *ppos)
180066c6762SPeter Ujfalusi {
181066c6762SPeter Ujfalusi struct sof_client_dev *cdev = file->private_data;
182066c6762SPeter Ujfalusi struct sof_msg_inject_priv *priv = cdev->data;
183066c6762SPeter Ujfalusi struct sof_ipc4_msg *ipc4_msg = priv->tx_buffer;
184*fa9b878fSDan Carpenter size_t data_size;
185066c6762SPeter Ujfalusi int ret;
186066c6762SPeter Ujfalusi
187066c6762SPeter Ujfalusi if (*ppos)
188066c6762SPeter Ujfalusi return 0;
189066c6762SPeter Ujfalusi
190066c6762SPeter Ujfalusi if (count < sizeof(ipc4_msg->header_u64))
191066c6762SPeter Ujfalusi return -EINVAL;
192066c6762SPeter Ujfalusi
193066c6762SPeter Ujfalusi /* copy the header first */
194*fa9b878fSDan Carpenter if (copy_from_user(&ipc4_msg->header_u64, buffer,
195*fa9b878fSDan Carpenter sizeof(ipc4_msg->header_u64)))
196d9a251a0SDan Carpenter return -EFAULT;
197066c6762SPeter Ujfalusi
198*fa9b878fSDan Carpenter data_size = count - sizeof(ipc4_msg->header_u64);
199*fa9b878fSDan Carpenter if (data_size > priv->max_msg_size)
200*fa9b878fSDan Carpenter return -EINVAL;
201*fa9b878fSDan Carpenter
202066c6762SPeter Ujfalusi /* Copy the payload */
203*fa9b878fSDan Carpenter if (copy_from_user(ipc4_msg->data_ptr,
204*fa9b878fSDan Carpenter buffer + sizeof(ipc4_msg->header_u64), data_size))
205d9a251a0SDan Carpenter return -EFAULT;
206066c6762SPeter Ujfalusi
207*fa9b878fSDan Carpenter ipc4_msg->data_size = data_size;
208066c6762SPeter Ujfalusi
209066c6762SPeter Ujfalusi /* Initialize the reply storage */
210066c6762SPeter Ujfalusi ipc4_msg = priv->rx_buffer;
211066c6762SPeter Ujfalusi ipc4_msg->header_u64 = 0;
212066c6762SPeter Ujfalusi ipc4_msg->data_size = priv->max_msg_size;
213066c6762SPeter Ujfalusi memset(ipc4_msg->data_ptr, 0, priv->max_msg_size);
214066c6762SPeter Ujfalusi
215066c6762SPeter Ujfalusi ret = sof_msg_inject_send_message(cdev);
216066c6762SPeter Ujfalusi
217066c6762SPeter Ujfalusi /* return the error code if test failed */
218066c6762SPeter Ujfalusi if (ret < 0)
219*fa9b878fSDan Carpenter return ret;
220066c6762SPeter Ujfalusi
221*fa9b878fSDan Carpenter return count;
222066c6762SPeter Ujfalusi };
223066c6762SPeter Ujfalusi
sof_msg_inject_dfs_release(struct inode * inode,struct file * file)224cac0b088SPeter Ujfalusi static int sof_msg_inject_dfs_release(struct inode *inode, struct file *file)
225cac0b088SPeter Ujfalusi {
226cac0b088SPeter Ujfalusi debugfs_file_put(file->f_path.dentry);
227cac0b088SPeter Ujfalusi
228cac0b088SPeter Ujfalusi return 0;
229cac0b088SPeter Ujfalusi }
230cac0b088SPeter Ujfalusi
231cac0b088SPeter Ujfalusi static const struct file_operations sof_msg_inject_fops = {
232cac0b088SPeter Ujfalusi .open = sof_msg_inject_dfs_open,
233cac0b088SPeter Ujfalusi .read = sof_msg_inject_dfs_read,
234cac0b088SPeter Ujfalusi .write = sof_msg_inject_dfs_write,
235cac0b088SPeter Ujfalusi .llseek = default_llseek,
236cac0b088SPeter Ujfalusi .release = sof_msg_inject_dfs_release,
237cac0b088SPeter Ujfalusi
238cac0b088SPeter Ujfalusi .owner = THIS_MODULE,
239cac0b088SPeter Ujfalusi };
240cac0b088SPeter Ujfalusi
241066c6762SPeter Ujfalusi static const struct file_operations sof_msg_inject_ipc4_fops = {
242066c6762SPeter Ujfalusi .open = sof_msg_inject_dfs_open,
243066c6762SPeter Ujfalusi .read = sof_msg_inject_ipc4_dfs_read,
244066c6762SPeter Ujfalusi .write = sof_msg_inject_ipc4_dfs_write,
245066c6762SPeter Ujfalusi .llseek = default_llseek,
246066c6762SPeter Ujfalusi .release = sof_msg_inject_dfs_release,
247066c6762SPeter Ujfalusi
248066c6762SPeter Ujfalusi .owner = THIS_MODULE,
249066c6762SPeter Ujfalusi };
250066c6762SPeter Ujfalusi
sof_msg_inject_probe(struct auxiliary_device * auxdev,const struct auxiliary_device_id * id)251cac0b088SPeter Ujfalusi static int sof_msg_inject_probe(struct auxiliary_device *auxdev,
252cac0b088SPeter Ujfalusi const struct auxiliary_device_id *id)
253cac0b088SPeter Ujfalusi {
254cac0b088SPeter Ujfalusi struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
255cac0b088SPeter Ujfalusi struct dentry *debugfs_root = sof_client_get_debugfs_root(cdev);
256066c6762SPeter Ujfalusi static const struct file_operations *fops;
257cac0b088SPeter Ujfalusi struct device *dev = &auxdev->dev;
258cac0b088SPeter Ujfalusi struct sof_msg_inject_priv *priv;
259066c6762SPeter Ujfalusi size_t alloc_size;
260cac0b088SPeter Ujfalusi
261cac0b088SPeter Ujfalusi /* allocate memory for client data */
262cac0b088SPeter Ujfalusi priv = devm_kzalloc(&auxdev->dev, sizeof(*priv), GFP_KERNEL);
263cac0b088SPeter Ujfalusi if (!priv)
264cac0b088SPeter Ujfalusi return -ENOMEM;
265cac0b088SPeter Ujfalusi
266066c6762SPeter Ujfalusi priv->ipc_type = sof_client_get_ipc_type(cdev);
267ef368c33SPeter Ujfalusi priv->max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
268066c6762SPeter Ujfalusi alloc_size = priv->max_msg_size;
269066c6762SPeter Ujfalusi
270066c6762SPeter Ujfalusi if (priv->ipc_type == SOF_INTEL_IPC4)
271066c6762SPeter Ujfalusi alloc_size += sizeof(struct sof_ipc4_msg);
272066c6762SPeter Ujfalusi
273066c6762SPeter Ujfalusi priv->tx_buffer = devm_kmalloc(dev, alloc_size, GFP_KERNEL);
274066c6762SPeter Ujfalusi priv->rx_buffer = devm_kzalloc(dev, alloc_size, GFP_KERNEL);
275cac0b088SPeter Ujfalusi if (!priv->tx_buffer || !priv->rx_buffer)
276cac0b088SPeter Ujfalusi return -ENOMEM;
277cac0b088SPeter Ujfalusi
278066c6762SPeter Ujfalusi if (priv->ipc_type == SOF_INTEL_IPC4) {
279066c6762SPeter Ujfalusi struct sof_ipc4_msg *ipc4_msg;
280066c6762SPeter Ujfalusi
281066c6762SPeter Ujfalusi ipc4_msg = priv->tx_buffer;
282066c6762SPeter Ujfalusi ipc4_msg->data_ptr = priv->tx_buffer + sizeof(struct sof_ipc4_msg);
283066c6762SPeter Ujfalusi
284066c6762SPeter Ujfalusi ipc4_msg = priv->rx_buffer;
285066c6762SPeter Ujfalusi ipc4_msg->data_ptr = priv->rx_buffer + sizeof(struct sof_ipc4_msg);
286066c6762SPeter Ujfalusi
287066c6762SPeter Ujfalusi fops = &sof_msg_inject_ipc4_fops;
288066c6762SPeter Ujfalusi } else {
289066c6762SPeter Ujfalusi fops = &sof_msg_inject_fops;
290066c6762SPeter Ujfalusi }
291066c6762SPeter Ujfalusi
292cac0b088SPeter Ujfalusi cdev->data = priv;
293cac0b088SPeter Ujfalusi
294cac0b088SPeter Ujfalusi priv->dfs_file = debugfs_create_file("ipc_msg_inject", 0644, debugfs_root,
295066c6762SPeter Ujfalusi cdev, fops);
296cac0b088SPeter Ujfalusi
297cac0b088SPeter Ujfalusi /* enable runtime PM */
298cac0b088SPeter Ujfalusi pm_runtime_set_autosuspend_delay(dev, SOF_IPC_CLIENT_SUSPEND_DELAY_MS);
299cac0b088SPeter Ujfalusi pm_runtime_use_autosuspend(dev);
300cac0b088SPeter Ujfalusi pm_runtime_enable(dev);
301cac0b088SPeter Ujfalusi pm_runtime_mark_last_busy(dev);
302cac0b088SPeter Ujfalusi pm_runtime_idle(dev);
303cac0b088SPeter Ujfalusi
304cac0b088SPeter Ujfalusi return 0;
305cac0b088SPeter Ujfalusi }
306cac0b088SPeter Ujfalusi
sof_msg_inject_remove(struct auxiliary_device * auxdev)307cac0b088SPeter Ujfalusi static void sof_msg_inject_remove(struct auxiliary_device *auxdev)
308cac0b088SPeter Ujfalusi {
309cac0b088SPeter Ujfalusi struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
310cac0b088SPeter Ujfalusi struct sof_msg_inject_priv *priv = cdev->data;
311cac0b088SPeter Ujfalusi
312cac0b088SPeter Ujfalusi pm_runtime_disable(&auxdev->dev);
313cac0b088SPeter Ujfalusi
314cac0b088SPeter Ujfalusi debugfs_remove(priv->dfs_file);
315cac0b088SPeter Ujfalusi }
316cac0b088SPeter Ujfalusi
317cac0b088SPeter Ujfalusi static const struct auxiliary_device_id sof_msg_inject_client_id_table[] = {
318cac0b088SPeter Ujfalusi { .name = "snd_sof.msg_injector" },
319cac0b088SPeter Ujfalusi {},
320cac0b088SPeter Ujfalusi };
321cac0b088SPeter Ujfalusi MODULE_DEVICE_TABLE(auxiliary, sof_msg_inject_client_id_table);
322cac0b088SPeter Ujfalusi
323cac0b088SPeter Ujfalusi /*
324cac0b088SPeter Ujfalusi * No need for driver pm_ops as the generic pm callbacks in the auxiliary bus
325cac0b088SPeter Ujfalusi * type are enough to ensure that the parent SOF device resumes to bring the DSP
326cac0b088SPeter Ujfalusi * back to D0.
327cac0b088SPeter Ujfalusi * Driver name will be set based on KBUILD_MODNAME.
328cac0b088SPeter Ujfalusi */
329cac0b088SPeter Ujfalusi static struct auxiliary_driver sof_msg_inject_client_drv = {
330cac0b088SPeter Ujfalusi .probe = sof_msg_inject_probe,
331cac0b088SPeter Ujfalusi .remove = sof_msg_inject_remove,
332cac0b088SPeter Ujfalusi
333cac0b088SPeter Ujfalusi .id_table = sof_msg_inject_client_id_table,
334cac0b088SPeter Ujfalusi };
335cac0b088SPeter Ujfalusi
336cac0b088SPeter Ujfalusi module_auxiliary_driver(sof_msg_inject_client_drv);
337cac0b088SPeter Ujfalusi
338cac0b088SPeter Ujfalusi MODULE_DESCRIPTION("SOF IPC Message Injector Client Driver");
339cac0b088SPeter Ujfalusi MODULE_LICENSE("GPL");
340cac0b088SPeter Ujfalusi MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
341