#include /* Needed by all modules */ #include /* Needed for KERN_INFO */ #include /* Needed for the macros */ #include #include /* for put_user */ #define DEVICE_NAME "one" static char outputchar = '1'; /* * module_param(foo, int, 0000) * The first param is the parameters name * The second param is it's data type * The final argument is the permissions bits, * for exposing parameters in sysfs (if non−zero). * e.g. change outputchar to 'a' with "echo "97" > /sys/module/one/parameter/outputchar" */ module_param(outputchar, byte, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ); MODULE_PARM_DESC(outputchar, "Character that will be output by the device file"); static int major; /* Major number assigned to our device driver */ static int device_opened = 0; /* * Prototypes − this would normally go in a .h file */ static int one_init(void); static void one_exit(void); static int one_open(struct inode *, struct file *); static int one_release(struct inode *, struct file *); static ssize_t one_read(struct file *, char *, size_t, loff_t *); static ssize_t one_write(struct file *, const char *, size_t, loff_t *); static struct file_operations fops = { .owner = THIS_MODULE, .read = one_read, .write = one_write, .open = one_open, .release = one_release }; static int __init one_init(void) { printk(KERN_INFO "Hello World from module one\n"); major = register_chrdev(0, DEVICE_NAME, &fops); if (major < 0) { printk(KERN_ALERT "Error in register_chrdev:%d\n", major); return major; } printk(KERN_INFO "I was assigned major number %d.\n", major); printk(KERN_INFO "Execute \"mknod /dev/one c %d 0\" to create device file.\n", major); return 0; } static void __exit one_exit(void) { // Unregister the device unregister_chrdev(major, DEVICE_NAME); printk(KERN_INFO "Goodbye World from module one\n"); } /* * Called when a process tries to open the device file, like * "cat /dev/mycharfile" */ static int one_open(struct inode *inode, struct file *file) { if (device_opened) return -EBUSY; device_opened++; return 0; } /* * Called when a process closes the device file. */ static int one_release(struct inode *inode, struct file *file) { device_opened--; /* We're now ready for our next caller */ return 0; } /* * Called when a process, which already opened the dev file, attempts to read from it. */ static ssize_t one_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; // Copying data to the buffer int i; for (i = 0; i < length; i++) { /* * 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(outputchar, buffer++); bytes_read++; } /* * Most read functions return the number of bytes put into the buffer * return 0 would signify end of file */ return bytes_read; } /* * Called when a process writes to dev file: echo "hi" > /dev/hello */ static ssize_t one_write(struct file *filp, const char *buff, size_t len, loff_t * off) { printk(KERN_ALERT "Sorry, write isn't supported.\n"); return -EINVAL; } module_init(one_init); module_exit(one_exit); MODULE_LICENSE("Some License"); MODULE_AUTHOR("Matthias Janetschek"); /* Who wrote this module? */ MODULE_DESCRIPTION("An example module"); /* What does this module do */