diff options
author | Jack Sangdahl <[email protected]> | 2024-09-28 01:48:47 -0600 |
---|---|---|
committer | Jack Sangdahl <[email protected]> | 2024-09-28 01:48:47 -0600 |
commit | eea3d410e709ebac4351f58487ed3c9f49631c44 (patch) | |
tree | 87efd0eda5ee33758204172911f9d002dcf022d4 | |
parent | 5b2e4d95a74f83277b654fadceb98bef87690a54 (diff) | |
download | csci3753-eea3d410e709ebac4351f58487ed3c9f49631c44.tar.gz csci3753-eea3d410e709ebac4351f58487ed3c9f49631c44.zip |
pa3: improvements
-rw-r--r-- | pa3_device_driver/char_driver.c | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/pa3_device_driver/char_driver.c b/pa3_device_driver/char_driver.c index 7ca63e3..8bea3fb 100644 --- a/pa3_device_driver/char_driver.c +++ b/pa3_device_driver/char_driver.c @@ -3,11 +3,13 @@ // PA3 Device Driver #include <linux/fs.h> #include <linux/module.h> +#include <linux/slab.h> MODULE_AUTHOR("jasa7131"); MODULE_LICENSE("GPL"); #define BUFFER_SIZE 900 +#define MAJOR_NUM 510 #define DEVICE_NAME "char_dev" static int major, counter = 0; static char *data; @@ -38,49 +40,59 @@ int char_driver_close(struct inode *pinode, struct file *pfile) { 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; + size_t data_avail = BUFFER_SIZE - *offset, bytes_read = length; + if (*offset >= BUFFER_SIZE || !length) + return 0; + if (length > data_avail) + bytes_read = data_avail; + printk("Requested data size: %zd bytes\n", length); + long res = copy_to_user(buffer, data + *offset, bytes_read); + printk("Read %zd bytes from device\n", bytes_read); + length -= res; + *offset += length; + return length; } 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; + size_t data_avail = BUFFER_SIZE - *offset, bytes_written = length; + if (*offset >= BUFFER_SIZE || !length) + return 0; + if (length > data_avail) + bytes_written = data_avail; + printk("Requested data size: %zd bytes\n", length); + long res = copy_from_user(data + *offset, buffer, bytes_written); + printk("Wrote %zd bytes to device\n", bytes_written); + length -= res; + *offset += bytes_written; + return length; } loff_t char_driver_seek(struct file *pfile, loff_t offset, int whence) { + loff_t new_pos = 0; switch (whence) { case SEEK_SET: - pfile->f_pos = offset; + new_pos = offset; break; case SEEK_CUR: - pfile->f_pos += offset; + new_pos = pfile->f_pos + offset; break; case SEEK_END: - pfile->f_pos = strlen(data) - offset; + new_pos = BUFFER_SIZE - offset; break; } - return pfile->f_pos; + if (new_pos > BUFFER_SIZE) + new_pos = BUFFER_SIZE; + if (new_pos < 0) + new_pos = 0; + pfile->f_pos = new_pos; + return new_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); + major = register_chrdev(MAJOR_NUM, DEVICE_NAME, &char_fops); if (major < 0) { printk(KERN_ALERT "REGISTRATION FAILED: %s could not be reigstered.\n", DEVICE_NAME); |