I will paste and anlaysis a small character device driver in this paragraph.
#include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/miscdevice.h> #include <asm/uaccess.h> #include <linux/unistd.h> #define DEVICE_NAME "wordcount2" #define TRUE -1 #define FALSE 0 static unsigned char mem[1024]; static int word_count = 0; static char is_spacewhite(char c) { if(c == ' ' || c == 9 || c == 13 || c == 10) return TRUE; else return FALSE; } static int get_world_count(const char *buf) { int n = 1; int i = 0; char c = ' '; char flag = 0; if(*buf == '\0') return 0; if(is_spacewhite(*buf) == TRUE) n--; for(; (c = *(buf +i)) != '\0'; i++) { if(flag == 1 && is_spacewhite(c) == FALSE) { flag = 0; } else if ( flag == 1 && is_spacewhite(c) == TRUE) { continue; } if(is_spacewhite(c) == TRUE) { n++; flag =1; } } if(is_spacewhite(*(buf + i -1)) == TRUE) n--; return n; } static ssize_t word_count_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { int ret; unsigned char tmp[4]; tmp[0] = word_count >> 24; tmp[1] = word_count >> 16; tmp[2] = word_count >> 8; tmp[3] = word_count ; ret = copy_to_user(buf, (void*) tmp, 4); printk(KERN_NOTICE "[wordcount2] read count : %d", (int) count + 1); printk(KERN_NOTICE "read wordcount success.\n"); return count; } static ssize_t word_count_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { int ret; ssize_t written = count; ret = copy_from_user(mem, buf, count); mem[count] = '\0'; word_count = get_world_count(mem); printk(KERN_NOTICE "[wordcount2] written count : %d", (int)word_count); printk(KERN_NOTICE "write wordcount success.\n"); return written; } static const struct file_operations misc_fops = { .owner = THIS_MODULE, .read = word_count_read, .write = word_count_write, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &misc_fops, }; static int word_count_init(void) { int ret; ret = misc_register(&misc); printk("word count init success.\n"); return ret; } static void word_count_exit(void) { misc_deregister(&misc); printk("word count exit success.\n"); } MODULE_LICENSE("Dual BSD/GPL"); module_init(word_count_init); module_exit(word_count_exit);
1、The entrance of device driver
When we are looking into a device driver, we should find the following entrance functions.
module_init(word_count_init);
module_exit(word_count_exit);
These two functions anounce the init and exit functions :
"word_count_init" and "word_count_exit".
Then we could check what effect of these two functions.
static int word_count_init(void) { int ret; ret = misc_register(&misc); printk("word count init success.\n"); return ret; } static void word_count_exit(void) { misc_deregister(&misc); printk("word count exit success.\n"); }
In a device driver, we must got a device.
The device "misc" is what we want.
When we insmod the module, this device would be register into the kernel.
2、Find out what mechanism the device support
------------------------------------------------------------------------------------------------------
I wanna add some messenge in this part :
In linux, we always talk about mechanism and policy.
Mechanism means that the methods of operation what we want.
Policy means that the methos of operation how can we use.
-----------------------------------------------------------------------------------------------------
In the device driver, we frequently support the mechanism instead of policy.
Means we create a device and give the methods of operation but never use it.
The miscdevice struct
static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &misc_fops, }; // #define DEVICE_NAME "wordcount2" // in include/linux/miscdevice.h #define MISC_DYNAMIC_MINOR 255
3、The callback operation functions
As we known, there are a lot of function interface in linux (open, close...)
In our device driver, we want to operate the device like the files too, so we must rebuild the functions.
static const struct file_operations misc_fops = { .owner = THIS_MODULE, .read = word_count_read, .write = word_count_write, }; // static ssize_t word_count_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
... // static ssize_t word_count_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
...
Summary :
When we build a device driver, I think we can follow the steps we analysis this driver.
1.Create the entrance function.
2.Register/Deregister the device in the entrance/exit function.
3.Build the real callback operation functions.