0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/debugfs.h>
0013 #include <linux/module.h>
0014 #include <linux/pm_runtime.h>
0015 #include <sound/soc.h>
0016 #include <sound/sof/header.h>
0017 #include "sof-client.h"
0018 #include "sof-client-probes.h"
0019
0020 #define SOF_PROBES_SUSPEND_DELAY_MS 3000
0021
0022 #define SOF_PROBES_NUM_DAI_LINKS 1
0023
0024 #define SOF_PROBES_INVALID_NODE_ID UINT_MAX
0025
0026 static bool __read_mostly sof_probes_enabled;
0027 module_param_named(enable, sof_probes_enabled, bool, 0444);
0028 MODULE_PARM_DESC(enable, "Enable SOF probes support");
0029
0030 struct sof_probes_priv {
0031 struct dentry *dfs_points;
0032 struct dentry *dfs_points_remove;
0033 u32 extractor_stream_tag;
0034 struct snd_soc_card card;
0035
0036 const struct sof_probes_host_ops *host_ops;
0037 };
0038
0039 struct sof_probe_point_desc {
0040 unsigned int buffer_id;
0041 unsigned int purpose;
0042 unsigned int stream_tag;
0043 } __packed;
0044
0045 struct sof_probe_dma {
0046 unsigned int stream_tag;
0047 unsigned int dma_buffer_size;
0048 } __packed;
0049
0050 struct sof_ipc_probe_dma_add_params {
0051 struct sof_ipc_cmd_hdr hdr;
0052 unsigned int num_elems;
0053 struct sof_probe_dma dma[];
0054 } __packed;
0055
0056 struct sof_ipc_probe_info_params {
0057 struct sof_ipc_reply rhdr;
0058 unsigned int num_elems;
0059 union {
0060 struct sof_probe_dma dma[0];
0061 struct sof_probe_point_desc desc[0];
0062 };
0063 } __packed;
0064
0065 struct sof_ipc_probe_point_add_params {
0066 struct sof_ipc_cmd_hdr hdr;
0067 unsigned int num_elems;
0068 struct sof_probe_point_desc desc[];
0069 } __packed;
0070
0071 struct sof_ipc_probe_point_remove_params {
0072 struct sof_ipc_cmd_hdr hdr;
0073 unsigned int num_elems;
0074 unsigned int buffer_id[];
0075 } __packed;
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091 static int sof_probes_init(struct sof_client_dev *cdev, u32 stream_tag,
0092 size_t buffer_size)
0093 {
0094 struct sof_ipc_probe_dma_add_params *msg;
0095 size_t size = struct_size(msg, dma, 1);
0096 struct sof_ipc_reply reply;
0097 int ret;
0098
0099 msg = kmalloc(size, GFP_KERNEL);
0100 if (!msg)
0101 return -ENOMEM;
0102 msg->hdr.size = size;
0103 msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_INIT;
0104 msg->num_elems = 1;
0105 msg->dma[0].stream_tag = stream_tag;
0106 msg->dma[0].dma_buffer_size = buffer_size;
0107
0108 ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
0109 kfree(msg);
0110 return ret;
0111 }
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 static int sof_probes_deinit(struct sof_client_dev *cdev)
0122 {
0123 struct sof_ipc_cmd_hdr msg;
0124 struct sof_ipc_reply reply;
0125
0126 msg.size = sizeof(msg);
0127 msg.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_DEINIT;
0128
0129 return sof_client_ipc_tx_message(cdev, &msg, &reply, sizeof(reply));
0130 }
0131
0132 static int sof_probes_info(struct sof_client_dev *cdev, unsigned int cmd,
0133 void **params, size_t *num_params)
0134 {
0135 size_t max_msg_size = sof_client_get_ipc_max_payload_size(cdev);
0136 struct sof_ipc_probe_info_params msg = {{{0}}};
0137 struct sof_ipc_probe_info_params *reply;
0138 size_t bytes;
0139 int ret;
0140
0141 *params = NULL;
0142 *num_params = 0;
0143
0144 reply = kzalloc(max_msg_size, GFP_KERNEL);
0145 if (!reply)
0146 return -ENOMEM;
0147 msg.rhdr.hdr.size = sizeof(msg);
0148 msg.rhdr.hdr.cmd = SOF_IPC_GLB_PROBE | cmd;
0149
0150 ret = sof_client_ipc_tx_message(cdev, &msg, reply, max_msg_size);
0151 if (ret < 0 || reply->rhdr.error < 0)
0152 goto exit;
0153
0154 if (!reply->num_elems)
0155 goto exit;
0156
0157 if (cmd == SOF_IPC_PROBE_DMA_INFO)
0158 bytes = sizeof(reply->dma[0]);
0159 else
0160 bytes = sizeof(reply->desc[0]);
0161 bytes *= reply->num_elems;
0162 *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL);
0163 if (!*params) {
0164 ret = -ENOMEM;
0165 goto exit;
0166 }
0167 *num_params = reply->num_elems;
0168
0169 exit:
0170 kfree(reply);
0171 return ret;
0172 }
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184 static int sof_probes_points_info(struct sof_client_dev *cdev,
0185 struct sof_probe_point_desc **desc,
0186 size_t *num_desc)
0187 {
0188 return sof_probes_info(cdev, SOF_IPC_PROBE_POINT_INFO,
0189 (void **)desc, num_desc);
0190 }
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205 static int sof_probes_points_add(struct sof_client_dev *cdev,
0206 struct sof_probe_point_desc *desc,
0207 size_t num_desc)
0208 {
0209 struct sof_ipc_probe_point_add_params *msg;
0210 size_t size = struct_size(msg, desc, num_desc);
0211 struct sof_ipc_reply reply;
0212 int ret;
0213
0214 msg = kmalloc(size, GFP_KERNEL);
0215 if (!msg)
0216 return -ENOMEM;
0217 msg->hdr.size = size;
0218 msg->num_elems = num_desc;
0219 msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_ADD;
0220 memcpy(&msg->desc[0], desc, size - sizeof(*msg));
0221
0222 ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
0223 kfree(msg);
0224 return ret;
0225 }
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 static int sof_probes_points_remove(struct sof_client_dev *cdev,
0237 unsigned int *buffer_id, size_t num_buffer_id)
0238 {
0239 struct sof_ipc_probe_point_remove_params *msg;
0240 size_t size = struct_size(msg, buffer_id, num_buffer_id);
0241 struct sof_ipc_reply reply;
0242 int ret;
0243
0244 msg = kmalloc(size, GFP_KERNEL);
0245 if (!msg)
0246 return -ENOMEM;
0247 msg->hdr.size = size;
0248 msg->num_elems = num_buffer_id;
0249 msg->hdr.cmd = SOF_IPC_GLB_PROBE | SOF_IPC_PROBE_POINT_REMOVE;
0250 memcpy(&msg->buffer_id[0], buffer_id, size - sizeof(*msg));
0251
0252 ret = sof_client_ipc_tx_message(cdev, msg, &reply, sizeof(reply));
0253 kfree(msg);
0254 return ret;
0255 }
0256
0257 static int sof_probes_compr_startup(struct snd_compr_stream *cstream,
0258 struct snd_soc_dai *dai)
0259 {
0260 struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
0261 struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
0262 struct sof_probes_priv *priv = cdev->data;
0263 const struct sof_probes_host_ops *ops = priv->host_ops;
0264 int ret;
0265
0266 if (sof_client_get_fw_state(cdev) == SOF_FW_CRASHED)
0267 return -ENODEV;
0268
0269 ret = sof_client_core_module_get(cdev);
0270 if (ret)
0271 return ret;
0272
0273 ret = ops->startup(cdev, cstream, dai, &priv->extractor_stream_tag);
0274 if (ret) {
0275 dev_err(dai->dev, "Failed to startup probe stream: %d\n", ret);
0276 priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
0277 sof_client_core_module_put(cdev);
0278 }
0279
0280 return ret;
0281 }
0282
0283 static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream,
0284 struct snd_soc_dai *dai)
0285 {
0286 struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
0287 struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
0288 struct sof_probes_priv *priv = cdev->data;
0289 const struct sof_probes_host_ops *ops = priv->host_ops;
0290 struct sof_probe_point_desc *desc;
0291 size_t num_desc;
0292 int i, ret;
0293
0294
0295 ret = sof_probes_points_info(cdev, &desc, &num_desc);
0296 if (ret < 0) {
0297 dev_err(dai->dev, "Failed to get probe points: %d\n", ret);
0298 goto exit;
0299 }
0300
0301 for (i = 0; i < num_desc; i++)
0302 sof_probes_points_remove(cdev, &desc[i].buffer_id, 1);
0303 kfree(desc);
0304
0305 exit:
0306 ret = sof_probes_deinit(cdev);
0307 if (ret < 0)
0308 dev_err(dai->dev, "Failed to deinit probe: %d\n", ret);
0309
0310 priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
0311 snd_compr_free_pages(cstream);
0312
0313 ret = ops->shutdown(cdev, cstream, dai);
0314
0315 sof_client_core_module_put(cdev);
0316
0317 return ret;
0318 }
0319
0320 static int sof_probes_compr_set_params(struct snd_compr_stream *cstream,
0321 struct snd_compr_params *params,
0322 struct snd_soc_dai *dai)
0323 {
0324 struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
0325 struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
0326 struct snd_compr_runtime *rtd = cstream->runtime;
0327 struct sof_probes_priv *priv = cdev->data;
0328 const struct sof_probes_host_ops *ops = priv->host_ops;
0329 int ret;
0330
0331 cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
0332 cstream->dma_buffer.dev.dev = sof_client_get_dma_dev(cdev);
0333 ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
0334 if (ret < 0)
0335 return ret;
0336
0337 ret = ops->set_params(cdev, cstream, params, dai);
0338 if (ret)
0339 return ret;
0340
0341 ret = sof_probes_init(cdev, priv->extractor_stream_tag, rtd->dma_bytes);
0342 if (ret < 0) {
0343 dev_err(dai->dev, "Failed to init probe: %d\n", ret);
0344 return ret;
0345 }
0346
0347 return 0;
0348 }
0349
0350 static int sof_probes_compr_trigger(struct snd_compr_stream *cstream, int cmd,
0351 struct snd_soc_dai *dai)
0352 {
0353 struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
0354 struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
0355 struct sof_probes_priv *priv = cdev->data;
0356 const struct sof_probes_host_ops *ops = priv->host_ops;
0357
0358 return ops->trigger(cdev, cstream, cmd, dai);
0359 }
0360
0361 static int sof_probes_compr_pointer(struct snd_compr_stream *cstream,
0362 struct snd_compr_tstamp *tstamp,
0363 struct snd_soc_dai *dai)
0364 {
0365 struct snd_soc_card *card = snd_soc_component_get_drvdata(dai->component);
0366 struct sof_client_dev *cdev = snd_soc_card_get_drvdata(card);
0367 struct sof_probes_priv *priv = cdev->data;
0368 const struct sof_probes_host_ops *ops = priv->host_ops;
0369
0370 return ops->pointer(cdev, cstream, tstamp, dai);
0371 }
0372
0373 static const struct snd_soc_cdai_ops sof_probes_compr_ops = {
0374 .startup = sof_probes_compr_startup,
0375 .shutdown = sof_probes_compr_shutdown,
0376 .set_params = sof_probes_compr_set_params,
0377 .trigger = sof_probes_compr_trigger,
0378 .pointer = sof_probes_compr_pointer,
0379 };
0380
0381 static int sof_probes_compr_copy(struct snd_soc_component *component,
0382 struct snd_compr_stream *cstream,
0383 char __user *buf, size_t count)
0384 {
0385 struct snd_compr_runtime *rtd = cstream->runtime;
0386 unsigned int offset, n;
0387 void *ptr;
0388 int ret;
0389
0390 if (count > rtd->buffer_size)
0391 count = rtd->buffer_size;
0392
0393 div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
0394 ptr = rtd->dma_area + offset;
0395 n = rtd->buffer_size - offset;
0396
0397 if (count < n) {
0398 ret = copy_to_user(buf, ptr, count);
0399 } else {
0400 ret = copy_to_user(buf, ptr, n);
0401 ret += copy_to_user(buf + n, rtd->dma_area, count - n);
0402 }
0403
0404 if (ret)
0405 return count - ret;
0406 return count;
0407 }
0408
0409 static const struct snd_compress_ops sof_probes_compressed_ops = {
0410 .copy = sof_probes_compr_copy,
0411 };
0412
0413
0414
0415
0416
0417
0418
0419
0420 static int strsplit_u32(char *buf, const char *delim, u32 **tkns, size_t *num_tkns)
0421 {
0422 char *s;
0423 u32 *data, *tmp;
0424 size_t count = 0;
0425 size_t cap = 32;
0426 int ret = 0;
0427
0428 *tkns = NULL;
0429 *num_tkns = 0;
0430 data = kcalloc(cap, sizeof(*data), GFP_KERNEL);
0431 if (!data)
0432 return -ENOMEM;
0433
0434 while ((s = strsep(&buf, delim)) != NULL) {
0435 ret = kstrtouint(s, 0, data + count);
0436 if (ret)
0437 goto exit;
0438 if (++count >= cap) {
0439 cap *= 2;
0440 tmp = krealloc(data, cap * sizeof(*data), GFP_KERNEL);
0441 if (!tmp) {
0442 ret = -ENOMEM;
0443 goto exit;
0444 }
0445 data = tmp;
0446 }
0447 }
0448
0449 if (!count)
0450 goto exit;
0451 *tkns = kmemdup(data, count * sizeof(*data), GFP_KERNEL);
0452 if (!(*tkns)) {
0453 ret = -ENOMEM;
0454 goto exit;
0455 }
0456 *num_tkns = count;
0457
0458 exit:
0459 kfree(data);
0460 return ret;
0461 }
0462
0463 static int tokenize_input(const char __user *from, size_t count,
0464 loff_t *ppos, u32 **tkns, size_t *num_tkns)
0465 {
0466 char *buf;
0467 int ret;
0468
0469 buf = kmalloc(count + 1, GFP_KERNEL);
0470 if (!buf)
0471 return -ENOMEM;
0472
0473 ret = simple_write_to_buffer(buf, count, ppos, from, count);
0474 if (ret != count) {
0475 ret = ret >= 0 ? -EIO : ret;
0476 goto exit;
0477 }
0478
0479 buf[count] = '\0';
0480 ret = strsplit_u32(buf, ",", tkns, num_tkns);
0481 exit:
0482 kfree(buf);
0483 return ret;
0484 }
0485
0486 static ssize_t sof_probes_dfs_points_read(struct file *file, char __user *to,
0487 size_t count, loff_t *ppos)
0488 {
0489 struct sof_client_dev *cdev = file->private_data;
0490 struct sof_probes_priv *priv = cdev->data;
0491 struct device *dev = &cdev->auxdev.dev;
0492 struct sof_probe_point_desc *desc;
0493 int remaining, offset;
0494 size_t num_desc;
0495 char *buf;
0496 int i, ret, err;
0497
0498 if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) {
0499 dev_warn(dev, "no extractor stream running\n");
0500 return -ENOENT;
0501 }
0502
0503 buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
0504 if (!buf)
0505 return -ENOMEM;
0506
0507 ret = pm_runtime_resume_and_get(dev);
0508 if (ret < 0 && ret != -EACCES) {
0509 dev_err_ratelimited(dev, "debugfs read failed to resume %d\n", ret);
0510 goto exit;
0511 }
0512
0513 ret = sof_probes_points_info(cdev, &desc, &num_desc);
0514 if (ret < 0)
0515 goto exit;
0516
0517 pm_runtime_mark_last_busy(dev);
0518 err = pm_runtime_put_autosuspend(dev);
0519 if (err < 0)
0520 dev_err_ratelimited(dev, "debugfs read failed to idle %d\n", err);
0521
0522 for (i = 0; i < num_desc; i++) {
0523 offset = strlen(buf);
0524 remaining = PAGE_SIZE - offset;
0525 ret = snprintf(buf + offset, remaining,
0526 "Id: %#010x Purpose: %u Node id: %#x\n",
0527 desc[i].buffer_id, desc[i].purpose, desc[i].stream_tag);
0528 if (ret < 0 || ret >= remaining) {
0529
0530 buf[offset] = '\0';
0531 break;
0532 }
0533 }
0534
0535 ret = simple_read_from_buffer(to, count, ppos, buf, strlen(buf));
0536
0537 kfree(desc);
0538 exit:
0539 kfree(buf);
0540 return ret;
0541 }
0542
0543 static ssize_t
0544 sof_probes_dfs_points_write(struct file *file, const char __user *from,
0545 size_t count, loff_t *ppos)
0546 {
0547 struct sof_client_dev *cdev = file->private_data;
0548 struct sof_probes_priv *priv = cdev->data;
0549 struct device *dev = &cdev->auxdev.dev;
0550 struct sof_probe_point_desc *desc;
0551 size_t num_tkns, bytes;
0552 u32 *tkns;
0553 int ret, err;
0554
0555 if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) {
0556 dev_warn(dev, "no extractor stream running\n");
0557 return -ENOENT;
0558 }
0559
0560 ret = tokenize_input(from, count, ppos, &tkns, &num_tkns);
0561 if (ret < 0)
0562 return ret;
0563 bytes = sizeof(*tkns) * num_tkns;
0564 if (!num_tkns || (bytes % sizeof(*desc))) {
0565 ret = -EINVAL;
0566 goto exit;
0567 }
0568
0569 desc = (struct sof_probe_point_desc *)tkns;
0570
0571 ret = pm_runtime_resume_and_get(dev);
0572 if (ret < 0 && ret != -EACCES) {
0573 dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret);
0574 goto exit;
0575 }
0576
0577 ret = sof_probes_points_add(cdev, desc, bytes / sizeof(*desc));
0578 if (!ret)
0579 ret = count;
0580
0581 pm_runtime_mark_last_busy(dev);
0582 err = pm_runtime_put_autosuspend(dev);
0583 if (err < 0)
0584 dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
0585 exit:
0586 kfree(tkns);
0587 return ret;
0588 }
0589
0590 static const struct file_operations sof_probes_points_fops = {
0591 .open = simple_open,
0592 .read = sof_probes_dfs_points_read,
0593 .write = sof_probes_dfs_points_write,
0594 .llseek = default_llseek,
0595
0596 .owner = THIS_MODULE,
0597 };
0598
0599 static ssize_t
0600 sof_probes_dfs_points_remove_write(struct file *file, const char __user *from,
0601 size_t count, loff_t *ppos)
0602 {
0603 struct sof_client_dev *cdev = file->private_data;
0604 struct sof_probes_priv *priv = cdev->data;
0605 struct device *dev = &cdev->auxdev.dev;
0606 size_t num_tkns;
0607 u32 *tkns;
0608 int ret, err;
0609
0610 if (priv->extractor_stream_tag == SOF_PROBES_INVALID_NODE_ID) {
0611 dev_warn(dev, "no extractor stream running\n");
0612 return -ENOENT;
0613 }
0614
0615 ret = tokenize_input(from, count, ppos, &tkns, &num_tkns);
0616 if (ret < 0)
0617 return ret;
0618 if (!num_tkns) {
0619 ret = -EINVAL;
0620 goto exit;
0621 }
0622
0623 ret = pm_runtime_resume_and_get(dev);
0624 if (ret < 0) {
0625 dev_err_ratelimited(dev, "debugfs write failed to resume %d\n", ret);
0626 goto exit;
0627 }
0628
0629 ret = sof_probes_points_remove(cdev, tkns, num_tkns);
0630 if (!ret)
0631 ret = count;
0632
0633 pm_runtime_mark_last_busy(dev);
0634 err = pm_runtime_put_autosuspend(dev);
0635 if (err < 0)
0636 dev_err_ratelimited(dev, "debugfs write failed to idle %d\n", err);
0637 exit:
0638 kfree(tkns);
0639 return ret;
0640 }
0641
0642 static const struct file_operations sof_probes_points_remove_fops = {
0643 .open = simple_open,
0644 .write = sof_probes_dfs_points_remove_write,
0645 .llseek = default_llseek,
0646
0647 .owner = THIS_MODULE,
0648 };
0649
0650 static struct snd_soc_dai_driver sof_probes_dai_drv[] = {
0651 {
0652 .name = "Probe Extraction CPU DAI",
0653 .compress_new = snd_soc_new_compress,
0654 .cops = &sof_probes_compr_ops,
0655 .capture = {
0656 .stream_name = "Probe Extraction",
0657 .channels_min = 1,
0658 .channels_max = 8,
0659 .rates = SNDRV_PCM_RATE_48000,
0660 .rate_min = 48000,
0661 .rate_max = 48000,
0662 },
0663 },
0664 };
0665
0666 static const struct snd_soc_component_driver sof_probes_component = {
0667 .name = "sof-probes-component",
0668 .compress_ops = &sof_probes_compressed_ops,
0669 .module_get_upon_open = 1,
0670 .legacy_dai_naming = 1,
0671 };
0672
0673 SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
0674
0675 static int sof_probes_client_probe(struct auxiliary_device *auxdev,
0676 const struct auxiliary_device_id *id)
0677 {
0678 struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
0679 struct dentry *dfsroot = sof_client_get_debugfs_root(cdev);
0680 struct device *dev = &auxdev->dev;
0681 struct snd_soc_dai_link_component platform_component[] = {
0682 {
0683 .name = dev_name(dev),
0684 }
0685 };
0686 struct snd_soc_card *card;
0687 struct sof_probes_priv *priv;
0688 struct snd_soc_dai_link_component *cpus;
0689 struct sof_probes_host_ops *ops;
0690 struct snd_soc_dai_link *links;
0691 int ret;
0692
0693
0694 if (!sof_probes_enabled)
0695 return -ENXIO;
0696
0697
0698 if (sof_client_get_ipc_type(cdev) != SOF_IPC)
0699 return -ENXIO;
0700
0701 if (!dev->platform_data) {
0702 dev_err(dev, "missing platform data\n");
0703 return -ENODEV;
0704 }
0705
0706 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0707 if (!priv)
0708 return -ENOMEM;
0709
0710 ops = dev->platform_data;
0711
0712 if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
0713 !ops->pointer) {
0714 dev_err(dev, "missing platform callback(s)\n");
0715 return -ENODEV;
0716 }
0717
0718 priv->host_ops = ops;
0719 cdev->data = priv;
0720
0721
0722 ret = devm_snd_soc_register_component(dev, &sof_probes_component,
0723 sof_probes_dai_drv,
0724 ARRAY_SIZE(sof_probes_dai_drv));
0725 if (ret < 0) {
0726 dev_err(dev, "failed to register SOF probes DAI driver %d\n", ret);
0727 return ret;
0728 }
0729
0730
0731 priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
0732
0733
0734 priv->dfs_points = debugfs_create_file("probe_points", 0644, dfsroot,
0735 cdev, &sof_probes_points_fops);
0736
0737
0738 priv->dfs_points_remove = debugfs_create_file("probe_points_remove", 0644,
0739 dfsroot, cdev,
0740 &sof_probes_points_remove_fops);
0741
0742 links = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*links), GFP_KERNEL);
0743 cpus = devm_kcalloc(dev, SOF_PROBES_NUM_DAI_LINKS, sizeof(*cpus), GFP_KERNEL);
0744 if (!links || !cpus) {
0745 debugfs_remove(priv->dfs_points);
0746 debugfs_remove(priv->dfs_points_remove);
0747 return -ENOMEM;
0748 }
0749
0750
0751 links[0].name = "Compress Probe Capture";
0752 links[0].id = 0;
0753 links[0].cpus = &cpus[0];
0754 links[0].num_cpus = 1;
0755 links[0].cpus->dai_name = "Probe Extraction CPU DAI";
0756 links[0].codecs = dummy;
0757 links[0].num_codecs = 1;
0758 links[0].platforms = platform_component;
0759 links[0].num_platforms = ARRAY_SIZE(platform_component);
0760 links[0].nonatomic = 1;
0761
0762 card = &priv->card;
0763
0764 card->dev = dev;
0765 card->name = "sof-probes";
0766 card->owner = THIS_MODULE;
0767 card->num_links = SOF_PROBES_NUM_DAI_LINKS;
0768 card->dai_link = links;
0769
0770
0771 card->dapm.idle_bias_off = true;
0772
0773 snd_soc_card_set_drvdata(card, cdev);
0774
0775 ret = devm_snd_soc_register_card(dev, card);
0776 if (ret < 0) {
0777 debugfs_remove(priv->dfs_points);
0778 debugfs_remove(priv->dfs_points_remove);
0779 dev_err(dev, "Probes card register failed %d\n", ret);
0780 return ret;
0781 }
0782
0783
0784 pm_runtime_set_autosuspend_delay(dev, SOF_PROBES_SUSPEND_DELAY_MS);
0785 pm_runtime_use_autosuspend(dev);
0786 pm_runtime_enable(dev);
0787 pm_runtime_mark_last_busy(dev);
0788 pm_runtime_idle(dev);
0789
0790 return 0;
0791 }
0792
0793 static void sof_probes_client_remove(struct auxiliary_device *auxdev)
0794 {
0795 struct sof_client_dev *cdev = auxiliary_dev_to_sof_client_dev(auxdev);
0796 struct sof_probes_priv *priv = cdev->data;
0797
0798 if (!sof_probes_enabled)
0799 return;
0800
0801 pm_runtime_disable(&auxdev->dev);
0802 debugfs_remove(priv->dfs_points);
0803 debugfs_remove(priv->dfs_points_remove);
0804 }
0805
0806 static const struct auxiliary_device_id sof_probes_client_id_table[] = {
0807 { .name = "snd_sof.hda-probes", },
0808 {},
0809 };
0810 MODULE_DEVICE_TABLE(auxiliary, sof_probes_client_id_table);
0811
0812
0813 static struct auxiliary_driver sof_probes_client_drv = {
0814 .probe = sof_probes_client_probe,
0815 .remove = sof_probes_client_remove,
0816
0817 .id_table = sof_probes_client_id_table,
0818 };
0819
0820 module_auxiliary_driver(sof_probes_client_drv);
0821
0822 MODULE_DESCRIPTION("SOF Probes Client Driver");
0823 MODULE_LICENSE("GPL v2");
0824 MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);