aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--alsa-pcm.c69
-rwxr-xr-xalsa-pcm.h28
-rwxr-xr-xalsa.c175
-rwxr-xr-xalsa.h98
-rw-r--r--core.c118
-rw-r--r--core.h22
-rw-r--r--utils.h49
8 files changed, 210 insertions, 350 deletions
diff --git a/Makefile b/Makefile
index dfdc715..af92bc5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_AVIRT) += avirt_core.o
avirt_core-y := core.o
-avirt_core-y += alsa.o
avirt_core-y += alsa-pcm.o
ifeq ($(CONFIG_AVIRT_BUILDLOCAL),)
diff --git a/alsa-pcm.c b/alsa-pcm.c
index ac9175b..d65809c 100644
--- a/alsa-pcm.c
+++ b/alsa-pcm.c
@@ -2,12 +2,13 @@
/*
* ALSA Virtual Soundcard
*
- * alsa-pcm.c - ALSA PCM implementation
+ * alsa-pcm.c - AVIRT ALSA PCM interface
*
* Copyright (C) 2010-2018 Fiberdyne Systems Pty Ltd
*/
-#include "alsa.h"
+#include "alsa-pcm.h"
+#include "utils.h"
#define DO_AUDIOPATH_CB(ap, callback, substream, ...) \
do { \
@@ -17,6 +18,36 @@
} \
} while (0)
+/**
+ * pcm_buff_complete_cb - PCM buffer complete callback
+ * @substreamid: pointer to ALSA PCM substream
+ * @return 0 on success or error code otherwise
+ *
+ * This should be called from a child Audio Path once it has finished processing
+ * the pcm buffer
+ */
+int pcm_buff_complete_cb(struct snd_pcm_substream *substream)
+{
+ // Notify ALSA middle layer of the elapsed period boundary
+ snd_pcm_period_elapsed(substream);
+
+ return 0;
+}
+
+static struct avirt_stream_group *avirt_stream_get_group(int direction)
+{
+ switch (direction) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ return &coreinfo.playback;
+ case SNDRV_PCM_STREAM_CAPTURE:
+ return &coreinfo.capture;
+ default:
+ pr_err("[%s] Direction must be SNDRV_PCM_STREAM_XXX!",
+ __func__);
+ return NULL;
+ }
+}
+
/*******************************************************************************
* ALSA PCM Callbacks
******************************************************************************/
@@ -31,13 +62,12 @@
*/
static int pcm_open(struct snd_pcm_substream *substream)
{
- struct avirt_alsa_devconfig *config;
struct avirt_audiopath *audiopath;
- struct avirt_alsa_group *group;
+ struct avirt_stream_group *group;
struct snd_pcm_hardware *hw;
- unsigned int bytes_per_sample = 0, blocksize = 0;
+ unsigned int bytes_per_sample = 0, blocksize = 0, chans = 0;
- char *uid = "ap_dummy"; // TD MF: Make this dynamic!
+ char *uid = "ap_fddsp"; // TD MF: Make this dynamic!
audiopath = avirt_get_audiopath(uid);
CHK_NULL_V(audiopath, "Cannot find Audio Path uid: '%s'!", uid);
substream->private_data = audiopath;
@@ -58,7 +88,7 @@ static int pcm_open(struct snd_pcm_substream *substream)
}
// Get device group (playback/capture)
- group = avirt_alsa_get_group(substream->stream);
+ group = avirt_stream_get_group(substream->stream);
CHK_NULL(group);
// Check if substream id is valid
@@ -70,13 +100,13 @@ static int pcm_open(struct snd_pcm_substream *substream)
}
// Setup remaining hw properties
- config = &group->config[substream->pcm->device];
- hw->channels_min = config->channels;
- hw->channels_max = config->channels;
- hw->buffer_bytes_max = blocksize * hw->periods_max * bytes_per_sample *
- config->channels;
- hw->period_bytes_min = blocksize * bytes_per_sample * config->channels;
- hw->period_bytes_max = blocksize * bytes_per_sample * config->channels;
+ chans = group->streams[substream->pcm->device].channels;
+ hw->channels_min = chans;
+ hw->channels_max = chans;
+ hw->buffer_bytes_max =
+ blocksize * hw->periods_max * bytes_per_sample * chans;
+ hw->period_bytes_min = blocksize * bytes_per_sample * chans;
+ hw->period_bytes_max = blocksize * bytes_per_sample * chans;
// Do additional Audio Path 'open' callback
DO_AUDIOPATH_CB(audiopath, open, substream);
@@ -118,12 +148,12 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
int channels, err;
size_t bufsz;
struct avirt_audiopath *audiopath;
- struct avirt_alsa_group *group;
+ struct avirt_stream_group *group;
- group = avirt_alsa_get_group(substream->stream);
+ group = avirt_stream_get_group(substream->stream);
CHK_NULL(group);
- channels = group->config[substream->pcm->device].channels;
+ channels = group->streams[substream->pcm->device].channels;
if ((params_channels(hw_params) > channels) ||
(params_channels(hw_params) < channels)) {
@@ -252,11 +282,6 @@ static int pcm_get_time_info(
struct snd_pcm_audio_tstamp_config *audio_tstamp_config,
struct snd_pcm_audio_tstamp_report *audio_tstamp_report)
{
- struct avirt_alsa_group *group;
-
- group = avirt_alsa_get_group(substream->stream);
- CHK_NULL(group);
-
DO_AUDIOPATH_CB(((struct avirt_audiopath *)substream->private_data),
get_time_info, substream, system_ts, audio_ts,
audio_tstamp_config, audio_tstamp_report);
diff --git a/alsa-pcm.h b/alsa-pcm.h
new file mode 100755
index 0000000..c45e2a7
--- /dev/null
+++ b/alsa-pcm.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA Virtual Soundcard
+ *
+ * alsa-pcm.h - AVIRT ALSA PCM interface
+ *
+ * Copyright (C) 2010-2018 Fiberdyne Systems Pty Ltd
+ */
+
+#ifndef __AVIRT_ALSA_PCM_H__
+#define __AVIRT_ALSA_PCM_H__
+
+#include "core.h"
+
+extern struct avirt_coreinfo coreinfo;
+extern struct snd_pcm_ops pcm_ops;
+
+/**
+ * pcm_buff_complete_cb - PCM buffer complete callback
+ * @substream: pointer to ALSA PCM substream
+ * @return 0 on success or error code otherwise
+ *
+ * This should be called from a child Audio Path once it has finished processing
+ * the PCM buffer
+ */
+int pcm_buff_complete_cb(struct snd_pcm_substream *substream);
+
+#endif // __AVIRT_ALSA_PCM_H__
diff --git a/alsa.c b/alsa.c
deleted file mode 100755
index fdbe6b0..0000000
--- a/alsa.c
+++ /dev/null
@@ -1,175 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ALSA Virtual Soundcard
- *
- * alsa.c - ALSA PCM driver for virtual ALSA card
- *
- * Copyright (C) 2010-2018 Fiberdyne Systems Pty Ltd
- */
-
-#include <sound/core.h>
-#include <sound/initval.h>
-
-#include "alsa.h"
-
-static struct snd_card *card;
-
-/**
- * pcm_constructor - Constructs the ALSA PCM middle devices for this driver
- * @card: The snd_card struct to construct the devices for
- * @return 0 on success or error code otherwise
- */
-static int pcm_constructor(struct snd_card *card)
-{
- struct snd_pcm *pcm;
- int i;
-
- // Allocate Playback PCM instances
- for (i = 0; i < coreinfo.playback.devices; i++) {
- CHK_ERR(snd_pcm_new(card,
- coreinfo.playback.config[i].devicename, i,
- 1, 0, &pcm));
-
- /** Register driver callbacks */
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
-
- pcm->info_flags = 0;
- strcpy(pcm->name, coreinfo.playback.config[i].devicename);
- }
-
- // Allocate Capture PCM instances
- for (i = 0; i < coreinfo.capture.devices; i++) {
- CHK_ERR(snd_pcm_new(card, coreinfo.capture.config[i].devicename,
- i, 0, 1, &pcm));
-
- /** Register driver callbacks */
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
-
- pcm->info_flags = 0;
- strcpy(pcm->name, coreinfo.capture.config[i].devicename);
- }
-
- return 0;
-}
-
-/**
- * alloc_dev_config - Allocates memory for ALSA device configuration
- * @return: 0 on success or error code otherwise
- */
-static int alloc_dev_config(struct avirt_alsa_devconfig **devconfig,
- struct avirt_alsa_devconfig *userconfig,
- unsigned int numdevices)
-{
- if (numdevices == 0)
- return 0;
-
- *devconfig = kzalloc(sizeof(**devconfig) * numdevices, GFP_KERNEL);
- if (!(*devconfig))
- return -ENOMEM;
-
- memcpy(*devconfig, userconfig,
- sizeof(struct avirt_alsa_devconfig) * numdevices);
-
- return 0;
-}
-
-struct avirt_alsa_group *avirt_alsa_get_group(int direction)
-{
- switch (direction) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- return &coreinfo.playback;
- case SNDRV_PCM_STREAM_CAPTURE:
- return &coreinfo.capture;
- default:
- pr_err("[%s] Direction must be SNDRV_PCM_STREAM_XXX!",
- __func__);
- return NULL;
- }
-}
-
-/**
- * avirt_alsa_configure_pcm- Configure the PCM device
- * @config: Device configuration structure array
- * @direction: Direction of PCM (SNDRV_PCM_STREAM_XXX)
- * @numdevices: Number of devices (array length)
- * @return: 0 on success or error code otherwise
- */
-int avirt_alsa_configure_pcm(struct avirt_alsa_devconfig *config, int direction,
- unsigned int numdevices)
-{
- struct avirt_alsa_group *group;
-
- group = avirt_alsa_get_group(direction);
- CHK_NULL(group);
-
- CHK_ERR(alloc_dev_config(&group->config, config, numdevices));
-
- group->devices = numdevices;
-
- return 0;
-}
-
-/**
- * avirt_alsa_register - Registers the ALSA driver
- * @devptr: Platform driver device
- * @return: 0 on success or error code otherwise
- */
-int avirt_alsa_register(struct platform_device *devptr)
-{
- static struct snd_device_ops device_ops;
-
- // Create the card instance
- CHK_ERR_V(snd_card_new(&devptr->dev, SNDRV_DEFAULT_IDX1, "avirt",
- THIS_MODULE, 0, &card),
- "Failed to create sound card");
-
- strcpy(card->driver, "avirt-alsa-device");
- strcpy(card->shortname, "avirt");
- strcpy(card->longname, "A virtual sound card driver for ALSA");
-
- // Create new sound device
- CHK_ERR_V((snd_device_new(card, SNDRV_DEV_LOWLEVEL, &coreinfo,
- &device_ops)),
- "Failed to create sound device");
-
- CHK_ERR((pcm_constructor(card)));
-
- /** Register with the ALSA framework */
- CHK_ERR_V(snd_card_register(card), "Device registration failed");
-
- return 0;
-}
-
-/**
- * avirt_alsa_deregister - Deregisters the ALSA driver
- * @devptr: Platform driver device
- * @return: 0 on success or error code otherwise
- */
-int avirt_alsa_deregister(void)
-{
- CHK_NULL(card);
- snd_card_free(card);
- CHK_NULL(coreinfo.playback.config);
- kfree(coreinfo.playback.config);
- CHK_NULL(coreinfo.capture.config);
- kfree(coreinfo.capture.config);
-
- return 0;
-}
-
-/**
- * pcm_buff_complete_cb - PCM buffer complete callback
- * @substreamid: pointer to ALSA PCM substream
- * @return 0 on success or error code otherwise
- *
- * This should be called from a child Audio Path once it has finished processing
- * the pcm buffer
- */
-int pcm_buff_complete_cb(struct snd_pcm_substream *substream)
-{
- // Notify ALSA middle layer of the elapsed period boundary
- snd_pcm_period_elapsed(substream);
-
- return 0;
-}
diff --git a/alsa.h b/alsa.h
deleted file mode 100755
index c22a93c..0000000
--- a/alsa.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * ALSA Virtual Soundcard
- *
- * alsa.h - Top level ALSA interface
- *
- * Copyright (C) 2010-2018 Fiberdyne Systems Pty Ltd
- */
-
-#ifndef __AVIRT_ALSA_H__
-#define __AVIRT_ALSA_H__
-
-#include "core.h"
-
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <sound/pcm.h>
-
-#define PRINT_ERR(errno, errmsg) \
- pr_err("[%s]:[ERRNO:%d]: %s ", __func__, errno, (errmsg));
-
-#define CHK_ERR(errno) \
- do { \
- if ((errno) < 0) \
- return (errno); \
- } while (0)
-
-#define CHK_ERR_V(errno, errmsg, ...) \
- do { \
- if ((errno) < 0) { \
- PRINT_ERR((errno), (errmsg), ##__VA_ARGS__) \
- return (errno); \
- } \
- } while (0)
-
-#define CHK_NULL(x) \
- do { \
- if (!(x)) \
- return -EFAULT; \
- } while (0)
-
-#define CHK_NULL_V(x, errmsg, ...) \
- do { \
- if (!(x)) { \
- char *errmsg_done = \
- kasprintf(GFP_KERNEL, errmsg, ##__VA_ARGS__); \
- PRINT_ERR(EFAULT, errmsg_done); \
- kfree(errmsg_done); \
- return -EFAULT; \
- } \
- } while (0)
-
-extern struct avirt_coreinfo coreinfo;
-extern struct snd_pcm_ops pcm_ops;
-
-/**
- * avirt_alsa_configure_pcm- Configure the PCM device
- * @config: Device configuration structure array
- * @direction: Direction of PCM (SNDRV_PCM_STREAM_XXX)
- * @numdevices: Number of devices (array length)
- * @return: 0 on success or error code otherwise
- */
-int avirt_alsa_configure_pcm(struct avirt_alsa_devconfig *config, int direction,
- unsigned int numdevices);
-
-/**
- * avirt_alsa_register - Registers the ALSA driver
- * @devptr: Platform driver device
- * @return: 0 on success or error code otherwise
- */
-int avirt_alsa_register(struct platform_device *devptr);
-
-/**
- * avirt_alsa_deregister - Deregisters the ALSA driver
- * @devptr: Platform driver device
- * @return: 0 on success or error code otherwise
- */
-int avirt_alsa_deregister(void);
-
-/**
- * avirt_alsa_get_group - Gets the device group for the specified direction
- * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE
- * @return: Either the playback or capture device group on success,
- * or NULL otherwise
- */
-struct avirt_alsa_group *avirt_alsa_get_group(int direction);
-
-/**
- * pcm_buff_complete_cb - PCM buffer complete callback
- * @substream: pointer to ALSA PCM substream
- * @return 0 on success or error code otherwise
- *
- * This should be called from a child Audio Path once it has finished processing
- * the PCM buffer
- */
-int pcm_buff_complete_cb(struct snd_pcm_substream *substream);
-
-#endif // __AVIRT_ALSA_H__
diff --git a/core.c b/core.c
index 360f174..c9e8d25 100644
--- a/core.c
+++ b/core.c
@@ -9,9 +9,13 @@
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/string.h>
+#include <sound/core.h>
+#include <sound/initval.h>
#include "avirt/core.h"
-#include "alsa.h"
+#include "alsa-pcm.h"
+#include "utils.h"
MODULE_AUTHOR("JOSHANNE <james.oshannessy@fiberdyne.com.au>");
MODULE_AUTHOR("MFARRUGI <mark.farrugia@fiberdyne.com.au>");
@@ -58,8 +62,8 @@ module_param_array(capture_chans, int, NULL, DEFAULT_FILE_PERMS);
MODULE_PARM_DESC(capture_chans, "Channels per capture device");
static struct avirt_core {
+ struct snd_card *card;
struct device *dev;
-
struct class *avirt_class;
struct platform_device *platform_dev;
} core;
@@ -78,8 +82,8 @@ static LIST_HEAD(audiopath_list);
*/
static int avirt_probe(struct platform_device *devptr)
{
- // struct avirt_alsa_devconfig capture_config[MAX_PCM_DEVS];
- struct avirt_alsa_devconfig playback_config[MAX_PCM_DEVS];
+ static struct snd_device_ops device_ops;
+ struct snd_pcm **pcm;
int err = 0, i = 0;
if (playback_num == 0 && capture_num == 0) {
@@ -87,51 +91,71 @@ static int avirt_probe(struct platform_device *devptr)
return -EINVAL;
}
- // Set up playback
- for (i = 0; i < playback_num; i++) {
- if (!playback_names[i]) {
- pr_err("Playback config dev name is NULL for idx=%d\n",
- i);
- return -EINVAL;
- }
- memcpy((char *)playback_config[i].devicename, playback_names[i],
- MAX_NAME_LEN);
- if (playback_chans[i] == 0) {
- pr_err("Playback config channels is 0 for idx=%d\n", i);
- return -EINVAL;
+ // Create the card instance
+ CHK_ERR_V(snd_card_new(&devptr->dev, SNDRV_DEFAULT_IDX1, "avirt",
+ THIS_MODULE, 0, &core.card),
+ "Failed to create sound card");
+
+ strcpy(core.card->driver, "avirt-alsa-device");
+ strcpy(core.card->shortname, "avirt");
+ strcpy(core.card->longname, "A virtual sound card driver for ALSA");
+
+ // Create new sound device
+ CHK_ERR_V((snd_device_new(core.card, SNDRV_DEV_LOWLEVEL, &coreinfo,
+ &device_ops)),
+ "Failed to create sound device");
+
+ // TEMP
+ if (playback_num > 0) {
+ coreinfo.playback.devices = playback_num;
+ coreinfo.playback.streams = kzalloc(
+ sizeof(*coreinfo.playback.streams) * playback_num,
+ GFP_KERNEL);
+ for (i = 0; i < playback_num; i++) {
+ pcm = &coreinfo.playback.streams[i].pcm;
+ CHK_ERR(snd_pcm_new(core.card, playback_names[i], i, 1,
+ 0, pcm));
+
+ /** Register driver callbacks */
+ snd_pcm_set_ops(*pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &pcm_ops);
+
+ (*pcm)->info_flags = 0;
+ strcpy((*pcm)->name, playback_names[i]);
+ coreinfo.playback.streams[i].channels =
+ playback_chans[i];
+ pr_info("snd_pcm_new: name: %s, chans: %d\n",
+ (*pcm)->name,
+ coreinfo.playback.streams[i].channels);
}
- playback_config[i].channels = playback_chans[i];
}
- err = avirt_alsa_configure_pcm(playback_config,
- SNDRV_PCM_STREAM_PLAYBACK, playback_num);
- if (err < 0)
- return err;
-
-// Does not work yet!
-#if 0
- // Set up capture
- for (i = 0; i < capture_num; i++) {
- if (!capture_names[i]) {
- pr_err("Capture config devicename is NULL for idx=%d",
- i);
- return -EINVAL;
- }
- memcpy((char *)capture_config[i].devicename, capture_names[i],
- 255);
- if (capture_chans[i] == 0) {
- pr_err("Capture config channels is 0 for idx=%d");
- return -EINVAL;
+ if (capture_num > 0) {
+ coreinfo.capture.devices = capture_num;
+ coreinfo.capture.streams =
+ kzalloc(sizeof(*coreinfo.capture.streams) * capture_num,
+ GFP_KERNEL);
+ for (i = 0; i < capture_num; i++) {
+ pcm = &coreinfo.capture.streams[i].pcm;
+ CHK_ERR(snd_pcm_new(core.card, capture_names[i],
+ i + playback_num, 0, 1, pcm));
+
+ /** Register driver callbacks */
+ snd_pcm_set_ops(*pcm, SNDRV_PCM_STREAM_CAPTURE,
+ &pcm_ops);
+
+ (*pcm)->info_flags = 0;
+ strcpy((*pcm)->name, capture_names[i]);
+ coreinfo.capture.streams[i].channels = capture_chans[i];
+ pr_info("snd_pcm_new: name: %s, chans: %d\n",
+ (*pcm)->name,
+ coreinfo.capture.streams[i].channels);
}
- capture_config[i].channels = capture_chans[i];
}
- err = avirt_alsa_configure_pcm(capture_config, SNDRV_PCM_STREAM_CAPTURE, capture_num);
- if (err < 0)
- return err;
-#endif
+ // TEMP
- // Register for ALSA
- CHK_ERR(avirt_alsa_register(devptr));
+ /** Register with the ALSA framework */
+ CHK_ERR_V(snd_card_register(core.card), "Device registration failed");
return err;
}
@@ -143,7 +167,13 @@ static int avirt_probe(struct platform_device *devptr)
*/
static int avirt_remove(struct platform_device *devptr)
{
- return avirt_alsa_deregister();
+ snd_card_free(core.card);
+ CHK_NULL(coreinfo.playback.streams);
+ kfree(coreinfo.playback.streams);
+ CHK_NULL(coreinfo.capture.streams);
+ kfree(coreinfo.capture.streams);
+
+ return 0;
}
static struct platform_driver avirt_driver = {
diff --git a/core.h b/core.h
index 98d1bbd..4a0157a 100644
--- a/core.h
+++ b/core.h
@@ -11,6 +11,7 @@
#define __AVIRT_CORE_H__
#include <sound/pcm.h>
+#include <linux/configfs.h>
#define MAX_NAME_LEN 32
@@ -37,19 +38,20 @@ struct avirt_audiopath {
};
/*
- * ALSA Substream device configuration
+ * Audio stream configuration
*/
-struct avirt_alsa_devconfig {
- const char devicename[MAX_NAME_LEN];
- int channels;
+struct avirt_stream {
+ struct snd_pcm *pcm; /* Stream PCM device */
+ unsigned int channels; /* Stream channel count */
+ struct config_item item; /* configfs item reference */
};
/**
- * Collection of ALSA devices
+ * Collection of audio streams
*/
-struct avirt_alsa_group {
- struct avirt_alsa_devconfig *config;
- int devices;
+struct avirt_stream_group {
+ struct avirt_stream *streams; /* AVIRT stream array */
+ unsigned int devices; /* Number of stream devices */
};
/**
@@ -58,8 +60,8 @@ struct avirt_alsa_group {
struct avirt_coreinfo {
unsigned int version[3];
- struct avirt_alsa_group playback;
- struct avirt_alsa_group capture;
+ struct avirt_stream_group playback;
+ struct avirt_stream_group capture;
avirt_buff_complete pcm_buff_complete;
};
diff --git a/utils.h b/utils.h
new file mode 100644
index 0000000..b449938
--- /dev/null
+++ b/utils.h
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ALSA Virtual Soundcard
+ *
+ * utils.h - Some useful utilities for AVIRT
+ *
+ * Copyright (C) 2010-2018 Fiberdyne Systems Pty Ltd
+ */
+
+#ifndef __AVIRT_UTILS_H__
+#define __AVIRT_UTILS_H__
+
+#include <linux/slab.h>
+
+#define PRINT_ERR(errno, errmsg) \
+ pr_err("[%s]:[ERRNO:%d]: %s ", __func__, errno, (errmsg));
+
+#define CHK_ERR(errno) \
+ do { \
+ if ((errno) < 0) \
+ return (errno); \
+ } while (0)
+
+#define CHK_ERR_V(errno, errmsg, ...) \
+ do { \
+ if ((errno) < 0) { \
+ PRINT_ERR((errno), (errmsg), ##__VA_ARGS__) \
+ return (errno); \
+ } \
+ } while (0)
+
+#define CHK_NULL(x) \
+ do { \
+ if (!(x)) \
+ return -EFAULT; \
+ } while (0)
+
+#define CHK_NULL_V(x, errmsg, ...) \
+ do { \
+ if (!(x)) { \
+ char *errmsg_done = \
+ kasprintf(GFP_KERNEL, errmsg, ##__VA_ARGS__); \
+ PRINT_ERR(EFAULT, errmsg_done); \
+ kfree(errmsg_done); \
+ return -EFAULT; \
+ } \
+ } while (0)
+
+#endif