Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions audioreach-driver/ar_kcompat.h
Original file line number Diff line number Diff line change
@@ -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 <linux/version.h>
#include <linux/types.h>

/*
* 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__ */
14 changes: 11 additions & 3 deletions audioreach-driver/q6apm_audio_pkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
11 changes: 10 additions & 1 deletion audioreach-driver/q6prm_audioreach.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "q6prm.h"
#include "audioreach.h"
#include "q6prm_audioreach.h"
#include "ar_kcompat.h"

struct q6prm {
struct device *dev;
Expand Down Expand Up @@ -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);
Expand Down
Loading