-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuffer_driver.c
More file actions
132 lines (112 loc) · 3.99 KB
/
Copy pathbuffer_driver.c
File metadata and controls
132 lines (112 loc) · 3.99 KB
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/version.h>
static const int MAJOR = 44;
static const int MINOR = 1;
static const char DEVICE_NAME[] = "buffer-device";
static const char DEVICE_CLASS[] = "buffer-device-class";
static struct cdev hcdev;
static dev_t dev;
static struct class *devclass;
#define CONTAINING_VALUE_LEN 1024
#define CONTAINING_VALUE_USED_LEN ((CONTAINING_VALUE_LEN - 1)) // the last byte will be always '\0'
static char containing_value[CONTAINING_VALUE_LEN];
ssize_t buffer_driver_read(struct file *f, char __user *buf, size_t sz, loff_t *off);
ssize_t buffer_driver_write(struct file *f, const char __user *buf, size_t sz, loff_t *off);
static struct file_operations buffer_driver_fops =
{
.owner = THIS_MODULE,
.read = buffer_driver_read,
.write = buffer_driver_write,
};
static int __init buffer_init(void)
{
if (register_chrdev(MAJOR, DEVICE_NAME,
&buffer_driver_fops))
{
pr_info("buffer_driver: unable to get major\n");
return -EIO;
}
pr_info("[%s] init: register_chrdev", DEVICE_NAME);
dev = MKDEV(MAJOR, MINOR);
/* class_create() dropped its first (owner) argument starting with
* Linux 6.4. Support both API generations so the module still
* builds on older and newer kernels. */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0)
devclass = class_create(DEVICE_CLASS);
#else
devclass = class_create(THIS_MODULE, DEVICE_CLASS);
#endif
if (IS_ERR(devclass))
{
pr_info("[%s] init: can't create class", DEVICE_NAME);
unregister_chrdev(MAJOR, DEVICE_NAME);
return PTR_ERR(devclass);
}
pr_info("[%s] init: class create", DEVICE_NAME);
if (IS_ERR(device_create(devclass, NULL, dev, NULL, "%s", DEVICE_NAME)))
{
pr_info("[%s] init: device_create fail", DEVICE_NAME);
class_destroy(devclass);
unregister_chrdev(MAJOR, DEVICE_NAME);
return -1;
}
pr_info("[%s] init: device_create", DEVICE_NAME);
cdev_init(&hcdev, &buffer_driver_fops);
if (cdev_add(&hcdev, dev, 1) < 0)
{
device_destroy(devclass, dev);
class_destroy(devclass);
unregister_chrdev(MAJOR, DEVICE_NAME);
return -1;
}
return 0;
}
static void __exit buffer_exit(void)
{
cdev_del(&hcdev);
device_destroy(devclass, dev);
class_destroy(devclass);
unregister_chrdev(MAJOR, DEVICE_NAME);
pr_info("[%s] buffer_exit", DEVICE_NAME);
return;
}
ssize_t buffer_driver_read(struct file *f, char __user *buf, size_t sz, loff_t *off)
{
pr_info("[%s] Try to read from the device \n", DEVICE_NAME);
size_t read_bytes = (CONTAINING_VALUE_USED_LEN < sz) ? CONTAINING_VALUE_USED_LEN : sz;
pr_info("[%s] Read bytes len = %zu \n", DEVICE_NAME, read_bytes);
pr_info("[%s] containing_value=%s", DEVICE_NAME, containing_value);
unsigned long not_copied = copy_to_user(buf, containing_value, read_bytes);
pr_info("[%s] copy_to_user not_copied = %lu \n", DEVICE_NAME, not_copied);
if (not_copied != 0)
{
return -EFAULT;
}
return (ssize_t)read_bytes;
}
ssize_t buffer_driver_write(struct file *f, const char __user *buf, size_t sz, loff_t *off)
{
pr_info("[%s] Try to write to the device \n", DEVICE_NAME);
size_t write_bytes = (CONTAINING_VALUE_USED_LEN < sz) ? CONTAINING_VALUE_USED_LEN : sz;
unsigned long not_copied = copy_from_user(containing_value, buf, write_bytes);
if (not_copied != 0)
{
size_t copied = write_bytes - not_copied;
if (copied == 0)
return -EFAULT;
containing_value[copied] = '\0';
return (ssize_t)copied;
}
containing_value[write_bytes] = '\0';
pr_info("[%s] wrote %zu bytes: '%s'\n", DEVICE_NAME, write_bytes, containing_value);
return (ssize_t)write_bytes;
}
module_init(buffer_init);
module_exit(buffer_exit);
MODULE_LICENSE("GPL");