📄 my.c
字号:
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif//编译选项
#include <linux/proc_fs.h>//头文件
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/seq_file.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/slab.h>MODULE_LICENSE("GPL");//#define DEVICE_LENS 1024*1024;//设备缓冲区大小//函数原型声明ssize_t wxw_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t wxw_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
int wxw_open(struct inode *inode, struct file *filp);
int wxw_release(struct inode *inode, struct file *filp);
struct file_operations wxw_fops = {
.owner = THIS_MODULE,
.read = wxw_read,
.write = wxw_write,
.open = wxw_open,
.release = wxw_release,
};//file_operations结构体struct wxw_dev {//自定义设备结构
char * data;//用于保存数据
unsigned int size;// 缓冲区大小
unsigned int len;// 缓冲区已有长度
unsigned int start;// 起始数据偏移量
struct semaphore sem;// 信号量,用于互斥访问
struct cdev cdev;// 字符型设备结构
};
struct wxw_dev wxw_device;
dev_t dev_no = 0;
int wxw_init(void)// 初始化函数
{
int err=0;
cdev_init(&wxw_device.cdev, &wxw_fops);//初始化字符设备以及操作
wxw_device.cdev.owner = THIS_MODULE;//模块计数
wxw_device.cdev.ops = &wxw_fops;//指向自己的操作集
alloc_chrdev_region(&dev_no, 0, 1, "wxwdev");//动态分配一个设备号 字符设备注册
err = cdev_add(&wxw_device.cdev, dev_no, 1);//将字符设备添加到系统
if (err){
printk(KERN_NOTICE "Error %d adding device\n", err);
return -1;
}
else{
init_MUTEX(&wxw_device.sem); // 初始化互斥信号量
printk(KERN_NOTICE "Device Initilize success.\n");
return 0;
}
}
void wxw_exit(void)//将设备模块从系统中卸载
{
unregister_chrdev_region(dev_no, 1);//释放设备
cdev_del(&wxw_device.cdev);
}
int wxw_open(struct inode *inode, struct file *filp)// 打开设备
{
struct wxw_dev *dev;
dev = container_of(inode->i_cdev,struct wxw_dev,cdev); //通过container_of宏获得cdev结构的wxw_dev结构
filp->private_data = dev;//通过文件结构中的private_data数据段传递设备结构
if (down_interruptible(&dev->sem))// 访问互斥
return -ERESTARTSYS;
up(&dev->sem);//将访问信号释放 if(!dev->data){ // 缓冲区为空,重新分配空间
dev->data = (char *)kmalloc(1024, GFP_KERNEL);
memset(dev->data, 0, 1024);// 初始化参数
dev->size = 1024;
dev->len = dev->start = 0;
}
return 0;
}
int wxw_release(struct inode *inode, struct file *filp)// 关闭设备
{
return 0;
}//读取设备文件, read()使用,读取设备文件到用户缓冲区buf
//参数:文件结构指针filp, 用户缓冲区指针buf,要读出的字节数count, 当前文件指针f_posssize_t wxw_read(struct file *filp,char __user *buf, size_t count, loff_t *f_pos){ struct wxw_dev *dev=filp->private_data;// 读取数据
if (down_interruptible(&dev->sem))//访问互斥
return -ERESTARTSYS; if(dev->len>0){
if(count > dev->len-dev->start)//如果要读的字节数目超过可读数,则只读剩余字节
count = dev->len-dev->start;//获得实际可以读取的字节数
if(copy_to_user(buf,dev->data+dev->start,count)){
printk("reading error.\n"); }
else{
dev->start += count;//移动当前开始指针
if(dev->start>=dev->size){//超出范围重新定位
dev->start = 0;
dev->len = 0;}
}
}
else{
printk("error! device file is null.\n");//设备文件为空
goto end;
}
end:
up(&dev->sem);// 将访问信号释放
return 0;}//写设备文件, write()使用,将用户缓冲区数据写到设备文件
//参数:文件结构指针filp, 用户缓冲区指针buf, 写入字符数count, 当前文件指针f_pos
ssize_t wxw_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){ struct wxw_dev *dev=filp->private_data;// 读取数据 if (down_interruptible(&dev->sem))//访问互斥
return -ERESTARTSYS; if(dev->start+dev->len+count > dev->size){//超过剩余空间范围
memset(dev->data, 0, dev->size);//重新分配空间
if(count > dev->size)//超过文件总长度,则只写一部分
count = dev->size;
dev->start = dev->len = 0;
}
if(copy_from_user(dev->data+dev->len,buf,count)){
printk(KERN_NOTICE "writing error!\n");//写入失败
}
else{dev->len += count;}//更新已经使用的空间大小 up(&dev->sem);// 将访问信号释放
return 0;}module_init(wxw_init); //注册模块的初始化函数
module_exit(wxw_exit); // 注册模块的退出函数
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -