4
* @author Aleksey Zhmulin
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>
26
#define IDESC_POOL_SIZE OPTION_GET(NUMBER, idesc_pool_size)
28
POOL_DEF(idesc_pool, struct char_dev_idesc, IDESC_POOL_SIZE);
30
static const struct idesc_ops char_dev_idesc_ops;
32
static bool char_dev_idesc_is_valid(struct idesc *idesc) {
33
return idesc && (idesc->idesc_ops == &char_dev_idesc_ops);
36
static struct char_dev *char_dev_idesc_get_dev(struct idesc *idesc) {
37
if (!char_dev_idesc_is_valid(idesc)) {
41
return ((struct char_dev_idesc *)idesc)->cdev;
44
static ssize_t char_dev_readv(struct idesc *idesc, const struct iovec *iov,
46
struct char_dev *cdev;
51
cdev = char_dev_idesc_get_dev(idesc);
54
if (idesc->idesc_flags & O_PATH) {
57
assert(cdev->ops->read);
59
for (i = 0, nbyte = 0; i < iovcnt; i++) {
60
res = cdev->ops->read(cdev, iov[i].iov_base, iov[i].iov_len);
71
static ssize_t char_dev_writev(struct idesc *idesc, const struct iovec *iov,
73
struct char_dev *cdev;
78
cdev = char_dev_idesc_get_dev(idesc);
81
if (idesc->idesc_flags & O_PATH) {
84
assert(cdev->ops->write);
86
for (i = 0, nbyte = 0; i < iovcnt; i++) {
87
res = cdev->ops->write(cdev, iov[i].iov_base, iov[i].iov_len);
98
void char_dev_close(struct idesc *idesc) {
99
struct char_dev *cdev;
101
cdev = char_dev_idesc_get_dev(idesc);
104
if (idesc->idesc_flags & O_PATH) {
108
if (--cdev->usage_count > 0) {
112
assert(cdev->usage_count == 0);
114
if (cdev->ops->close) {
115
cdev->ops->close(cdev);
119
pool_free(&idesc_pool, idesc);
122
static int char_dev_ioctl(struct idesc *idesc, int request, void *data) {
123
struct char_dev *cdev;
125
cdev = char_dev_idesc_get_dev(idesc);
128
if (!cdev->ops->ioctl) {
132
return cdev->ops->ioctl(cdev, request, data);
135
static int char_dev_fstat(struct idesc *idesc, struct stat *stat) {
136
assert(char_dev_idesc_is_valid(idesc));
139
memset(stat, 0, sizeof(struct stat));
140
stat->st_mode = S_IFCHR;
145
static int char_dev_status(struct idesc *idesc, int mask) {
146
struct char_dev *cdev;
148
cdev = char_dev_idesc_get_dev(idesc);
151
if (!cdev->ops->status) {
155
return cdev->ops->status(cdev, mask);
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;
163
cdev = char_dev_idesc_get_dev(idesc);
166
if (!cdev->ops->direct_access) {
170
phy_addr = cdev->ops->direct_access(cdev, off, len);
175
mmap_device_memory(phy_addr, len, prot, flags, (uintptr_t)phy_addr);
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,
190
struct idesc *char_dev_open(struct char_dev *cdev, int oflag) {
191
struct char_dev_idesc *cdev_idesc;
195
assert(cdev->usage_count >= 0);
197
cdev_idesc = pool_alloc(&idesc_pool);
199
return err2ptr(ENOMEM);
202
idesc_init((struct idesc *)cdev_idesc, &char_dev_idesc_ops, oflag);
203
cdev_idesc->cdev = cdev;
205
if (oflag & O_PATH) {
209
if (!cdev->ops->read && ((oflag & O_ACCESS_MASK) != O_WRONLY)) {
210
return err2ptr(EACCES);
213
if (!cdev->ops->write && ((oflag & O_ACCESS_MASK) != O_RDONLY)) {
214
return err2ptr(EACCES);
217
if (cdev->usage_count++ > 0) {
221
if (cdev->ops->open && (err = cdev->ops->open(cdev, &cdev_idesc->idesc))) {
222
pool_free(&idesc_pool, cdev_idesc);
223
return err2ptr(-err);
227
return (struct idesc *)cdev_idesc;