diff --git a/audioreach-driver/ar_kcompat.h b/audioreach-driver/ar_kcompat.h new file mode 100644 index 0000000..d4c67a4 --- /dev/null +++ b/audioreach-driver/ar_kcompat.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +#ifndef __AR_KCOMPAT_H__ +#define __AR_KCOMPAT_H__ + +#include +#include + +/* + * Detect whether the kernel expects GPR callback with: + * - <= 6.19 : struct gpr_resp_pkt * (non-const) + * - >= 7.0 : const struct gpr_resp_pkt * (const) + * + * Allow a build-time override (vendors may backport). + * + * Use: + * -D HAVE_GPR_CB_CONST -> force >=7.0 behavior (const) + * -D HAVE_GPR_CB_MUTABLE -> force <=6.19 behavior (non-const) + * + * If neither is defined, pick based on LINUX_VERSION_CODE. + */ +#if defined(HAVE_GPR_CB_CONST) && defined(HAVE_GPR_CB_MUTABLE) +# error "Define at most one of HAVE_GPR_CB_CONST or HAVE_GPR_CB_MUTABLE" +#endif + +#if defined(HAVE_GPR_CB_CONST) +# define AR_HAVE_GPR_CB_CONST 1 +#elif defined(HAVE_GPR_CB_MUTABLE) +# define AR_HAVE_GPR_CB_CONST 0 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(7, 0, 0) +# define AR_HAVE_GPR_CB_CONST 1 +#else +# define AR_HAVE_GPR_CB_CONST 0 +#endif + +/* + * Thunk generator for GPR callbacks. + * + * The driver provides a version‑independent core: + * int name_core(const struct gpr_resp_pkt *data, void *priv, int op); + * + * This macro emits an ABI‑appropriate wrapper ('name') and forwards the + * packet to the const‑correct core. Legacy kernels that pass a mutable + * gpr_resp_pkt pointer are handled by accepting the mutable form and + * forwarding it as const. The packet is not modified. + * + * For kernels that require in‑place packet modification, a local copy must + * be created before invoking the core. Current code paths do not modify + * the packet. + */ + +#define AR_GPR_CB_WRAPPER(name) \ + static int name##_core(const struct gpr_resp_pkt *data, \ + void *priv, int op); \ + __AR_GPR_CB_DECL(name) \ + { \ + /* Non‑const legacy pointer; handled as read‑only. */ \ + return name##_core((const struct gpr_resp_pkt *)data, priv, op); \ + } + +/* Emit the kernel-facing callback prototype */ +#if AR_HAVE_GPR_CB_CONST +# define __AR_GPR_CB_DECL(name) \ + static int name(const struct gpr_resp_pkt *data, void *priv, int op) +#else +# define __AR_GPR_CB_DECL(name) \ + static int name(struct gpr_resp_pkt *data, void *priv, int op) +#endif + +#endif /* __AR_KCOMPAT_H__ */ diff --git a/audioreach-driver/q6apm_audio_pkt.c b/audioreach-driver/q6apm_audio_pkt.c index d611040..ce5097e 100644 --- a/audioreach-driver/q6apm_audio_pkt.c +++ b/audioreach-driver/q6apm_audio_pkt.c @@ -29,6 +29,7 @@ #include "audioreach.h" #include "q6apm.h" #include "q6prm_audioreach.h" +#include "ar_kcompat.h" #define APM_CMD_SHARED_MEM_MAP_REGIONS 0x0100100C #define APM_MEMORY_MAP_BIT_MASK_IS_OFFSET_MODE 0x00000004UL @@ -590,7 +591,14 @@ static int q6apm_audio_pkt_probe(gpr_device_t *adev) return ret; } -static int q6apm_audio_pkt_callback(const struct gpr_resp_pkt *data, void *priv, int op) +/* + * Generate the kernel-facing wrapper with the correct signature + * for <=6.19 (non-const) and >=7.0 (const). The wrapper calls + * q6apm_audio_pkt_callback_core() which always uses 'const'. + */ +AR_GPR_CB_WRAPPER(q6apm_audio_pkt_callback) + +static int q6apm_audio_pkt_callback_core(const struct gpr_resp_pkt *data, void *priv, int op) { gpr_device_t *gdev = priv; struct q6apm_audio_pkt *apm = dev_get_drvdata(&gdev->dev); @@ -638,8 +646,8 @@ static int q6apm_audio_pkt_callback(const struct gpr_resp_pkt *data, void *priv, skb = alloc_skb(pkt_size, GFP_ATOMIC); if (!skb) { - kfree(pkt); - return -ENOMEM; + kfree(pkt); + return -ENOMEM; } skb_put_data(skb, (void *)pkt, pkt_size); diff --git a/audioreach-driver/q6prm_audioreach.c b/audioreach-driver/q6prm_audioreach.c index 9398d64..588c880 100644 --- a/audioreach-driver/q6prm_audioreach.c +++ b/audioreach-driver/q6prm_audioreach.c @@ -17,6 +17,7 @@ #include "q6prm.h" #include "audioreach.h" #include "q6prm_audioreach.h" +#include "ar_kcompat.h" struct q6prm { struct device *dev; @@ -277,7 +278,15 @@ int q6prm_audioreach_set_lpass_clock(struct device *dev, int clk_id, int clk_att return q6prm_audioreach_release_lpass_clock(dev, clk_id, clk_attr, clk_root, freq); } -static int prm_audioreach_callback(const struct gpr_resp_pkt *data, void *priv, int op) +/* + * Generate the kernel-facing wrapper with the correct signature + * for <=6.19 (non-const) and >=7.0 (const). The wrapper calls + * prm_audioreach_callback_core() which always uses 'const'. + */ +AR_GPR_CB_WRAPPER(prm_audioreach_callback) + +static int prm_audioreach_callback_core(const struct gpr_resp_pkt *data, + void *priv, int op) { gpr_device_t *gdev = priv; struct q6prm *prm = dev_get_drvdata(&gdev->dev);