Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Character device drivers lab
- *
- * All tasks
- */
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/cdev.h>
- #include <linux/uaccess.h>
- #include <linux/sched.h>
- #include <linux/wait.h>
- #include "../include/so2_cdev.h"
- MODULE_DESCRIPTION("SO2 character device");
- MODULE_AUTHOR("SO2");
- MODULE_LICENSE("GPL");
- #define LOG_LEVEL KERN_DEBUG
- #define MY_MAJOR 42
- #define MY_MINOR 0
- #define NUM_MINORS 1
- #define MODULE_NAME "so2_cdev"
- #define MESSAGE "hello\n"
- #define IOCTL_MESSAGE "Hello ioctl"
- #ifndef BUFSIZ
- #define BUFSIZ 4096
- #endif
- struct so2_device_data {
- /* TODO 2: add cdev member */
- struct cdev c_dev;
- /* TODO 4: add buffer with BUFSIZ elements */
- char buffer[BUFSIZ];
- /* TODO 7: extra members for home */
- /* TODO 3: add atomic_t access variable to keep track if file is opened */
- atomic_t access;
- };
- struct so2_device_data devs[NUM_MINORS];
- static int so2_cdev_open(struct inode *inode, struct file *file)
- {
- struct so2_device_data *data;
- pr_info("open\n");
- /* TODO 3: inode->i_cdev contains our cdev struct, use container_of to obtain a pointer to so2_device_data */
- data = container_of(inode->i_cdev, struct so2_device_data, c_dev);
- file->private_data = data;
- /* TODO 3: return immediately if access is != 0, use atomic_cmpxchg */
- if (atomic_cmpxchg(&(data->access), 0, 1)) {
- pr_info("it works\n");
- return -EBUSY;
- }
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(10);
- return 0;
- }
- static int
- so2_cdev_release(struct inode *inode, struct file *file)
- {
- #ifndef EXTRA
- struct so2_device_data *data =
- (struct so2_device_data *) file->private_data;
- pr_info("release\n");
- /* TODO 3: reset access variable to 0, use atomic_set */
- atomic_set(&(data->access), 0);
- #endif
- return 0;
- }
- static ssize_t
- so2_cdev_read(struct file *file,
- char __user *user_buffer,
- size_t size, loff_t *offset)
- {
- struct so2_device_data *data =
- (struct so2_device_data *) file->private_data;
- ssize_t to_read = size;
- printk(LOG_LEVEL "Offset: %lld\n", *offset);
- #ifdef EXTRA
- /* TODO 7: extra tasks for home */
- #endif
- /* TODO 4: Copy data->buffer to user_buffer, use copy_to_user */
- if (copy_to_user(user_buffer, data->buffer, size))
- return -EFAULT;
- *offset += size;
- to_read = size - *offset;
- return to_read;
- }
- static ssize_t
- so2_cdev_write(struct file *file,
- const char __user *user_buffer,
- size_t size, loff_t *offset)
- {
- struct so2_device_data *data =
- (struct so2_device_data *) file->private_data;
- /* TODO 5: copy user_buffer to data->buffer, use copy_from_user */
- if (copy_from_user(data->buffer, user_buffer, size))
- return -EFAULT;
- *offset += size;
- /* TODO 7: extra tasks for home */
- pr_info("write\n");
- return size;
- }
- static long
- so2_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- struct so2_device_data *data =
- (struct so2_device_data *) file->private_data;
- int ret = 0;
- int remains;
- switch (cmd) {
- /* TODO 6: if cmd = MY_IOCTL_PRINT, display IOCTL_MESSAGE */
- /* TODO 7: extra tasks, for home */
- default:
- ret = -EINVAL;
- }
- return ret;
- }
- static const struct file_operations so2_fops = {
- .owner = THIS_MODULE,
- /* TODO 2: add open, release, read, write functions */
- .unlocked_ioctl = so2_cdev_ioctl,
- .open = so2_cdev_open,
- .release = so2_cdev_release,
- .read = so2_cdev_read,
- .write = so2_cdev_write
- };
- static int so2_cdev_init(void)
- {
- int err;
- int i;
- pr_info("cdev init:");
- /* TODO 1: register char device region for MY_MAJOR and NUM_MINORS starting at MY_MINOR */
- if (register_chrdev_region(MKDEV(MY_MAJOR, MY_MINOR), NUM_MINORS, MODULE_NAME) < 0)
- pr_err("register failed!");
- else pr_info("register success\n");
- for (i = 0; i < NUM_MINORS; i++) {
- #ifdef EXTRA
- /* TODO 7: extra tasks, for home */
- #else
- /*TODO 4: initialize buffer with MESSAGE string */
- strcpy(devs[i].buffer, MESSAGE);
- #endif
- /* TODO 7: extra tasks for home */
- /* TODO 3: set access variable to 0, use atomic_set */
- atomic_set(&(devs[i].access), 0);
- /* TODO 2: init and add cdev to kernel core */
- cdev_init(&devs[i].c_dev, &so2_fops);
- cdev_add(&devs[i].c_dev, MKDEV(MY_MAJOR, MY_MINOR), 1);
- }
- return 0;
- }
- static void so2_cdev_exit(void)
- {
- int i;
- pr_info("cdev exit:");
- for (i = 0; i < NUM_MINORS; i++) {
- /* TODO 2: delete cdev from kernel core */
- cdev_del(&devs[i].c_dev);
- }
- /* TODO 1: unregister char device region, for MY_MAJOR and NUM_MINORS starting at MY_MINOR */
- unregister_chrdev_region(MKDEV(MY_MAJOR, MY_MINOR), NUM_MINORS);
- pr_info("unregister\n");
- }
- module_init(so2_cdev_init);
- module_exit(so2_cdev_exit);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement