aboutsummaryrefslogtreecommitdiff
path: root/pa3_device_driver/char_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'pa3_device_driver/char_driver.c')
-rw-r--r--pa3_device_driver/char_driver.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/pa3_device_driver/char_driver.c b/pa3_device_driver/char_driver.c
new file mode 100644
index 0000000..7ca63e3
--- /dev/null
+++ b/pa3_device_driver/char_driver.c
@@ -0,0 +1,100 @@
+// Jack Sangdahl
+// CSCI3753 SP24
+// PA3 Device Driver
+#include <linux/fs.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("jasa7131");
+MODULE_LICENSE("GPL");
+
+#define BUFFER_SIZE 900
+#define DEVICE_NAME "char_dev"
+static int major, counter = 0;
+static char *data;
+
+int char_driver_open(struct inode *, struct file *);
+int char_driver_close(struct inode *, struct file *);
+ssize_t char_driver_read(struct file *, char *, size_t, loff_t *);
+ssize_t char_driver_write(struct file *, const char *, size_t, loff_t *);
+loff_t char_driver_seek(struct file *, loff_t, int);
+
+struct file_operations char_fops = {.owner = THIS_MODULE,
+ .open = char_driver_open,
+ .release = char_driver_close,
+ .read = char_driver_read,
+ .write = char_driver_write,
+ .llseek = char_driver_seek};
+
+int char_driver_open(struct inode *pinode, struct file *pfile) {
+ counter++;
+ printk("Device opened %d times\n", counter);
+ return 0;
+}
+
+int char_driver_close(struct inode *pinode, struct file *pfile) {
+ printk("Device closed %d times\n", counter);
+ return 0;
+}
+
+ssize_t char_driver_read(struct file *pfile, char __user *buffer, size_t length,
+ loff_t *offset) {
+ ssize_t data_read = simple_read_from_buffer(buffer, length, offset,
+ data + *offset, BUFFER_SIZE);
+ if (data_read < 0) {
+ printk("READ FAILED: Failed to read from user buffer.\n");
+ return -EFAULT;
+ }
+ if (data_read) {
+ printk("READ SUCCESS: Read %ld bytes from %s.\n", data_read, DEVICE_NAME);
+ if (data_read >= BUFFER_SIZE)
+ printk("Reached EOF\n");
+ }
+ return data_read;
+}
+
+ssize_t char_driver_write(struct file *pfile, const char __user *buffer,
+ size_t length, loff_t *offset) {
+ ssize_t data_written = simple_write_to_buffer(data + *offset, BUFFER_SIZE,
+ offset, buffer, length);
+ printk("WRITE SUCCESS: Wrote %ld bytes to %s.\n", data_written, DEVICE_NAME);
+ if (data_written > BUFFER_SIZE)
+ printk("WRITE ERR: Buffer is filled.\n");
+ return data_written;
+}
+
+loff_t char_driver_seek(struct file *pfile, loff_t offset, int whence) {
+ switch (whence) {
+ case SEEK_SET:
+ pfile->f_pos = offset;
+ break;
+ case SEEK_CUR:
+ pfile->f_pos += offset;
+ break;
+ case SEEK_END:
+ pfile->f_pos = strlen(data) - offset;
+ break;
+ }
+ return pfile->f_pos;
+}
+
+static int char_driver_init(void) {
+ printk("Registering device %s\n", DEVICE_NAME);
+ data = (char *)kmalloc(BUFFER_SIZE * sizeof(char), GFP_KERNEL);
+ major = register_chrdev(511, DEVICE_NAME, &char_fops);
+ if (major < 0) {
+ printk(KERN_ALERT "REGISTRATION FAILED: %s could not be reigstered.\n",
+ DEVICE_NAME);
+ return -EFAULT;
+ }
+ printk("REGISTRATION SUCCESS: %s successfully registered.\n", DEVICE_NAME);
+ return 0;
+}
+
+static void char_driver_exit(void) {
+ kfree(data);
+ unregister_chrdev(major, DEVICE_NAME);
+ printk("UNREGISTER SUCCESS: %s successfully unregistered\n", DEVICE_NAME);
+}
+
+module_init(char_driver_init);
+module_exit(char_driver_exit);