diff --git a/20220411/Makefile b/20220411/Makefile new file mode 120000 index 0000000000000000000000000000000000000000..5ce401dd46fbd7266779a960b7ddfda0197b3a70 --- /dev/null +++ b/20220411/Makefile @@ -0,0 +1 @@ +Makefile-modules \ No newline at end of file diff --git a/20220411/Makefile-modules b/20220411/Makefile-modules new file mode 100644 index 0000000000000000000000000000000000000000..5dfbaa80b8a97151b02d6b52423cd8d29cd5b0b9 --- /dev/null +++ b/20220411/Makefile-modules @@ -0,0 +1,7 @@ +obj-m += chardev-1.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/20220411/chardev-1.c b/20220411/chardev-1.c new file mode 100644 index 0000000000000000000000000000000000000000..17a6651a33313322de202fbcb6bbf82333c0b766 --- /dev/null +++ b/20220411/chardev-1.c @@ -0,0 +1,166 @@ +/* + * chardev.c: Creates a read-only char device that says how many times + * you've read from the dev file + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <asm/uaccess.h> /* for put_user */ + +/* + * Prototypes - this would normally go in a .h file + */ +int init_module(void); +void cleanup_module(void); +static int device_open(struct inode *, struct file *); +static int device_release(struct inode *, struct file *); +static ssize_t device_read(struct file *, char *, size_t, loff_t *); +static ssize_t device_write(struct file *, const char *, size_t, loff_t *); + +#define SUCCESS 0 +#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */ +#define BUF_LEN 80 /* Max length of the message from the device */ + +/* + * Global variables are declared as static, so are global within the file. + */ + +static int Major; /* Major number assigned to our device driver */ +static int Device_Open = 0; /* Is device open? + * Used to prevent multiple access to device */ +static char msg[BUF_LEN]; /* The msg the device will give when asked */ +static char *msg_Ptr; + +static struct file_operations fops = { + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release +}; + +/* + * This function is called when the module is loaded + */ +int init_module(void) +{ + Major = register_chrdev(0, DEVICE_NAME, &fops); + + if (Major < 0) { + printk(KERN_ALERT "Registering char device failed with %d\n", Major); + return Major; + } + + printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major); + printk(KERN_INFO "the driver, create a dev file with\n"); + printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major); + printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n"); + printk(KERN_INFO "the device file.\n"); + printk(KERN_INFO "Remove the device file and module when done.\n"); + + return SUCCESS; +} + +/* + * This function is called when the module is unloaded + */ +void cleanup_module(void) +{ + /* + * Unregister the device + */ + unregister_chrdev(Major, DEVICE_NAME); +} + +/* + * Methods + */ + +/* + * Called when a process tries to open the device file, like + * "cat /dev/mycharfile" + */ +static int device_open(struct inode *inode, struct file *file) +{ + static int counter = 0; + + if (Device_Open) + return -EBUSY; + + Device_Open++; + sprintf(msg, "I already told you %d times Hello world!\n", counter++); + msg_Ptr = msg; + try_module_get(THIS_MODULE); + + return SUCCESS; +} + +/* + * Called when a process closes the device file. + */ +static int device_release(struct inode *inode, struct file *file) +{ + Device_Open--; /* We're now ready for our next caller */ + + /* + * Decrement the usage count, or else once you opened the file, you'll + * never get get rid of the module. + */ + module_put(THIS_MODULE); + + return 0; +} + +/* + * Called when a process, which already opened the dev file, attempts to + * read from it. + */ +static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ + char *buffer, /* buffer to fill with data */ + size_t length, /* length of the buffer */ + loff_t * offset) +{ + /* + * Number of bytes actually written to the buffer + */ + int bytes_read = 0; + + /* + * If we're at the end of the message, + * return 0 signifying end of file + */ + if (*msg_Ptr == 0) + return 0; + + /* + * Actually put the data into the buffer + */ + while (length && *msg_Ptr) { + + /* + * The buffer is in the user data segment, not the kernel + * segment so "*" assignment won't work. We have to use + * put_user which copies data from the kernel data segment to + * the user data segment. + */ + put_user(*(msg_Ptr++), buffer++); + + length--; + bytes_read++; + } + + /* + * Most read functions return the number of bytes put into the buffer + */ + return bytes_read; +} + +/* + * Called when a process writes to dev file: echo "hi" > /dev/hello + */ +static ssize_t +device_write(struct file *filp, const char *buff, size_t len, loff_t * off) +{ + printk(KERN_ALERT "Sorry, this operation isn't supported.\n"); + return -EINVAL; +} diff --git a/20220411/chardev-2.c b/20220411/chardev-2.c new file mode 100644 index 0000000000000000000000000000000000000000..54b8e3f30a580c7896ea18a0e4358059a6c03a48 --- /dev/null +++ b/20220411/chardev-2.c @@ -0,0 +1,183 @@ +/* + * chardev.c: Creates a read-only char device that says how many times + * you've read from the dev file + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <asm/uaccess.h> /* for put_user */ + +/* + * Prototypes - this would normally go in a .h file + */ +int init_module(void); +void cleanup_module(void); +static int device_open(struct inode *, struct file *); +static int device_release(struct inode *, struct file *); +static ssize_t device_read(struct file *, char *, size_t, loff_t *); +static ssize_t device_write(struct file *, const char *, size_t, loff_t *); + +struct class *dev_Class; +struct device *chr_dev; + +#define SUCCESS 0 +#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */ +#define BUF_LEN 80 /* Max length of the message from the device */ + +/* + * Global variables are declared as static, so are global within the file. + */ + +static int Major; /* Major number assigned to our device driver */ +static int Device_Open = 0; /* Is device open? + * Used to prevent multiple access to device */ +static char msg[BUF_LEN]; /* The msg the device will give when asked */ +static char *msg_Ptr; + +static struct file_operations fops = { + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release +}; + +/* + * This function is called when the module is loaded + */ +int init_module(void) +{ + Major = register_chrdev(0, DEVICE_NAME, &fops); + + if (Major < 0) { + printk(KERN_ALERT "Registering char device failed with %d\n", Major); + return Major; + } + + // Create module class + printk(KERN_INFO "Creating device class LCD...\n"); + dev_Class = class_create(THIS_MODULE,DEVICE_NAME); + if( dev_Class == NULL) + { + printk( KERN_ALERT "Error! Class couldn't be created!\n" ); + return 1 ; + } + printk( KERN_INFO "Class created!\n" ); + // Create device in /dev/... + printk(KERN_INFO "Creating device\n"); + chr_dev = device_create(dev_Class, NULL, MKDEV(Major,0), NULL, DEVICE_NAME); + + printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major); + printk(KERN_INFO "the driver, create a dev file with\n"); + printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n", DEVICE_NAME, Major); + printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n"); + printk(KERN_INFO "the device file.\n"); + printk(KERN_INFO "Remove the device file and module when done.\n"); + + return SUCCESS; +} + +/* + * This function is called when the module is unloaded + */ +void cleanup_module(void) +{ + /* + * Unregister the device + */ + unregister_chrdev(Major, DEVICE_NAME); +} + +/* + * Methods + */ + +/* + * Called when a process tries to open the device file, like + * "cat /dev/mycharfile" + */ +static int device_open(struct inode *inode, struct file *file) +{ + static int counter = 0; + + if (Device_Open) + return -EBUSY; + + Device_Open++; + sprintf(msg, "I already told you %d times Hello world!\n", counter++); + msg_Ptr = msg; + try_module_get(THIS_MODULE); + + return SUCCESS; +} + +/* + * Called when a process closes the device file. + */ +static int device_release(struct inode *inode, struct file *file) +{ + Device_Open--; /* We're now ready for our next caller */ + + /* + * Decrement the usage count, or else once you opened the file, you'll + * never get get rid of the module. + */ + module_put(THIS_MODULE); + + return 0; +} + +/* + * Called when a process, which already opened the dev file, attempts to + * read from it. + */ +static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ + char *buffer, /* buffer to fill with data */ + size_t length, /* length of the buffer */ + loff_t * offset) +{ + /* + * Number of bytes actually written to the buffer + */ + int bytes_read = 0; + + /* + * If we're at the end of the message, + * return 0 signifying end of file + */ + if (*msg_Ptr == 0) + return 0; + + /* + * Actually put the data into the buffer + */ + while (length && *msg_Ptr) { + + /* + * The buffer is in the user data segment, not the kernel + * segment so "*" assignment won't work. We have to use + * put_user which copies data from the kernel data segment to + * the user data segment. + */ + put_user(*(msg_Ptr++), buffer++); + + length--; + bytes_read++; + } + + /* + * Most read functions return the number of bytes put into the buffer + */ + return bytes_read; +} + +/* + * Called when a process writes to dev file: echo "hi" > /dev/hello + */ +static ssize_t +device_write(struct file *filp, const char *buff, size_t len, loff_t * off) +{ + printk(KERN_ALERT "Sorry, this operation isn't supported.\n"); + return -EINVAL; +} diff --git a/20220411/chardev-3.c b/20220411/chardev-3.c new file mode 100644 index 0000000000000000000000000000000000000000..516a074f806e3f600009b39ca912bf5ab69e3989 --- /dev/null +++ b/20220411/chardev-3.c @@ -0,0 +1,198 @@ +/* + * chardev.c: Creates a read-only char device that says how many times + * you've read from the dev file + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <asm/uaccess.h> /* for put_user */ + +MODULE_LICENSE("GPL"); + +/* + * Prototypes - this would normally go in a .h file + */ +int init_module(void); +void cleanup_module(void); +static int device_open(struct inode *, struct file *); +static int device_release(struct inode *, struct file *); +static ssize_t device_read(struct file *, char *, size_t, loff_t *); +static ssize_t device_write(struct file *, const char *, size_t, loff_t *); + +struct class *dev_Class; +struct device *chr_dev; + +#define SUCCESS 0 +#define DEVICE_NAME "chardev" /* Dev name as it appears in /proc/devices */ +#define BUF_LEN 80 /* Max length of the message from the device */ + +/* + * Global variables are declared as static, so are global within the file. + */ + +static int Major; /* Major number assigned to our device driver */ +static int Device_Open = 0; /* Is device open? + * Used to prevent multiple access to device */ +static char msg[BUF_LEN]; /* The msg the device will give when asked */ +static char *msg_Ptr; + +static struct file_operations fops = { + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release +}; + +/* + * This function is called when the module is loaded + */ +int init_module(void) +{ + Major = register_chrdev(0, DEVICE_NAME, &fops); + + if (Major < 0) { + printk(KERN_ALERT "Registering char device failed with %d\n", Major); + return Major; + } + + // Create module class + printk (KERN_INFO "Creating device class \"chardev\" ...\n"); + dev_Class = class_create (THIS_MODULE,DEVICE_NAME); + if( dev_Class == NULL) + { + printk (KERN_ALERT "Error! Class couldn't be created!\n"); + return 1; + } + printk (KERN_INFO "Class created!\n"); + // Create device in /dev/... + printk (KERN_INFO "Creating device\n"); + chr_dev = device_create (dev_Class, NULL, MKDEV (Major,0), NULL, DEVICE_NAME); + if (chr_dev == NULL) + { + printk( KERN_ALERT "Error! Device couldn't be created!\n" ); + return 1 ; + } + + return SUCCESS; +} + +/* + * This function is called when the module is unloaded + */ +void cleanup_module(void) +{ + printk(KERN_INFO "module chardev-4 cleanup\n"); + //Unregister the device + if (chr_dev) + { + printk(KERN_INFO "Unregister device ...\n"); + device_unregister(chr_dev); + printk(KERN_INFO "OK\n"); + } + + if (dev_Class) + { + printk(KERN_INFO "Unregister class ...\n"); + class_unregister(dev_Class); + printk(KERN_INFO "OK\n"); + } + + printk(KERN_INFO "Unregister Chardev ...\n"); + unregister_chrdev(Major, DEVICE_NAME); + printk(KERN_INFO "Device %s unregistered!\n", DEVICE_NAME); +} + +/* + * Methods + */ + +/* + * Called when a process tries to open the device file, like + * "cat /dev/mycharfile" + */ +static int device_open(struct inode *inode, struct file *file) +{ + static int counter = 0; + + if (Device_Open) + return -EBUSY; + + Device_Open++; + sprintf(msg, "I already told you %d times Hello world!\n", counter++); + msg_Ptr = msg; + try_module_get(THIS_MODULE); + + return SUCCESS; +} + +/* + * Called when a process closes the device file. + */ +static int device_release(struct inode *inode, struct file *file) +{ + Device_Open--; /* We're now ready for our next caller */ + + /* + * Decrement the usage count, or else once you opened the file, you'll + * never get get rid of the module. + */ + module_put(THIS_MODULE); + + return 0; +} + +/* + * Called when a process, which already opened the dev file, attempts to + * read from it. + */ +static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ + char *buffer, /* buffer to fill with data */ + size_t length, /* length of the buffer */ + loff_t * offset) +{ + /* + * Number of bytes actually written to the buffer + */ + int bytes_read = 0; + + /* + * If we're at the end of the message, + * return 0 signifying end of file + */ + if (*msg_Ptr == 0) + return 0; + + /* + * Actually put the data into the buffer + */ + while (length && *msg_Ptr) { + + /* + * The buffer is in the user data segment, not the kernel + * segment so "*" assignment won't work. We have to use + * put_user which copies data from the kernel data segment to + * the user data segment. + */ + put_user(*(msg_Ptr++), buffer++); + + length--; + bytes_read++; + } + + /* + * Most read functions return the number of bytes put into the buffer + */ + return bytes_read; +} + +/* + * Called when a process writes to dev file: echo "hi" > /dev/hello + */ +static ssize_t +device_write(struct file *filp, const char *buff, size_t len, loff_t * off) +{ + printk(KERN_ALERT "Sorry, this operation isn't supported.\n"); + return -EINVAL; +}