diff options
Diffstat (limited to 'sound/soc/sdca/sdca_hid.c')
| -rw-r--r-- | sound/soc/sdca/sdca_hid.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c index 967f7ec6fb79..abbd56a3d297 100644 --- a/sound/soc/sdca/sdca_hid.c +++ b/sound/soc/sdca/sdca_hid.c @@ -10,6 +10,7 @@ #include <linux/cleanup.h> #include <linux/device.h> #include <linux/dev_printk.h> +#include <linux/hid.h> #include <linux/module.h> #include <linux/property.h> #include <linux/soundwire/sdw.h> @@ -17,6 +18,8 @@ #include <sound/sdca.h> #include <sound/sdca_function.h> #include <sound/sdca_hid.h> +#include <sound/sdca_interrupts.h> +#include <sound/sdca_ump.h> static int sdwhid_parse(struct hid_device *hid) { @@ -82,15 +85,13 @@ static const struct hid_ll_driver sdw_hid_driver = { .raw_request = sdwhid_raw_request, }; -int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity) +int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, + struct sdca_entity *entity) { - struct sdw_bus *bus; + struct sdw_bus *bus = sdw->bus; struct hid_device *hid; - struct sdw_slave *slave = dev_to_sdw_dev(dev); int ret; - bus = slave->bus; - hid = hid_allocate_device(); if (IS_ERR(hid)) return PTR_ERR(hid); @@ -103,8 +104,8 @@ int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity) snprintf(hid->name, sizeof(hid->name), "HID sdw:%01x:%01x:%04x:%04x:%02x", - bus->controller_id, bus->link_id, slave->id.mfg_id, - slave->id.part_id, slave->id.class_id); + bus->controller_id, bus->link_id, sdw->id.mfg_id, + sdw->id.part_id, sdw->id.class_id); snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name); @@ -123,5 +124,45 @@ int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity) } EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("SDCA HID library"); +/** + * sdca_hid_process_report - read a HID event from the device and report + * @interrupt: Pointer to the SDCA interrupt information structure. + * + * Return: Zero on success, and a negative error code on failure. + */ +int sdca_hid_process_report(struct sdca_interrupt *interrupt) +{ + struct device *dev = interrupt->dev; + struct hid_device *hid = interrupt->entity->hide.hid; + void *val __free(kfree) = NULL; + int len, ret; + + ret = sdca_ump_get_owner_host(dev, interrupt->function_regmap, + interrupt->function, interrupt->entity, + interrupt->control); + if (ret) + return ret; + + len = sdca_ump_read_message(dev, interrupt->device_regmap, + interrupt->function_regmap, + interrupt->function, interrupt->entity, + SDCA_CTL_HIDE_HIDTX_MESSAGEOFFSET, + SDCA_CTL_HIDE_HIDTX_MESSAGELENGTH, &val); + if (len < 0) + return len; + + ret = sdca_ump_set_owner_device(dev, interrupt->function_regmap, + interrupt->function, interrupt->entity, + interrupt->control); + if (ret) + return ret; + + ret = hid_input_report(hid, HID_INPUT_REPORT, val, len, true); + if (ret < 0) { + dev_err(dev, "failed to report hid event: %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_NS(sdca_hid_process_report, "SND_SOC_SDCA"); |
