162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Misc memory accessors
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/export.h>
962306a36Sopenharmony_ci#include <linux/io.h>
1062306a36Sopenharmony_ci#include <linux/uaccess.h>
1162306a36Sopenharmony_ci#include <sound/core.h>
1262306a36Sopenharmony_ci#include <sound/pcm.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/**
1562306a36Sopenharmony_ci * copy_to_user_fromio - copy data from mmio-space to user-space
1662306a36Sopenharmony_ci * @dst: the destination pointer on user-space
1762306a36Sopenharmony_ci * @src: the source pointer on mmio
1862306a36Sopenharmony_ci * @count: the data size to copy in bytes
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Copies the data from mmio-space to user-space.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Return: Zero if successful, or non-zero on failure.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_ciint copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct iov_iter iter;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (import_ubuf(ITER_DEST, dst, count, &iter))
2962306a36Sopenharmony_ci		return -EFAULT;
3062306a36Sopenharmony_ci	return copy_to_iter_fromio(&iter, (const void __iomem *)src, count);
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ciEXPORT_SYMBOL(copy_to_user_fromio);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/**
3562306a36Sopenharmony_ci * copy_to_iter_fromio - copy data from mmio-space to iov_iter
3662306a36Sopenharmony_ci * @dst: the destination iov_iter
3762306a36Sopenharmony_ci * @src: the source pointer on mmio
3862306a36Sopenharmony_ci * @count: the data size to copy in bytes
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Copies the data from mmio-space to iov_iter.
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * Return: Zero if successful, or non-zero on failure.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ciint copy_to_iter_fromio(struct iov_iter *dst, const void __iomem *src,
4562306a36Sopenharmony_ci			size_t count)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci#if defined(__i386__) || defined(CONFIG_SPARC32)
4862306a36Sopenharmony_ci	return copy_to_iter((const void __force *)src, count, dst) == count ? 0 : -EFAULT;
4962306a36Sopenharmony_ci#else
5062306a36Sopenharmony_ci	char buf[256];
5162306a36Sopenharmony_ci	while (count) {
5262306a36Sopenharmony_ci		size_t c = count;
5362306a36Sopenharmony_ci		if (c > sizeof(buf))
5462306a36Sopenharmony_ci			c = sizeof(buf);
5562306a36Sopenharmony_ci		memcpy_fromio(buf, (void __iomem *)src, c);
5662306a36Sopenharmony_ci		if (copy_to_iter(buf, c, dst) != c)
5762306a36Sopenharmony_ci			return -EFAULT;
5862306a36Sopenharmony_ci		count -= c;
5962306a36Sopenharmony_ci		src += c;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci	return 0;
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ciEXPORT_SYMBOL(copy_to_iter_fromio);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/**
6762306a36Sopenharmony_ci * copy_from_user_toio - copy data from user-space to mmio-space
6862306a36Sopenharmony_ci * @dst: the destination pointer on mmio-space
6962306a36Sopenharmony_ci * @src: the source pointer on user-space
7062306a36Sopenharmony_ci * @count: the data size to copy in bytes
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * Copies the data from user-space to mmio-space.
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * Return: Zero if successful, or non-zero on failure.
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_ciint copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct iov_iter iter;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	if (import_ubuf(ITER_SOURCE, (void __user *)src, count, &iter))
8162306a36Sopenharmony_ci		return -EFAULT;
8262306a36Sopenharmony_ci	return copy_from_iter_toio((void __iomem *)dst, &iter, count);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ciEXPORT_SYMBOL(copy_from_user_toio);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/**
8762306a36Sopenharmony_ci * copy_from_iter_toio - copy data from iov_iter to mmio-space
8862306a36Sopenharmony_ci * @dst: the destination pointer on mmio-space
8962306a36Sopenharmony_ci * @src: the source iov_iter
9062306a36Sopenharmony_ci * @count: the data size to copy in bytes
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci * Copies the data from iov_iter to mmio-space.
9362306a36Sopenharmony_ci *
9462306a36Sopenharmony_ci * Return: Zero if successful, or non-zero on failure.
9562306a36Sopenharmony_ci */
9662306a36Sopenharmony_ciint copy_from_iter_toio(void __iomem *dst, struct iov_iter *src, size_t count)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci#if defined(__i386__) || defined(CONFIG_SPARC32)
9962306a36Sopenharmony_ci	return copy_from_iter((void __force *)dst, count, src) == count ? 0 : -EFAULT;
10062306a36Sopenharmony_ci#else
10162306a36Sopenharmony_ci	char buf[256];
10262306a36Sopenharmony_ci	while (count) {
10362306a36Sopenharmony_ci		size_t c = count;
10462306a36Sopenharmony_ci		if (c > sizeof(buf))
10562306a36Sopenharmony_ci			c = sizeof(buf);
10662306a36Sopenharmony_ci		if (copy_from_iter(buf, c, src) != c)
10762306a36Sopenharmony_ci			return -EFAULT;
10862306a36Sopenharmony_ci		memcpy_toio(dst, buf, c);
10962306a36Sopenharmony_ci		count -= c;
11062306a36Sopenharmony_ci		dst += c;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	return 0;
11362306a36Sopenharmony_ci#endif
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ciEXPORT_SYMBOL(copy_from_iter_toio);
116