模块描述
将30个字节的内存空间模仿成设备文件。每次读写不超过30个字节。
模块加载成功之后,需建立设备文件
mknod /dev/mydev c 231 0
模块代码
#include <linux/types.h> //dev_t,MAJOR,MINOR,MKDEV #include <linux/fs.h> //file_operations,struct file,struct indoe,register //unregister_chrdev,register/alloc/unregister_chrdev_regino, #include <linux/cdev.h> //cdev_alloc,cdev_init,cdev_add,cdev_del #include <linux/kernel.h> //container_of #include <linux/slab.h> //kfree,kmalloc #include <linux/errno.h> //error code #include <linux/module.h> //MODULE_LICENSE,... #include <linux/platform_device.h> //struct platform_device,struct platform_driver #include <asm/uaccess.h> //copy_from_user,copy_to_user #define MYMAJOR 231 //静态分配设备号 MODULE_LICENSE("GPL"); MODULE_AUTHOR("WGY"); MODULE_DESCRIPTION("MY_FIRST_MODULE"); unsigned int count=0; //记录打开设备的次数 dev_t devn; //设备号 struct my_cdev { char kerbuf[30]; //分配30个字节的内存空间 struct cdev cd; //如果这里实例化cd为指针,记得使用前为cd分配空间 }; struct my_cdev ex_cdev; //设备结构 int simple_open(struct inode * inode,struct file * filp) { if(count>=1) //设备已被打开 { printk(KERN_ERR "Device is in use."); return -EBUSY; } count++; //设备初次打开,加一 return 0; } int simple_release(struct inode * inode,struct file * filp) { count--; //关闭设备,计数减一 return 0; } ssize_t simple_read(struct file * filp,char __user *usrbuf,size_t count,loff_t * f_pos) { if(count>30) //用户要求读出字符总数超过30个字节 { printk(KERN_WARNING "Over the max length of the kernel array"); return -1; } //拷贝内核空间的数据到用户空间 if(copy_to_user(usrbuf,ex_cdev.kerbuf,count)) { return -EFAULT; } return count; } ssize_t simple_write(struct file * filp,const char __user *usrbuf,size_t count,loff_t * f_pos) { if(count>30) //用户写入字符总数超过30个字节 { printk(KERN_WARNING "over the max length of the kernel array"); return -1; } //拷贝用户空间的数据到内核空间 if(copy_from_user(ex_cdev.kerbuf,usrbuf,count)) { return -EFAULT; } return 0; } struct file_operations simple_ops= { .owner=THIS_MODULE, .read=simple_read, .write=simple_write, .open=simple_open, .release=simple_release, }; int __init simple_init_module(void) { int ret,result; devn=MKDEV(MYMAJOR,0); //获取设备号 ret=register_chrdev_region(devn,1,"/dev/mydev"); //起始设备号,设备个数,设备名 if(ret<0) { printk(KERN_WARNING "failed to alloc a dev number"); return ret; } //直接涉及内核的操作 cdev_init(&ex_cdev.cd,&simple_ops); ex_cdev.cd.owner=THIS_MODULE; result = cdev_add (&ex_cdev.cd, devn, 1); if(result) { printk(KERN_NOTICE "Error %d adding DEMO ", result); } printk("success ,good!"); return 0; } void __exit simple_cleanup_module(void) { cdev_del(&ex_cdev.cd); unregister_chrdev_region(devn,1); printk("simple_cleanup_module"); } module_init(simple_init_module); module_exit(simple_cleanup_module);
应用
#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> int main() { int fd,ret; char buf[30]={' '}; fd=open("/dev/mydev",O_RDWR|O_NONBLOCK|O_NOCTTY); if(fd<0) { printf("fail to open.."); exit(1); } ret=write(fd,"hello",5); //向设备写入5个字符 if(ret<0) { printf("fail to write.. "); exit(1); } ret=read(fd,buf,5); //从设备读入5个字符 if(ret<0) { printf("fail to read.."); exit(1); } printf("string=%s ",buf); //打印从设备读到的字符 close(fd); //关闭打开的文件 return 0; }