// Jack Sangdahl // CSCI3753 SP24 // PA3 Device Driver #include #include #include 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; 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) { 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) { 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: new_pos = offset; break; case SEEK_CUR: new_pos = pfile->f_pos + offset; break; case SEEK_END: new_pos = BUFFER_SIZE - offset; break; } 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(MAJOR_NUM, 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);