embox

Форк
0
/
char_dev_idesc.c 
228 строк · 4.4 Кб
1
/**
2
 * @brief
3
 *
4
 * @author Aleksey Zhmulin
5
 * @date 19.02.24
6
 */
7

8
#include <assert.h>
9
#include <errno.h>
10
#include <fcntl.h>
11
#include <stddef.h>
12
#include <stdint.h>
13
#include <string.h>
14
#include <sys/mman.h>
15
#include <sys/stat.h>
16
#include <sys/uio.h>
17

18
#include <drivers/char_dev.h>
19
#include <framework/mod/options.h>
20
#include <kernel/task/resource/idesc.h>
21
#include <lib/libds/array.h>
22
#include <mem/misc/pool.h>
23
#include <util/err.h>
24
#include <util/log.h>
25

26
#define IDESC_POOL_SIZE OPTION_GET(NUMBER, idesc_pool_size)
27

28
POOL_DEF(idesc_pool, struct char_dev_idesc, IDESC_POOL_SIZE);
29

30
static const struct idesc_ops char_dev_idesc_ops;
31

32
static bool char_dev_idesc_is_valid(struct idesc *idesc) {
33
	return idesc && (idesc->idesc_ops == &char_dev_idesc_ops);
34
}
35

36
static struct char_dev *char_dev_idesc_get_dev(struct idesc *idesc) {
37
	if (!char_dev_idesc_is_valid(idesc)) {
38
		return NULL;
39
	}
40

41
	return ((struct char_dev_idesc *)idesc)->cdev;
42
}
43

44
static ssize_t char_dev_readv(struct idesc *idesc, const struct iovec *iov,
45
    int iovcnt) {
46
	struct char_dev *cdev;
47
	ssize_t nbyte;
48
	ssize_t res;
49
	int i;
50

51
	cdev = char_dev_idesc_get_dev(idesc);
52
	assert(cdev);
53

54
	if (idesc->idesc_flags & O_PATH) {
55
		return -EBADF;
56
	}
57
	assert(cdev->ops->read);
58

59
	for (i = 0, nbyte = 0; i < iovcnt; i++) {
60
		res = cdev->ops->read(cdev, iov[i].iov_base, iov[i].iov_len);
61
		if (res < 0) {
62
			nbyte = res;
63
			break;
64
		}
65
		nbyte += res;
66
	}
67

68
	return nbyte;
69
}
70

71
static ssize_t char_dev_writev(struct idesc *idesc, const struct iovec *iov,
72
    int iovcnt) {
73
	struct char_dev *cdev;
74
	ssize_t nbyte;
75
	ssize_t res;
76
	int i;
77

78
	cdev = char_dev_idesc_get_dev(idesc);
79
	assert(cdev);
80

81
	if (idesc->idesc_flags & O_PATH) {
82
		return -EBADF;
83
	}
84
	assert(cdev->ops->write);
85

86
	for (i = 0, nbyte = 0; i < iovcnt; i++) {
87
		res = cdev->ops->write(cdev, iov[i].iov_base, iov[i].iov_len);
88
		if (res < 0) {
89
			nbyte = res;
90
			break;
91
		}
92
		nbyte += res;
93
	}
94

95
	return nbyte;
96
}
97

98
void char_dev_close(struct idesc *idesc) {
99
	struct char_dev *cdev;
100

101
	cdev = char_dev_idesc_get_dev(idesc);
102
	assert(cdev);
103

104
	if (idesc->idesc_flags & O_PATH) {
105
		goto out;
106
	}
107

108
	if (--cdev->usage_count > 0) {
109
		goto out;
110
	}
111

112
	assert(cdev->usage_count == 0);
113

114
	if (cdev->ops->close) {
115
		cdev->ops->close(cdev);
116
	}
117

118
out:
119
	pool_free(&idesc_pool, idesc);
120
}
121

122
static int char_dev_ioctl(struct idesc *idesc, int request, void *data) {
123
	struct char_dev *cdev;
124

125
	cdev = char_dev_idesc_get_dev(idesc);
126
	assert(cdev);
127

128
	if (!cdev->ops->ioctl) {
129
		return -EBADF;
130
	}
131

132
	return cdev->ops->ioctl(cdev, request, data);
133
}
134

135
static int char_dev_fstat(struct idesc *idesc, struct stat *stat) {
136
	assert(char_dev_idesc_is_valid(idesc));
137
	assert(stat);
138

139
	memset(stat, 0, sizeof(struct stat));
140
	stat->st_mode = S_IFCHR;
141

142
	return 0;
143
}
144

145
static int char_dev_status(struct idesc *idesc, int mask) {
146
	struct char_dev *cdev;
147

148
	cdev = char_dev_idesc_get_dev(idesc);
149
	assert(cdev);
150

151
	if (!cdev->ops->status) {
152
		return -EBADF;
153
	}
154

155
	return cdev->ops->status(cdev, mask);
156
}
157

158
static void *char_dev_mmap(struct idesc *idesc, void *addr, size_t len,
159
    int prot, int flags, int fd, off_t off) {
160
	struct char_dev *cdev;
161
	void *phy_addr;
162

163
	cdev = char_dev_idesc_get_dev(idesc);
164
	assert(cdev);
165

166
	if (!cdev->ops->direct_access) {
167
		return NULL;
168
	}
169

170
	phy_addr = cdev->ops->direct_access(cdev, off, len);
171
	if (!phy_addr) {
172
		return NULL;
173
	}
174

175
	mmap_device_memory(phy_addr, len, prot, flags, (uintptr_t)phy_addr);
176

177
	return phy_addr;
178
}
179

180
static const struct idesc_ops char_dev_idesc_ops = {
181
    .id_readv = char_dev_readv,
182
    .id_writev = char_dev_writev,
183
    .close = char_dev_close,
184
    .ioctl = char_dev_ioctl,
185
    .fstat = char_dev_fstat,
186
    .status = char_dev_status,
187
    .idesc_mmap = char_dev_mmap,
188
};
189

190
struct idesc *char_dev_open(struct char_dev *cdev, int oflag) {
191
	struct char_dev_idesc *cdev_idesc;
192
	int err;
193

194
	assert(cdev);
195
	assert(cdev->usage_count >= 0);
196

197
	cdev_idesc = pool_alloc(&idesc_pool);
198
	if (!cdev_idesc) {
199
		return err2ptr(ENOMEM);
200
	}
201

202
	idesc_init((struct idesc *)cdev_idesc, &char_dev_idesc_ops, oflag);
203
	cdev_idesc->cdev = cdev;
204

205
	if (oflag & O_PATH) {
206
		goto out;
207
	}
208

209
	if (!cdev->ops->read && ((oflag & O_ACCESS_MASK) != O_WRONLY)) {
210
		return err2ptr(EACCES);
211
	}
212

213
	if (!cdev->ops->write && ((oflag & O_ACCESS_MASK) != O_RDONLY)) {
214
		return err2ptr(EACCES);
215
	}
216

217
	if (cdev->usage_count++ > 0) {
218
		goto out;
219
	}
220

221
	if (cdev->ops->open && (err = cdev->ops->open(cdev, &cdev_idesc->idesc))) {
222
		pool_free(&idesc_pool, cdev_idesc);
223
		return err2ptr(-err);
224
	}
225

226
out:
227
	return (struct idesc *)cdev_idesc;
228
}
229

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.