copy_to_user()就是先将不可访问的地址变成可访问的
#include <linux/module.h> /*它定义了模块的 API、类型和宏(MODULE_LICENSE、MODULE_AUTHOR等等),所有的内核模块都必须包含这个头文件。*/ #include <linux/init.h> #include <linux/fs.h> //设备号相关函数 #include <linux/slab.h> //内存分配相关函数 #include <linux/types.h> #include <linux/kdev_t.h>//设备号相关函数 #include <linux/cdev.h>//字符设备头文件 #include <linux/module.h> #include <linux/uaccess.h>//copy_to_user等函数 struct char_dev { int size; char *data; struct cdev cdev;//内核中的字符设备 }; int major = 0; int minor = 0; struct char_dev char_devices; //open方法,一般是没啥用的 int char_open(struct inode *inode, struct file *filep) { int Major = 0; Major = MAJOR(inode->i_rdev); printk("open my_char_dev major: %d\n", Major); return 0; } //简单read方法,只有当要读取的数据大小不大于设备内存时才会读取 ssize_t char_read(struct file *filep, char __user *buf, size_t count, loff_t *offp) { ssize_t returnval = 0; printk("read start: char_dev_data:%s, count:%u, offp:%u\n", char_devices.data, (unsigned int)count, (unsigned int)*offp); if(count > char_devices.size){ count = char_devices.size; } if(copy_to_user(buf, char_devices.data, count)){ returnval = -EFAULT; goto out; } //*offp += count; returnval = count; out: return returnval; } //简单write方法,只有当要读取的数据大小不大于设备内存时才会写入 ssize_t char_write(struct file *filep, const char __user *buf, size_t count, loff_t *offp) { ssize_t returnval = 0; printk("write start: buf:%s, count:%u, offp:%u\n", buf, (unsigned int)count, (unsigned int)*offp); if(count > char_devices.size){ goto out; } if(copy_from_user(char_devices.data, buf, count)){ returnval = -EFAULT; goto out; } //*offp += count; returnval = count; printk("write end: char_dev_data:%s\n", char_devices.data); out: return returnval; } //release方法与open相对应 int char_release(struct inode *inode, struct file *filep) { printk("char release\n"); return 0; } struct file_operations char_fops = { .owner = THIS_MODULE, .open = char_open, .read = char_read, .write = char_write, .release = char_release, }; static void char_exit(void) //如果init函数中调用了该函数,则不应有 __exit { dev_t dev; printk("char device driver exit \n"); //释放设备号 dev = MKDEV(major, minor); unregister_chrdev_region(dev, 1); printk("release major %d\n", major); //释放内存 if(char_devices.data){ kfree(char_devices.data); } //从内核中删除字符设备 cdev_del(&(char_devices.cdev)); } static int __init char_init(void)//__init一个标记,表明是初始化函数 { //初始化的代码 dev_t dev; int result; printk("char device driver init \n"); //动态向内核申请设备号 result = alloc_chrdev_region(&dev, 0, 1, "my_char_dev"); major = MAJOR(dev); minor = MINOR(dev); printk("alloc major %d\n", major); if (result < 0) { printk(KERN_WARNING "my_char_dev: can't get major %d\n", major); return result; } //为设备分配一块内存 char_devices.size = 100; char_devices.data = (char*)kmalloc(char_devices.size, GFP_KERNEL); if (!char_devices.data) { result = -ENOMEM; goto fail; //不能直接退出函数,需要释放设备号 } //向内核中添加字符设备cdev cdev_init(&(char_devices.cdev), &char_fops); char_devices.cdev.owner = THIS_MODULE; char_devices.cdev.ops = &char_fops; result = cdev_add(&(char_devices.cdev), dev, 1); if((result < 0)) { printk(KERN_WARNING "Error %d adding my_char_dev\n", result); goto fail; } return 0; //成功 fail: char_exit(); return result; } MODULE_LICENSE("Dual BSD/GPL"); //当模块被加载时,执行moudle_init函数,该函数会调用初始化函数 module_init(char_init); //模块卸载时,调用,释放资源 module_exit(char_exit);