diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h index d3024c3b38b9..599a72f33515 100644 --- a/include/sound/sdca_asoc.h +++ b/include/sound/sdca_asoc.h @@ -107,9 +107,9 @@ int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap, +int sdca_asoc_pde_poll_actual_ps(struct regmap *regmap, int function_id, int entity_id, - int from_ps, int to_ps, - const struct sdca_pde_delay *pde_delays, - int num_delays); + int from_ps, int to_ps, + const struct sdca_pde_delay *pde_delays, + int num_delays); #endif // __SDCA_ASOC_H__ diff --git a/include/sound/sdca_function.h b/include/sound/sdca_function.h index fb931ae735a2..f65a1d6784e8 100644 --- a/include/sound/sdca_function.h +++ b/include/sound/sdca_function.h @@ -1116,7 +1116,6 @@ struct sdca_entity_ge { /** * struct sdca_entity_hide - information specific to HIDE Entities - * @hid: HID device structure * @num_hidtx_ids: number of HIDTx Report ID * @num_hidrx_ids: number of HIDRx Report ID * @hidtx_ids: HIDTx Report ID @@ -1127,11 +1126,8 @@ struct sdca_entity_ge { * within this Device * @max_delay: the maximum time in microseconds allowed for the Device * to change the ownership from Device to Host - * @hid_report_desc: HID Report Descriptor for the HIDE Entity - * @hid_desc: HID descriptor for the HIDE Entity */ struct sdca_entity_hide { - struct hid_device *hid; unsigned int *hidtx_ids; unsigned int *hidrx_ids; int num_hidtx_ids; @@ -1139,8 +1135,6 @@ struct sdca_entity_hide { unsigned int af_number_list[SDCA_MAX_FUNCTION_COUNT]; unsigned int hide_reside_function_num; unsigned int max_delay; - unsigned char *hid_report_desc; - struct hid_descriptor hid_desc; }; /** @@ -1401,6 +1395,16 @@ struct sdca_fdl_data { int num_sets; }; +/** + * struct sdca_function_hid - information about a function's HID descriptors + * @report_desc: HID Report Descriptor for the HID Function + * @desc: HID descriptor for the HID Function + */ +struct sdca_function_hid { + unsigned char *report_desc; + struct hid_descriptor desc; +}; + /** * struct sdca_function_data - top-level information for one SDCA function * @desc: Pointer to short descriptor from initial parsing. @@ -1415,6 +1419,7 @@ struct sdca_fdl_data { * @reset_max_delay: Maximum Function reset delay in microseconds, before an * error should be reported. * @fdl_data: FDL data for this Function, if available. + * @hid: HID data for this Function, if available. */ struct sdca_function_data { struct sdca_function_desc *desc; @@ -1430,6 +1435,10 @@ struct sdca_function_data { unsigned int reset_max_delay; struct sdca_fdl_data fdl_data; + + union { + struct sdca_function_hid hid; + }; }; static inline u32 sdca_range(struct sdca_control_range *range, @@ -1451,8 +1460,7 @@ static inline u32 sdca_range_search(struct sdca_control_range *range, return 0; } -int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, - struct sdca_function_data *function); +int sdca_parse_function(struct device *dev, struct sdca_function_data *function); const char *sdca_find_terminal_name(enum sdca_terminal_type type); diff --git a/include/sound/sdca_hid.h b/include/sound/sdca_hid.h index 18bebbe428c9..848081df3e4e 100644 --- a/include/sound/sdca_hid.h +++ b/include/sound/sdca_hid.h @@ -16,18 +16,21 @@ struct sdca_interrupt; #if IS_ENABLED(CONFIG_SND_SOC_SDCA_HID) -int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, - struct sdca_entity *entity); +int sdca_add_hid_device(struct sdca_interrupt *interrupt); +void sdca_destroy_hid_device(struct sdca_interrupt *interrupt); int sdca_hid_process_report(struct sdca_interrupt *interrupt); #else -static inline int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, - struct sdca_entity *entity) +static inline int sdca_add_hid_device(struct sdca_interrupt *interrupt) { return 0; } +static inline void sdca_destroy_hid_device(struct sdca_interrupt *interrupt) +{ +} + static inline int sdca_hid_process_report(struct sdca_interrupt *interrupt) { return 0; diff --git a/sound/soc/codecs/rt766-sdca.c b/sound/soc/codecs/rt766-sdca.c index 49ee9cef5c54..64d763b96a06 100644 --- a/sound/soc/codecs/rt766-sdca.c +++ b/sound/soc/codecs/rt766-sdca.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,6 @@ static int rt766_sdca_btn_detect(struct sdca_interrupt *interrupt) { struct rt766_sdca_priv *rt766 = interrupt->priv; - struct sdca_entity *ent_hid = interrupt->entity; unsigned char *buf = NULL; unsigned int offset, owner, length; unsigned int det_mode, idx, val; @@ -85,8 +85,8 @@ static int rt766_sdca_btn_detect(struct sdca_interrupt *interrupt) buf[idx] = val & 0xff; } - if (ent_hid) - hid_input_report(ent_hid->hide.hid, HID_INPUT_REPORT, + if (rt766->hid) + hid_input_report(rt766->hid, HID_INPUT_REPORT, buf, length, 1); } @@ -191,6 +191,13 @@ static irqreturn_t rt766_sdca_irq_jd_handler(int irq, void *data) return IRQ_HANDLED; } +static void rt766_sdca_destroy_hid_device(struct sdca_interrupt *interrupt) +{ + struct rt766_sdca_priv *rt766 = interrupt->priv; + + hid_destroy_device(rt766->hid); +} + static int rt766_sdca_irq_ctl(struct rt766_sdca_priv *rt766, struct sdca_function_data *function, struct snd_soc_component *component, @@ -231,6 +238,15 @@ static int rt766_sdca_irq_ctl(struct rt766_sdca_priv *rt766, if (ret) return ret; + if (handler == rt766_sdca_irq_btn_handler) { + ret = sdca_add_hid_device(interrupt); + if (ret) + return ret; + + interrupt->free_priv = rt766_sdca_destroy_hid_device; + rt766->hid = interrupt->priv; + } + interrupt->priv = rt766; ret = sdca_irq_request(dev, info, irq, interrupt->name, handler, interrupt); @@ -616,7 +632,7 @@ static int rt766_sdca_pde_event(struct snd_soc_dapm_widget *w, return -EINVAL; } - ret = sdca_asoc_pde_poll_actual_ps(component->dev, rt766->regmap, + ret = sdca_asoc_pde_poll_actual_ps(rt766->regmap, func_num, pde_num, from_ps, to_ps, @@ -1185,7 +1201,7 @@ int rt766_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave } func_data_ptr->desc = &slave->sdca_data.function[i]; - ret = sdca_parse_function(dev, slave, func_data_ptr); + ret = sdca_parse_function(dev, func_data_ptr); if (ret) { devm_kfree(dev, func_data_ptr); goto _free_dai_drv_; diff --git a/sound/soc/codecs/rt766-sdca.h b/sound/soc/codecs/rt766-sdca.h index 5acdb83a42fb..de4064007eb9 100644 --- a/sound/soc/codecs/rt766-sdca.h +++ b/sound/soc/codecs/rt766-sdca.h @@ -8,6 +8,7 @@ #ifndef __RT766_H__ #define __RT766_H__ +#include #include #include #include @@ -41,6 +42,7 @@ struct rt766_sdca_priv { struct sdca_function_data *sa_func_data; struct sdca_function_data *hid_func_data; struct sdca_interrupt_info *irq_info; + struct hid_device *hid; }; /* vendor registers */ diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c index ace06f5ab58c..fdb6213d1360 100644 --- a/sound/soc/codecs/tac5xx2-sdw.c +++ b/sound/soc/codecs/tac5xx2-sdw.c @@ -800,7 +800,7 @@ static int tac_sdw_hw_params(struct snd_pcm_substream *substream, return ret; } - ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, pde_entity, + ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, pde_entity, SDCA_PDE_PS3, SDCA_PDE_PS0, NULL, 0); if (ret) dev_err(tac_dev->dev, "failed to transition func %d, pde %d from PS3 -> PS0, err=%d\n", @@ -847,7 +847,7 @@ static int tac_sdw_pcm_hw_free(struct snd_pcm_substream *substream, return ret; } - ret = sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, function_id, + ret = sdca_asoc_pde_poll_actual_ps(tac_dev->regmap, function_id, pde_entity, SDCA_PDE_PS0, SDCA_PDE_PS3, NULL, 0); if (ret) @@ -1940,7 +1940,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral, "failed to allocate %s function data", func_name); function_data->desc = &peripheral->sdca_data.function[i]; - ret = sdca_parse_function(dev, peripheral, function_data); + ret = sdca_parse_function(dev, function_data); if (!ret) *func_ptr = function_data; else diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c index 34f17e063fa3..94f11e3b0c20 100644 --- a/sound/soc/codecs/tas2783-sdw.c +++ b/sound/soc/codecs/tas2783-sdw.c @@ -1348,7 +1348,7 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral, function_data->desc = &peripheral->sdca_data.function[i]; /* Parse the function */ - ret = sdca_parse_function(dev, peripheral, function_data); + ret = sdca_parse_function(dev, function_data); if (!ret) tas_dev->sa_func_data = function_data; else diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 9a6c0036b7be..ce2e7c270765 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -364,7 +364,6 @@ static int entity_parse_ot(struct device *dev, /** * sdca_asoc_pde_poll_actual_ps - Verify PDE power state reached target state - * @dev: Pointer to the device for error logging. * @regmap: Register map for reading ACTUAL_PS register. * @function_id: SDCA function identifier. * @entity_id: SDCA entity identifier for the power domain. @@ -389,11 +388,11 @@ static int entity_parse_ot(struct device *dev, * polling times out before reaching the target state, or a negative error code if * a register read fails. */ -int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap, +int sdca_asoc_pde_poll_actual_ps(struct regmap *regmap, int function_id, int entity_id, - int from_ps, int to_ps, - const struct sdca_pde_delay *pde_delays, - int num_delays) + int from_ps, int to_ps, + const struct sdca_pde_delay *pde_delays, + int num_delays) { static const int polls = 100; static const int default_poll_us = 1000; @@ -451,14 +450,14 @@ static int entity_pde_event(struct snd_soc_dapm_widget *widget, return 0; } - ret = sdca_asoc_pde_poll_actual_ps(component->dev, component->regmap, + ret = sdca_asoc_pde_poll_actual_ps(component->regmap, SDW_SDCA_CTL_FUNC(widget->reg), SDW_SDCA_CTL_ENT(widget->reg), from, to, entity->pde.max_delay, entity->pde.num_max_delay); if (ret) - dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n", + dev_err(component->dev, "%s: pde transition %x -> %x failed: %d\n", entity->label, from, to, ret); return ret; diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c index 2fb2b043c979..cc7045dc26e6 100644 --- a/sound/soc/sdca/sdca_class_function.c +++ b/sound/soc/sdca/sdca_class_function.c @@ -329,7 +329,7 @@ static int class_function_probe(struct auxiliary_device *auxdev, drv->core = core; drv->function = &sdev->function; - ret = sdca_parse_function(dev, core->sdw, drv->function); + ret = sdca_parse_function(dev, drv->function); if (ret) return ret; diff --git a/sound/soc/sdca/sdca_function_device.c b/sound/soc/sdca/sdca_function_device.c index b5ca98283a88..54604872ae0d 100644 --- a/sound/soc/sdca/sdca_function_device.c +++ b/sound/soc/sdca/sdca_function_device.c @@ -32,7 +32,8 @@ static void sdca_dev_release(struct device *dev) /* alloc, init and add link devices */ static struct sdca_dev *sdca_dev_register(struct device *parent, - struct sdca_function_desc *function_desc) + struct sdca_function_desc *function_desc, + struct acpi_table_swft *swft) { struct sdca_dev *sdev; struct auxiliary_device *auxdev; @@ -50,6 +51,7 @@ static struct sdca_dev *sdca_dev_register(struct device *parent, auxdev->dev.release = sdca_dev_release; sdev->function.desc = function_desc; + sdev->function.fdl_data.swft = swft; rc = ida_alloc(&sdca_function_ida, GFP_KERNEL); if (rc < 0) { @@ -99,7 +101,8 @@ int sdca_dev_register_functions(struct sdw_slave *slave) struct sdca_dev *func_dev; func_dev = sdca_dev_register(&slave->dev, - &sdca_data->function[i]); + &sdca_data->function[i], + sdca_data->swft); if (IS_ERR(func_dev)) { ret = PTR_ERR(func_dev); /* diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index cdf1e68d60ac..e01d91eb3cc8 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include /* * Should be long enough to encompass all the MIPI DisCo properties. @@ -1365,90 +1365,76 @@ static int find_sdca_entity_ge(struct device *dev, return -EINVAL; } -static int -find_sdca_entity_hide(struct device *dev, struct sdw_slave *sdw, - struct fwnode_handle *function_node, - struct fwnode_handle *entity_node, struct sdca_entity *entity) +static int find_sdca_entity_hide(struct device *dev, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) { struct sdca_entity_hide *hide = &entity->hide; - unsigned int delay, *af_list = hide->af_number_list; - int nval, ret; - unsigned char *report_desc = NULL; + int num_reports, ret; + unsigned int delay; ret = fwnode_property_read_u32(entity_node, - "mipi-sdca-RxUMP-ownership-transition-max-delay", &delay); + "mipi-sdca-RxUMP-ownership-transition-max-delay", + &delay); if (!ret) hide->max_delay = delay; - nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDTx-supported-report-ids"); - if (nval > 0) { - hide->num_hidtx_ids = nval; + num_reports = fwnode_property_count_u32(entity_node, + "mipi-sdca-HIDTx-supported-report-ids"); + if (num_reports < 0 && num_reports != -EINVAL) { + dev_err(dev, "%pfwP: failed to read hid tx ids: %d\n", + entity_node, num_reports); + return num_reports; + } else if (num_reports > 0) { + hide->num_hidtx_ids = num_reports; hide->hidtx_ids = devm_kcalloc(dev, hide->num_hidtx_ids, sizeof(*hide->hidtx_ids), GFP_KERNEL); if (!hide->hidtx_ids) return -ENOMEM; - ret = fwnode_property_read_u32_array(entity_node, - "mipi-sdca-HIDTx-supported-report-ids", - hide->hidtx_ids, - hide->num_hidtx_ids); - if (ret < 0) - return ret; + fwnode_property_read_u32_array(entity_node, + "mipi-sdca-HIDTx-supported-report-ids", + hide->hidtx_ids, hide->num_hidtx_ids); } - nval = fwnode_property_count_u32(entity_node, "mipi-sdca-HIDRx-supported-report-ids"); - if (nval > 0) { - hide->num_hidrx_ids = nval; + num_reports = fwnode_property_count_u32(entity_node, + "mipi-sdca-HIDRx-supported-report-ids"); + if (num_reports < 0 && num_reports != -EINVAL) { + dev_err(dev, "%pfwP: failed to read hid rx ids: %d\n", + entity_node, num_reports); + return num_reports; + } else if (num_reports > 0) { + hide->num_hidrx_ids = num_reports; hide->hidrx_ids = devm_kcalloc(dev, hide->num_hidrx_ids, sizeof(*hide->hidrx_ids), GFP_KERNEL); if (!hide->hidrx_ids) return -ENOMEM; - ret = fwnode_property_read_u32_array(entity_node, - "mipi-sdca-HIDRx-supported-report-ids", - hide->hidrx_ids, - hide->num_hidrx_ids); - if (ret < 0) - return ret; + fwnode_property_read_u32_array(entity_node, + "mipi-sdca-HIDRx-supported-report-ids", + hide->hidrx_ids, hide->num_hidrx_ids); } - nval = fwnode_property_count_u32(entity_node, "mipi-sdca-hide-related-audio-function-list"); - if (nval <= 0) { + /* + * FIXME: This should probably link to the actual sdca_function_data pointer, + * but updating to do so should probably wait until we have a user. + */ + num_reports = fwnode_property_count_u32(entity_node, + "mipi-sdca-hide-related-audio-function-list"); + if (num_reports <= 0) { dev_err(dev, "%pfwP: audio function numbers list missing: %d\n", - entity_node, nval); + entity_node, num_reports); return -EINVAL; - } else if (nval > SDCA_MAX_FUNCTION_COUNT) { - dev_err(dev, "%pfwP: maximum number of audio function exceeded\n", entity_node); + } else if (num_reports > ARRAY_SIZE(hide->af_number_list)) { + dev_err(dev, "%pfwP: maximum number of audio function exceeded\n", + entity_node); return -EINVAL; } - hide->hide_reside_function_num = nval; + hide->hide_reside_function_num = num_reports; fwnode_property_read_u32_array(entity_node, - "mipi-sdca-hide-related-audio-function-list", af_list, nval); - - nval = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor"); - if (nval) - fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor", - (u8 *)&hide->hid_desc, nval); - - if (hide->hid_desc.bNumDescriptors) { - nval = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor"); - if (nval) { - report_desc = devm_kzalloc(dev, nval, GFP_KERNEL); - if (!report_desc) - return -ENOMEM; - hide->hid_report_desc = report_desc; - fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor", - report_desc, nval); - - /* add HID device */ - ret = sdca_add_hid_device(dev, sdw, entity); - if (ret) { - dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret); - return ret; - } - } - } + "mipi-sdca-hide-related-audio-function-list", + hide->af_number_list, num_reports); return 0; } @@ -1475,8 +1461,7 @@ static int find_sdca_entity_xu(struct device *dev, return 0; } -static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw, - struct sdca_function_data *function, +static int find_sdca_entity(struct device *dev, struct sdca_function_data *function, struct fwnode_handle *function_node, struct fwnode_handle *entity_node, struct sdca_entity *entity) @@ -1528,8 +1513,7 @@ static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw, ret = find_sdca_entity_ge(dev, entity_node, entity); break; case SDCA_ENTITY_TYPE_HIDE: - ret = find_sdca_entity_hide(dev, sdw, function_node, - entity_node, entity); + ret = find_sdca_entity_hide(dev, entity_node, entity); break; default: break; @@ -1544,8 +1528,7 @@ static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw, return 0; } -static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, - struct fwnode_handle *function_node, +static int find_sdca_entities(struct device *dev, struct fwnode_handle *function_node, struct sdca_function_data *function) { struct sdca_entity *entities; @@ -1596,7 +1579,7 @@ static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, return -EINVAL; } - ret = find_sdca_entity(dev, sdw, function, function_node, + ret = find_sdca_entity(dev, function, function_node, entity_node, &entities[i]); fwnode_handle_put(entity_node); if (ret) @@ -2089,8 +2072,7 @@ static int find_sdca_clusters(struct device *dev, return 0; } -static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, - struct fwnode_handle *function_node, +static int find_sdca_filesets(struct device *dev, struct fwnode_handle *function_node, struct sdca_function_data *function) { static const int mult_fileset = 3; @@ -2172,23 +2154,65 @@ static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, set->files = files; } - function->fdl_data.swft = sdw->sdca_data.swft; function->fdl_data.num_sets = num_sets; function->fdl_data.sets = sets; return 0; } +static int find_sdca_hid(struct device *dev, struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + int num_desc; + + num_desc = fwnode_property_count_u8(function_node, "mipi-sdca-hid-descriptor"); + if (!num_desc) { + return 0; + } else if (num_desc < 0) { + dev_err(dev, "%pfwP: failed to read hid descriptor: %d\n", + function_node, num_desc); + return num_desc; + } else if (num_desc > sizeof(function->hid.desc)) { + dev_err(dev, "%pfwP: hid descriptor too large: %d\n", + function_node, num_desc); + return -EINVAL; + } + + fwnode_property_read_u8_array(function_node, "mipi-sdca-hid-descriptor", + (u8 *)&function->hid.desc, num_desc); + + if (!function->hid.desc.bNumDescriptors) + return 0; + + num_desc = fwnode_property_count_u8(function_node, "mipi-sdca-report-descriptor"); + if (num_desc <= 0) { + dev_err(dev, "%pfwP: failed to read report descriptor: %d\n", + function_node, num_desc); + + if (!num_desc) + return -EINVAL; + + return num_desc; + } + + function->hid.report_desc = devm_kzalloc(dev, num_desc, GFP_KERNEL); + if (!function->hid.report_desc) + return -ENOMEM; + + fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor", + function->hid.report_desc, num_desc); + + return 0; +} + /** * sdca_parse_function - parse ACPI DisCo for a Function * @dev: Pointer to device against which function data will be allocated. - * @sdw: SoundWire slave device to be processed. * @function: Pointer to the Function information, to be populated. * * Return: Returns 0 for success. */ -int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, - struct sdca_function_data *function) +int sdca_parse_function(struct device *dev, struct sdca_function_data *function) { struct fwnode_handle *node = function->desc->node; u32 tmp; @@ -2214,7 +2238,7 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, if (ret) return ret; - ret = find_sdca_entities(dev, sdw, node, function); + ret = find_sdca_entities(dev, node, function); if (ret) return ret; @@ -2226,10 +2250,20 @@ int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, if (ret < 0) return ret; - ret = find_sdca_filesets(dev, sdw, node, function); + ret = find_sdca_filesets(dev, node, function); if (ret) return ret; + switch (function->desc->type) { + case SDCA_FUNCTION_TYPE_HID: + ret = find_sdca_hid(dev, node, function); + if (ret) + return ret; + break; + default: + break; + } + return 0; } EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c index abbd56a3d297..bee1b83c05f2 100644 --- a/sound/soc/sdca/sdca_hid.c +++ b/sound/soc/sdca/sdca_hid.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -23,18 +24,18 @@ static int sdwhid_parse(struct hid_device *hid) { - struct sdca_entity *entity = hid->driver_data; + struct sdca_function_data *function = hid->driver_data; unsigned int rsize; int ret; - rsize = le16_to_cpu(entity->hide.hid_desc.rpt_desc.wDescriptorLength); + rsize = le16_to_cpu(function->hid.desc.rpt_desc.wDescriptorLength); if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize); return -EINVAL; } - ret = hid_parse_report(hid, entity->hide.hid_report_desc, rsize); + ret = hid_parse_report(hid, function->hid.report_desc, rsize); if (!ret) return 0; @@ -85,10 +86,16 @@ static const struct hid_ll_driver sdw_hid_driver = { .raw_request = sdwhid_raw_request, }; -int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, - struct sdca_entity *entity) +/** + * sdca_add_hid_device - create a new SDCA HID device + * @interrupt: Pointer to the SDCA interrupt information structure. + * + * Return: Zero on success, and a negative error code on failure. + */ +int sdca_add_hid_device(struct sdca_interrupt *interrupt) { - struct sdw_bus *bus = sdw->bus; + struct device *dev = interrupt->dev; + struct sdca_function_data *function = interrupt->function; struct hid_device *hid; int ret; @@ -100,16 +107,13 @@ int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, hid->dev.parent = dev; hid->bus = BUS_SDW; - hid->version = le16_to_cpu(entity->hide.hid_desc.bcdHID); + hid->version = le16_to_cpu(function->hid.desc.bcdHID); - snprintf(hid->name, sizeof(hid->name), - "HID sdw:%01x:%01x:%04x:%04x:%02x", - bus->controller_id, bus->link_id, sdw->id.mfg_id, - sdw->id.part_id, sdw->id.class_id); + strscpy(hid->phys, dev_name(dev)); + snprintf(hid->name, sizeof(hid->name), "SDCA %s:%02x", + function->desc->name, function->desc->adr); - snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name); - - hid->driver_data = entity; + hid->driver_data = function; ret = hid_add_device(hid); if (ret && ret != -ENODEV) { @@ -118,12 +122,24 @@ int sdca_add_hid_device(struct device *dev, struct sdw_slave *sdw, return ret; } - entity->hide.hid = hid; + interrupt->priv = hid; return 0; } EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA"); +/** + * sdca_destroy_hid_device - destroy the HID device + * @interrupt: Pointer to the SDCA interrupt information structure. + */ +void sdca_destroy_hid_device(struct sdca_interrupt *interrupt) +{ + struct hid_device *hid = interrupt->priv; + + hid_destroy_device(hid); +} +EXPORT_SYMBOL_NS(sdca_destroy_hid_device, "SND_SOC_SDCA"); + /** * sdca_hid_process_report - read a HID event from the device and report * @interrupt: Pointer to the SDCA interrupt information structure. @@ -133,7 +149,7 @@ EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA"); int sdca_hid_process_report(struct sdca_interrupt *interrupt) { struct device *dev = interrupt->dev; - struct hid_device *hid = interrupt->entity->hide.hid; + struct hid_device *hid = interrupt->priv; void *val __free(kfree) = NULL; int len, ret; diff --git a/sound/soc/sdca/sdca_interrupts.c b/sound/soc/sdca/sdca_interrupts.c index 42fbd3af8a75..7aebc721a847 100644 --- a/sound/soc/sdca/sdca_interrupts.c +++ b/sound/soc/sdca/sdca_interrupts.c @@ -487,6 +487,12 @@ int sdca_irq_populate_early(struct device *dev, struct regmap *regmap, } break; case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER): + interrupt->free_priv = sdca_destroy_hid_device; + + ret = sdca_add_hid_device(interrupt); + if (ret) + return ret; + interrupt->handler = hid_handler; break; default: