summaryrefslogtreecommitdiff
path: root/libhw_generic/io.c
blob: 4ebff108e8dac1aac2952cfd2b6870760e5fc7ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/* libhw_generic/io.c - Utilities for device-independent I/O definitions
 *
 * Copyright (C) 2025  Luke T. Shumaker <lukeshu@lukeshu.com>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#include <libmisc/assert.h>

#include <libhw/generic/io.h>

#define IOV_ITER(ACTION)                                                \
	assert(src_cnt >= 0);                                           \
	assert(src_cnt == 0 || src);                                    \
                                                                        \
	const size_t byte_end = byte_beg + byte_max_cnt;                \
	int j = 0;                                                      \
	size_t byte_pos = 0;                                            \
	for (int i = 0;                                                 \
	     i < src_cnt && (byte_max_cnt == 0 || byte_pos < byte_end); \
	     i++) {                                                     \
		size_t off = 0, len;                                    \
		if (byte_pos < byte_beg) {                              \
			if (byte_beg - byte_pos >= src[i].iov_len) {    \
				byte_pos += src[i].iov_len;             \
				continue;                               \
			}                                               \
			off = byte_beg-byte_pos;                        \
			len = src[i].iov_len-off;                       \
			byte_pos = byte_beg;                            \
		} else {                                                \
			len = src[i].iov_len;                           \
		}                                                       \
		if (byte_max_cnt && byte_end - byte_pos < len)          \
			len = byte_end - byte_pos;                      \
		do { ACTION } while (0);                                \
		byte_pos += len;                                        \
		j++;                                                    \
	}

int io_slice_cnt(const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
	IOV_ITER();
	return j;
}

int io_duplex_slice_cnt(const struct duplex_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
	IOV_ITER();
	return j;
}

void io_slice(struct iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
	assert(src_cnt == 0 || dst);
	IOV_ITER(
		dst[j] = ((struct iovec){
			.iov_base = src[i].iov_base+off,
			.iov_len  = len,
		});
	);
}
void io_slice_duplex(struct duplex_iovec *dst, const struct duplex_iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
	assert(src_cnt == 0 || dst);
	IOV_ITER(
		dst[j] = ((struct duplex_iovec){
			.iov_read_to    = src[i].iov_read_to+off,
			.iov_write_from = src[i].iov_write_from+off,
			.iov_len        = len,
		});
	);
}

void io_slice_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
	assert(src_cnt == 0 || dst);
	IOV_ITER(
		dst[j] = ((struct duplex_iovec){
			.iov_read_to    = src[i].iov_base+off,
			.iov_write_from = IOVEC_DISCARD,
			.iov_len        = len,
		});
	);
}

void io_slice_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int src_cnt, size_t byte_beg, size_t byte_max_cnt) {
	assert(src_cnt == 0 || dst);
	IOV_ITER(
		dst[j] = ((struct duplex_iovec){
			.iov_read_to    = IOVEC_DISCARD,
			.iov_write_from = src[i].iov_base+off,
			.iov_len        = len,
		});
	);
}

void io_rd_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt) {
	io_slice_rd_to_duplex(dst, src, iovcnt, 0, 0);
}

void io_wr_to_duplex(struct duplex_iovec *dst, const struct iovec *src, int iovcnt) {
	io_slice_wr_to_duplex(dst, src, iovcnt, 0, 0);
}