cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

audio_module.c (12660B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Greybus audio driver
      4 * Copyright 2015 Google Inc.
      5 * Copyright 2015 Linaro Ltd.
      6 */
      7#include <linux/kernel.h>
      8#include <linux/module.h>
      9#include <sound/soc.h>
     10#include <sound/pcm_params.h>
     11
     12#include "audio_codec.h"
     13#include "audio_apbridgea.h"
     14#include "audio_manager.h"
     15
     16/*
     17 * gb_snd management functions
     18 */
     19
     20static int gbaudio_request_jack(struct gbaudio_module_info *module,
     21				struct gb_audio_jack_event_request *req)
     22{
     23	int report;
     24	struct snd_jack *jack = module->headset.jack.jack;
     25	struct snd_jack *btn_jack = module->button.jack.jack;
     26
     27	if (!jack) {
     28		dev_err_ratelimited(module->dev,
     29				    "Invalid jack event received:type: %u, event: %u\n",
     30				    req->jack_attribute, req->event);
     31		return -EINVAL;
     32	}
     33
     34	dev_warn_ratelimited(module->dev,
     35			     "Jack Event received: type: %u, event: %u\n",
     36			     req->jack_attribute, req->event);
     37
     38	if (req->event == GB_AUDIO_JACK_EVENT_REMOVAL) {
     39		module->jack_type = 0;
     40		if (btn_jack && module->button_status) {
     41			snd_soc_jack_report(&module->button.jack, 0,
     42					    module->button_mask);
     43			module->button_status = 0;
     44		}
     45		snd_soc_jack_report(&module->headset.jack, 0,
     46				    module->jack_mask);
     47		return 0;
     48	}
     49
     50	report = req->jack_attribute & module->jack_mask;
     51	if (!report) {
     52		dev_err_ratelimited(module->dev,
     53				    "Invalid jack event received:type: %u, event: %u\n",
     54				    req->jack_attribute, req->event);
     55		return -EINVAL;
     56	}
     57
     58	if (module->jack_type)
     59		dev_warn_ratelimited(module->dev,
     60				     "Modifying jack from %d to %d\n",
     61				     module->jack_type, report);
     62
     63	module->jack_type = report;
     64	snd_soc_jack_report(&module->headset.jack, report, module->jack_mask);
     65
     66	return 0;
     67}
     68
     69static int gbaudio_request_button(struct gbaudio_module_info *module,
     70				  struct gb_audio_button_event_request *req)
     71{
     72	int soc_button_id, report;
     73	struct snd_jack *btn_jack = module->button.jack.jack;
     74
     75	if (!btn_jack) {
     76		dev_err_ratelimited(module->dev,
     77				    "Invalid button event received:type: %u, event: %u\n",
     78				    req->button_id, req->event);
     79		return -EINVAL;
     80	}
     81
     82	dev_warn_ratelimited(module->dev,
     83			     "Button Event received: id: %u, event: %u\n",
     84			     req->button_id, req->event);
     85
     86	/* currently supports 4 buttons only */
     87	if (!module->jack_type) {
     88		dev_err_ratelimited(module->dev,
     89				    "Jack not present. Bogus event!!\n");
     90		return -EINVAL;
     91	}
     92
     93	report = module->button_status & module->button_mask;
     94	soc_button_id = 0;
     95
     96	switch (req->button_id) {
     97	case 1:
     98		soc_button_id = SND_JACK_BTN_0 & module->button_mask;
     99		break;
    100
    101	case 2:
    102		soc_button_id = SND_JACK_BTN_1 & module->button_mask;
    103		break;
    104
    105	case 3:
    106		soc_button_id = SND_JACK_BTN_2 & module->button_mask;
    107		break;
    108
    109	case 4:
    110		soc_button_id = SND_JACK_BTN_3 & module->button_mask;
    111		break;
    112	}
    113
    114	if (!soc_button_id) {
    115		dev_err_ratelimited(module->dev,
    116				    "Invalid button request received\n");
    117		return -EINVAL;
    118	}
    119
    120	if (req->event == GB_AUDIO_BUTTON_EVENT_PRESS)
    121		report = report | soc_button_id;
    122	else
    123		report = report & ~soc_button_id;
    124
    125	module->button_status = report;
    126
    127	snd_soc_jack_report(&module->button.jack, report, module->button_mask);
    128
    129	return 0;
    130}
    131
    132static int gbaudio_request_stream(struct gbaudio_module_info *module,
    133				  struct gb_audio_streaming_event_request *req)
    134{
    135	dev_warn(module->dev, "Audio Event received: cport: %u, event: %u\n",
    136		 le16_to_cpu(req->data_cport), req->event);
    137
    138	return 0;
    139}
    140
    141static int gbaudio_codec_request_handler(struct gb_operation *op)
    142{
    143	struct gb_connection *connection = op->connection;
    144	struct gbaudio_module_info *module =
    145		greybus_get_drvdata(connection->bundle);
    146	struct gb_operation_msg_hdr *header = op->request->header;
    147	struct gb_audio_streaming_event_request *stream_req;
    148	struct gb_audio_jack_event_request *jack_req;
    149	struct gb_audio_button_event_request *button_req;
    150	int ret;
    151
    152	switch (header->type) {
    153	case GB_AUDIO_TYPE_STREAMING_EVENT:
    154		stream_req = op->request->payload;
    155		ret = gbaudio_request_stream(module, stream_req);
    156		break;
    157
    158	case GB_AUDIO_TYPE_JACK_EVENT:
    159		jack_req = op->request->payload;
    160		ret = gbaudio_request_jack(module, jack_req);
    161		break;
    162
    163	case GB_AUDIO_TYPE_BUTTON_EVENT:
    164		button_req = op->request->payload;
    165		ret = gbaudio_request_button(module, button_req);
    166		break;
    167
    168	default:
    169		dev_err_ratelimited(&connection->bundle->dev,
    170				    "Invalid Audio Event received\n");
    171		return -EINVAL;
    172	}
    173
    174	return ret;
    175}
    176
    177static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule,
    178					struct greybus_descriptor_cport *cport_desc,
    179					struct gb_bundle *bundle)
    180{
    181	struct gb_connection *connection;
    182
    183	/* Management Cport */
    184	if (gbmodule->mgmt_connection) {
    185		dev_err(&bundle->dev,
    186			"Can't have multiple Management connections\n");
    187		return -ENODEV;
    188	}
    189
    190	connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id),
    191					  gbaudio_codec_request_handler);
    192	if (IS_ERR(connection))
    193		return PTR_ERR(connection);
    194
    195	greybus_set_drvdata(bundle, gbmodule);
    196	gbmodule->mgmt_connection = connection;
    197
    198	return 0;
    199}
    200
    201static int gb_audio_add_data_connection(struct gbaudio_module_info *gbmodule,
    202					struct greybus_descriptor_cport *cport_desc,
    203					struct gb_bundle *bundle)
    204{
    205	struct gb_connection *connection;
    206	struct gbaudio_data_connection *dai;
    207
    208	dai = devm_kzalloc(gbmodule->dev, sizeof(*dai), GFP_KERNEL);
    209	if (!dai)
    210		return -ENOMEM;
    211
    212	connection = gb_connection_create_offloaded(bundle,
    213						    le16_to_cpu(cport_desc->id),
    214						    GB_CONNECTION_FLAG_CSD);
    215	if (IS_ERR(connection)) {
    216		devm_kfree(gbmodule->dev, dai);
    217		return PTR_ERR(connection);
    218	}
    219
    220	greybus_set_drvdata(bundle, gbmodule);
    221	dai->id = 0;
    222	dai->data_cport = cpu_to_le16(connection->intf_cport_id);
    223	dai->connection = connection;
    224	list_add(&dai->list, &gbmodule->data_list);
    225
    226	return 0;
    227}
    228
    229/*
    230 * This is the basic hook get things initialized and registered w/ gb
    231 */
    232
    233static int gb_audio_probe(struct gb_bundle *bundle,
    234			  const struct greybus_bundle_id *id)
    235{
    236	struct device *dev = &bundle->dev;
    237	struct gbaudio_module_info *gbmodule;
    238	struct greybus_descriptor_cport *cport_desc;
    239	struct gb_audio_manager_module_descriptor desc;
    240	struct gbaudio_data_connection *dai, *_dai;
    241	int ret, i;
    242	struct gb_audio_topology *topology;
    243
    244	/* There should be at least one Management and one Data cport */
    245	if (bundle->num_cports < 2)
    246		return -ENODEV;
    247
    248	/*
    249	 * There can be only one Management connection and any number of data
    250	 * connections.
    251	 */
    252	gbmodule = devm_kzalloc(dev, sizeof(*gbmodule), GFP_KERNEL);
    253	if (!gbmodule)
    254		return -ENOMEM;
    255
    256	gbmodule->num_data_connections = bundle->num_cports - 1;
    257	INIT_LIST_HEAD(&gbmodule->data_list);
    258	INIT_LIST_HEAD(&gbmodule->widget_list);
    259	INIT_LIST_HEAD(&gbmodule->ctl_list);
    260	INIT_LIST_HEAD(&gbmodule->widget_ctl_list);
    261	INIT_LIST_HEAD(&gbmodule->jack_list);
    262	gbmodule->dev = dev;
    263	snprintf(gbmodule->name, sizeof(gbmodule->name), "%s.%s", dev->driver->name,
    264		 dev_name(dev));
    265	greybus_set_drvdata(bundle, gbmodule);
    266
    267	/* Create all connections */
    268	for (i = 0; i < bundle->num_cports; i++) {
    269		cport_desc = &bundle->cport_desc[i];
    270
    271		switch (cport_desc->protocol_id) {
    272		case GREYBUS_PROTOCOL_AUDIO_MGMT:
    273			ret = gb_audio_add_mgmt_connection(gbmodule, cport_desc,
    274							   bundle);
    275			if (ret)
    276				goto destroy_connections;
    277			break;
    278		case GREYBUS_PROTOCOL_AUDIO_DATA:
    279			ret = gb_audio_add_data_connection(gbmodule, cport_desc,
    280							   bundle);
    281			if (ret)
    282				goto destroy_connections;
    283			break;
    284		default:
    285			dev_err(dev, "Unsupported protocol: 0x%02x\n",
    286				cport_desc->protocol_id);
    287			ret = -ENODEV;
    288			goto destroy_connections;
    289		}
    290	}
    291
    292	/* There must be a management cport */
    293	if (!gbmodule->mgmt_connection) {
    294		ret = -EINVAL;
    295		dev_err(dev, "Missing management connection\n");
    296		goto destroy_connections;
    297	}
    298
    299	/* Initialize management connection */
    300	ret = gb_connection_enable(gbmodule->mgmt_connection);
    301	if (ret) {
    302		dev_err(dev, "%d: Error while enabling mgmt connection\n", ret);
    303		goto destroy_connections;
    304	}
    305	gbmodule->dev_id = gbmodule->mgmt_connection->intf->interface_id;
    306
    307	/*
    308	 * FIXME: malloc for topology happens via audio_gb driver
    309	 * should be done within codec driver itself
    310	 */
    311	ret = gb_audio_gb_get_topology(gbmodule->mgmt_connection, &topology);
    312	if (ret) {
    313		dev_err(dev, "%d:Error while fetching topology\n", ret);
    314		goto disable_connection;
    315	}
    316
    317	/* process topology data */
    318	ret = gbaudio_tplg_parse_data(gbmodule, topology);
    319	if (ret) {
    320		dev_err(dev, "%d:Error while parsing topology data\n",
    321			ret);
    322		goto free_topology;
    323	}
    324	gbmodule->topology = topology;
    325
    326	/* Initialize data connections */
    327	list_for_each_entry(dai, &gbmodule->data_list, list) {
    328		ret = gb_connection_enable(dai->connection);
    329		if (ret) {
    330			dev_err(dev,
    331				"%d:Error while enabling %d:data connection\n",
    332				ret, le16_to_cpu(dai->data_cport));
    333			goto disable_data_connection;
    334		}
    335	}
    336
    337	/* register module with gbcodec */
    338	ret = gbaudio_register_module(gbmodule);
    339	if (ret)
    340		goto disable_data_connection;
    341
    342	/* inform above layer for uevent */
    343	dev_dbg(dev, "Inform set_event:%d to above layer\n", 1);
    344	/* prepare for the audio manager */
    345	strscpy(desc.name, gbmodule->name, sizeof(desc.name));
    346	desc.vid = 2; /* todo */
    347	desc.pid = 3; /* todo */
    348	desc.intf_id = gbmodule->dev_id;
    349	desc.op_devices = gbmodule->op_devices;
    350	desc.ip_devices = gbmodule->ip_devices;
    351	gbmodule->manager_id = gb_audio_manager_add(&desc);
    352
    353	dev_dbg(dev, "Add GB Audio device:%s\n", gbmodule->name);
    354
    355	gb_pm_runtime_put_autosuspend(bundle);
    356
    357	return 0;
    358
    359disable_data_connection:
    360	list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list)
    361		gb_connection_disable(dai->connection);
    362	gbaudio_tplg_release(gbmodule);
    363	gbmodule->topology = NULL;
    364
    365free_topology:
    366	kfree(topology);
    367
    368disable_connection:
    369	gb_connection_disable(gbmodule->mgmt_connection);
    370
    371destroy_connections:
    372	list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
    373		gb_connection_destroy(dai->connection);
    374		list_del(&dai->list);
    375		devm_kfree(dev, dai);
    376	}
    377
    378	if (gbmodule->mgmt_connection)
    379		gb_connection_destroy(gbmodule->mgmt_connection);
    380
    381	devm_kfree(dev, gbmodule);
    382
    383	return ret;
    384}
    385
    386static void gb_audio_disconnect(struct gb_bundle *bundle)
    387{
    388	struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
    389	struct gbaudio_data_connection *dai, *_dai;
    390
    391	gb_pm_runtime_get_sync(bundle);
    392
    393	/* cleanup module related resources first */
    394	gbaudio_unregister_module(gbmodule);
    395
    396	/* inform uevent to above layers */
    397	gb_audio_manager_remove(gbmodule->manager_id);
    398
    399	gbaudio_tplg_release(gbmodule);
    400	kfree(gbmodule->topology);
    401	gbmodule->topology = NULL;
    402	gb_connection_disable(gbmodule->mgmt_connection);
    403	list_for_each_entry_safe(dai, _dai, &gbmodule->data_list, list) {
    404		gb_connection_disable(dai->connection);
    405		gb_connection_destroy(dai->connection);
    406		list_del(&dai->list);
    407		devm_kfree(gbmodule->dev, dai);
    408	}
    409	gb_connection_destroy(gbmodule->mgmt_connection);
    410	gbmodule->mgmt_connection = NULL;
    411
    412	devm_kfree(&bundle->dev, gbmodule);
    413}
    414
    415static const struct greybus_bundle_id gb_audio_id_table[] = {
    416	{ GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_AUDIO) },
    417	{ }
    418};
    419MODULE_DEVICE_TABLE(greybus, gb_audio_id_table);
    420
    421#ifdef CONFIG_PM
    422static int gb_audio_suspend(struct device *dev)
    423{
    424	struct gb_bundle *bundle = to_gb_bundle(dev);
    425	struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
    426	struct gbaudio_data_connection *dai;
    427
    428	list_for_each_entry(dai, &gbmodule->data_list, list)
    429		gb_connection_disable(dai->connection);
    430
    431	gb_connection_disable(gbmodule->mgmt_connection);
    432
    433	return 0;
    434}
    435
    436static int gb_audio_resume(struct device *dev)
    437{
    438	struct gb_bundle *bundle = to_gb_bundle(dev);
    439	struct gbaudio_module_info *gbmodule = greybus_get_drvdata(bundle);
    440	struct gbaudio_data_connection *dai;
    441	int ret;
    442
    443	ret = gb_connection_enable(gbmodule->mgmt_connection);
    444	if (ret) {
    445		dev_err(dev, "%d:Error while enabling mgmt connection\n", ret);
    446		return ret;
    447	}
    448
    449	list_for_each_entry(dai, &gbmodule->data_list, list) {
    450		ret = gb_connection_enable(dai->connection);
    451		if (ret) {
    452			dev_err(dev,
    453				"%d:Error while enabling %d:data connection\n",
    454				ret, le16_to_cpu(dai->data_cport));
    455			return ret;
    456		}
    457	}
    458
    459	return 0;
    460}
    461#endif
    462
    463static const struct dev_pm_ops gb_audio_pm_ops = {
    464	SET_RUNTIME_PM_OPS(gb_audio_suspend, gb_audio_resume, NULL)
    465};
    466
    467static struct greybus_driver gb_audio_driver = {
    468	.name		= "gb-audio",
    469	.probe		= gb_audio_probe,
    470	.disconnect	= gb_audio_disconnect,
    471	.id_table	= gb_audio_id_table,
    472	.driver.pm	= &gb_audio_pm_ops,
    473};
    474module_greybus_driver(gb_audio_driver);
    475
    476MODULE_DESCRIPTION("Greybus Audio module driver");
    477MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@linaro.org>");
    478MODULE_LICENSE("GPL v2");
    479MODULE_ALIAS("platform:gbaudio-module");