Created
February 27, 2019 13:11
-
-
Save vbarboza/3b5840b617038e2171ee2c78dfd66df4 to your computer and use it in GitHub Desktop.
Exploring Beagle Bone character device example.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/init.h> // Macros used to mark up functions e.g. __init __exit | |
#include <linux/module.h> // Core header for loading LKMs into the kernel | |
#include <linux/device.h> // Header to support the kernel Driver Model | |
#include <linux/kernel.h> // Contains types, macros, functions for the kernel | |
#include <linux/fs.h> // Header for the Linux file system support | |
#include <linux/uaccess.h> // Required for the copy to user function | |
#define DEVICE_NAME "ebbchar" ///< The device will appear at /dev/ebbchar using this value | |
#define CLASS_NAME "ebb" ///< The device class -- this is a character device driver | |
MODULE_LICENSE("GPL"); ///< The license type -- this affects available functionality | |
MODULE_AUTHOR("Derek Molloy"); ///< The author -- visible when you use modinfo | |
MODULE_DESCRIPTION("A simple Linux char driver for the BBB"); ///< The description -- see modinfo | |
MODULE_VERSION("0.1"); ///< A version number to inform users | |
static int majorNumber; ///< Stores the device number -- determined automatically | |
static char message[256] = {0}; ///< Memory for the string that is passed from userspace | |
static short size_of_message; ///< Used to remember the size of the string stored | |
static int numberOpens = 0; ///< Counts the number of times the device is opened | |
static struct class* ebbcharClass = NULL; ///< The device-driver class struct pointer | |
static struct device* ebbcharDevice = NULL; ///< The device-driver device struct pointer | |
// The prototype functions for the character driver -- must come before the struct definition | |
static int dev_open(struct inode *, struct file *); | |
static int dev_release(struct inode *, struct file *); | |
static ssize_t dev_read(struct file *, char *, size_t, loff_t *); | |
static ssize_t dev_write(struct file *, const char *, size_t, loff_t *); | |
static struct file_operations fops = | |
{ | |
.open = dev_open, | |
.read = dev_read, | |
.write = dev_write, | |
.release = dev_release, | |
}; | |
static int __init ebbchar_init(void){ | |
printk(KERN_INFO "EBBChar: Initializing the EBBChar LKM\n"); | |
// Try to dynamically allocate a major number for the device -- more difficult but worth it | |
majorNumber = register_chrdev(0, DEVICE_NAME, &fops); | |
printk(KERN_INFO "EBBChar: registered correctly with major number %d\n", majorNumber); | |
// Register the device class | |
ebbcharClass = class_create(THIS_MODULE, CLASS_NAME); | |
printk(KERN_INFO "EBBChar: device class registered correctly\n"); | |
// Register the device driver | |
ebbcharDevice = device_create(ebbcharClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); | |
printk(KERN_INFO "EBBChar: device class created correctly\n"); // Made it! device was initialized | |
return 0; | |
} | |
static void __exit ebbchar_exit(void){ | |
device_destroy(ebbcharClass, MKDEV(majorNumber, 0)); // remove the device | |
class_unregister(ebbcharClass); // unregister the device class | |
class_destroy(ebbcharClass); // remove the device class | |
unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number | |
printk(KERN_INFO "EBBChar: Goodbye from the LKM!\n"); | |
} | |
static int dev_open(struct inode *inodep, struct file *filep){ | |
numberOpens++; | |
printk(KERN_INFO "EBBChar: Device has been opened %d time(s)\n", numberOpens); | |
return 0; | |
} | |
static ssize_t dev_read(struct file *filep, char *buffer, size_t len, loff_t *offset){ | |
int error_count = 0; | |
error_count = copy_to_user(buffer, message, size_of_message); | |
} | |
static ssize_t dev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset){ | |
sprintf(message, "%s(%zu letters)", buffer, len); // appending received string with its length | |
size_of_message = strlen(message); // store the length of the stored message | |
printk(KERN_INFO "EBBChar: Received %zu characters from the user\n", len); | |
return len; | |
} | |
static int dev_release(struct inode *inodep, struct file *filep){ | |
printk(KERN_INFO "EBBChar: Device successfully closed\n"); | |
return 0; | |
} | |
module_init(ebbchar_init); | |
module_exit(ebbchar_exit); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment