/
simple_char_driver.c
130 lines (102 loc) · 3.79 KB
/
simple_char_driver.c
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
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<asm/uaccess.h>
#define BUFFER_SIZE 1024
static char device_buffer[BUFFER_SIZE];
int openCount = 0;
int closeCount = 0;
int placeholder = 0;
ssize_t simple_char_driver_read (struct file *pfile, char __user *buffer, size_t length, loff_t *offset)
{
/* pfile = driver file
* buffer = buffer in user space
* length = length of what is to be read (using cat will give something like 6000+ bytes)
* offset = variable to store offset for ONE read cycle.
*/
int bytesRead;
int bytesToRead = BUFFER_SIZE - *offset;
// If we are at the end of the file, STOP READING!
if (bytesToRead == 0){
printk(KERN_ALERT "Reached the end of the file");
return bytesToRead;
}
// Get bytes read by subtracting return of copy_to_user (returns unread bytes)
bytesRead = bytesToRead - copy_to_user(buffer, device_buffer + *offset, bytesToRead);
printk(KERN_ALERT "READING with Simple Character Driver. Reading %d bytes\n", bytesRead);
// Set offset so that we can eventually reach the end of the file
*offset += bytesRead;
return bytesRead;
}
ssize_t simple_char_driver_write (struct file *pfile, const char __user *buffer, size_t length, loff_t *offset)
{
/* pfile = driver file
* buffer = buffer in user space
* length = length of what is to be written
* offset = variable to store offset for ONE write
* placeholder = global var for the current write spot in the buffer
*/
int bytesToWrite;
int bytesWritten;
int bytesAvailable = BUFFER_SIZE - *offset - placeholder;
// Make sure there is sufficient space
if(bytesAvailable > length){
bytesToWrite = length;
}
else{
bytesToWrite = bytesAvailable;
}
//Get bites written by subtracting unwritten bites from retun of copy_from_user
bytesWritten = bytesToWrite - copy_from_user(device_buffer + *offset + placeholder, buffer, bytesToWrite);
// If no space left:
if(bytesWritten == 0){
printk(KERN_ALERT "The device is out of space.\n");
}
else{
//Increment offset and placeholder
*offset += bytesWritten;
placeholder += bytesWritten;
printk(KERN_ALERT "WRITING with Simple Character Driver. Writing %d bytes\n", bytesWritten);
}
return bytesWritten;
}
int simple_char_driver_open (struct inode *pinode, struct file *pfile)
{
/* print to the log file that the device is opened and also print the number of times this device has been opened until now*/
openCount++;
printk(KERN_ALERT "OPENING Simple Character Driver. It has been opened %d times\n", openCount);
return 0;
}
int simple_char_driver_close (struct inode *pinode, struct file *pfile)
{
/* print to the log file that the device is closed and also print the number of times this device has been closed until now*/
closeCount++;
printk(KERN_ALERT "CLOSING Simple Character Driver. It has been closed %d times\n", closeCount);
return 0;
}
struct file_operations simple_char_driver_file_operations = {
.owner = THIS_MODULE,
.read = simple_char_driver_read,
.write = simple_char_driver_write,
.open = simple_char_driver_open,
.release = simple_char_driver_close
};
static int simple_char_driver_init(void)
{
/* print to the log file that the init function is called.*/
printk(KERN_ALERT "INITIALIZING Simple Character Driver\n");
/* register the device */
register_chrdev( 301, "simple_driver", &simple_char_driver_file_operations);
return 0;
}
// Return type must be void to avoid warning in compilation
static void simple_char_driver_exit(void)
{
/* print to the log file that the exit function is called.*/
printk(KERN_ALERT "EXITING Simple Character Driver\n");
/* unregister the device */
unregister_chrdev( 301, "simple_driver");
}
/* add module_init and module_exit to point to the corresponding init and exit function*/
module_init(simple_char_driver_init);
module_exit(simple_char_driver_exit);