//如下是一段增加了open和release的scull代码,还不完整,只是编译通过,暂时保存到这里,一会儿再修改。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
//命令行参数
static char *whom="world";
static int howmany=1;
module_param(howmany,int,S_IRUGO);
module_param(whom,charp,S_IRUGO);
//命令行参数结束
//申请设备号需要的设备编号,主设备号,次设备号,申请结果
dev_t dev;
unsigned int scull_nr_devs=4;
unsigned int scull_major=0; //全局变量,用来保存选择的主设备号
unsigned int scull_minor=0; //保存次设备号
int result;
//申请设备号结束
loff_t scull_llseek(struct file *,loff_t, int);
ssize_t scull_read(struct file *,char __user *,size_t,loff_t *);
ssize_t scull_write(struct file *,const char __user *,size_t,loff_t *);
int scull_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
int scull_open(struct inode *,struct file *);
int scull_release(struct inode *,struct file *);
struct scull_cdev{
struct scull_qset *data;//指向第一个量子集的指针
int quantum;//当前量子的大小
int qset;//当前数组的大小
unsigned long size;//保存其中的数据总量
unsigned int access_key;//由sculluid和scullpriv使用
struct semaphore sem;//互斥信号量
struct cdev cdev;//字符设备结构
};
struct scull_cdev my_scull_cdev; //一个scull_cdev设备
struct file_operations scull_fops={
.owner=THIS_MODULE,
.llseek=scull_llseek,
.read=scull_read,
.write=scull_write,
.ioctl=scull_ioctl,
.open=scull_open,
.release=scull_release }; //fops
static void scull_setup_cdev(struct scull_cdev *dev,int index); //完成将字符设备和设备编号连接起来
void scull_cdev_del(struct scull_cdev *dev); //注销字符设备
struct scull_qset;
//scull_trim方法实现
int scull_trim(struct scull_cdev *dev);
static int hello_init(void)//装载时运行
{
int i;
for(i=0;i<howmany;i++)
printk(KERN_ALERT "hello %s./n",whom);//printk()内核态的输出函数;KERN_ALERT,显示的优先级
if(scull_major) //若默认的不是0,则
{
dev=MKDEV(scull_major,scull_minor); //通过主设备号和次设备号得到设备编号
result=register_chrdev_region(dev,scull_nr_devs, "scull"); //申请该设备编号
}
else //若默认的主设备号是0,则
{
result=alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,"scull"); //动态申请设备编号
scull_major=MAJOR(dev); //通过设备编号得到主设备号
scull_minor=MINOR(dev);
}
if(result<0) //申请设备编号失败
{
printk(KERN_WARNING "scull: can't get major %d/n",scull_major);
return result;
}
//将设备编号和字符设备关联
scull_setup_cdev(&my_scull_cdev,0);
return 0;
}
static void hello_exit(void)//卸载时运行
{
printk(KERN_ALERT "Goodbye,cruel world. My first drivers is over!/n");
scull_cdev_del(&my_scull_cdev);
unregister_chrdev_region(dev,scull_nr_devs);
}
static void scull_setup_cdev(struct scull_cdev *dev,int index)
{
int err,devno=MKDEV(scull_major,scull_minor+index);
cdev_init(&dev->cdev,&scull_fops);
dev->cdev.ops=&scull_fops;
err=cdev_add(&dev->cdev,devno,1);
if(err)
printk(KERN_NOTICE "Error %d adding scull %d",err,index);
}
//注销字符设备
void scull_cdev_del(struct scull_cdev *dev)
{
cdev_del(&dev->cdev);
}
loff_t scull_llseek(struct file *f,loff_t l, int n){loff_t t=0;return t;}
ssize_t scull_read(struct file *f,char __user *s,size_t n,loff_t *l){ssize_t t=0;return t;}
ssize_t scull_write(struct file *f,const char __user *s,size_t n,loff_t *l){ssize_t t=0;return t;}
int scull_ioctl(struct inode *i,struct file *f,unsigned int n,unsigned long l){return 1;}
int scull_open(struct inode *inode,struct file *filp)
{
struct scull_cdev *dev;
dev=container_of(inode->i_cdev,struct scull_cdev,cdev);//从inode->i_cdev得到scull_dev的地址
filp->private_data=dev;//为其它的方法
//下面设置:若以写方式打开设备,则将它的长度截断为0
if((filp->f_flags & O_ACCMODE)==O_WRONLY)
{
scull_trim(dev);//一个用于截短的宏
}
return 0;
}
int scull_release(struct inode *i,struct file *f)
{
return 0;
}
struct scull_qset
{
void **data;
struct scull_qset *next;
};
//scull_trim方法实现
int scull_trim(struct scull_cdev *dev)
{
struct scull_qset *next,*dptr;
int qset=dev->qset;
int i;
int scull_quantum=0;//自己加,因为原函数找不到
int scull_qset=0;//自己加,因为原函数找不到
for(dptr=dev->data;dptr;dptr=next)
{
if(dptr->data)
{
for(i=0;i<qset;i++)
kfree(dptr->data[i]);
kfree(dptr->data);
dptr->data=NULL;
}
next=dptr->next;
kfree(dptr);
}
dev->size=0;
dev->quantum=scull_quantum;
dev->qset=scull_qset;
dev->data=NULL;
return 0;
}
//声明init和exit方法
module_init(hello_init); //指定装载时调用的函数
module_exit(hello_exit); //指定卸载时调用的函数
//声明符合GPL
MODULE_LICENSE("Dual BSD/GPL");//告诉内核,该模块才用了自由许可证,否则转载时会遭到内核抱怨
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kernel.h>
//命令行参数
static char *whom="world";
static int howmany=1;
module_param(howmany,int,S_IRUGO);
module_param(whom,charp,S_IRUGO);
//命令行参数结束
//申请设备号需要的设备编号,主设备号,次设备号,申请结果
dev_t dev;
unsigned int scull_nr_devs=4;
unsigned int scull_major=0; //全局变量,用来保存选择的主设备号
unsigned int scull_minor=0; //保存次设备号
int result;
//申请设备号结束
loff_t scull_llseek(struct file *,loff_t, int);
ssize_t scull_read(struct file *,char __user *,size_t,loff_t *);
ssize_t scull_write(struct file *,const char __user *,size_t,loff_t *);
int scull_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
int scull_open(struct inode *,struct file *);
int scull_release(struct inode *,struct file *);
struct scull_cdev{
struct scull_qset *data;//指向第一个量子集的指针
int quantum;//当前量子的大小
int qset;//当前数组的大小
unsigned long size;//保存其中的数据总量
unsigned int access_key;//由sculluid和scullpriv使用
struct semaphore sem;//互斥信号量
struct cdev cdev;//字符设备结构
};
struct scull_cdev my_scull_cdev; //一个scull_cdev设备
struct file_operations scull_fops={
.owner=THIS_MODULE,
.llseek=scull_llseek,
.read=scull_read,
.write=scull_write,
.ioctl=scull_ioctl,
.open=scull_open,
.release=scull_release }; //fops
static void scull_setup_cdev(struct scull_cdev *dev,int index); //完成将字符设备和设备编号连接起来
void scull_cdev_del(struct scull_cdev *dev); //注销字符设备
struct scull_qset;
//scull_trim方法实现
int scull_trim(struct scull_cdev *dev);
static int hello_init(void)//装载时运行
{
int i;
for(i=0;i<howmany;i++)
printk(KERN_ALERT "hello %s./n",whom);//printk()内核态的输出函数;KERN_ALERT,显示的优先级
if(scull_major) //若默认的不是0,则
{
dev=MKDEV(scull_major,scull_minor); //通过主设备号和次设备号得到设备编号
result=register_chrdev_region(dev,scull_nr_devs, "scull"); //申请该设备编号
}
else //若默认的主设备号是0,则
{
result=alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,"scull"); //动态申请设备编号
scull_major=MAJOR(dev); //通过设备编号得到主设备号
scull_minor=MINOR(dev);
}
if(result<0) //申请设备编号失败
{
printk(KERN_WARNING "scull: can't get major %d/n",scull_major);
return result;
}
//将设备编号和字符设备关联
scull_setup_cdev(&my_scull_cdev,0);
return 0;
}
static void hello_exit(void)//卸载时运行
{
printk(KERN_ALERT "Goodbye,cruel world. My first drivers is over!/n");
scull_cdev_del(&my_scull_cdev);
unregister_chrdev_region(dev,scull_nr_devs);
}
static void scull_setup_cdev(struct scull_cdev *dev,int index)
{
int err,devno=MKDEV(scull_major,scull_minor+index);
cdev_init(&dev->cdev,&scull_fops);
dev->cdev.ops=&scull_fops;
err=cdev_add(&dev->cdev,devno,1);
if(err)
printk(KERN_NOTICE "Error %d adding scull %d",err,index);
}
//注销字符设备
void scull_cdev_del(struct scull_cdev *dev)
{
cdev_del(&dev->cdev);
}
loff_t scull_llseek(struct file *f,loff_t l, int n){loff_t t=0;return t;}
ssize_t scull_read(struct file *f,char __user *s,size_t n,loff_t *l){ssize_t t=0;return t;}
ssize_t scull_write(struct file *f,const char __user *s,size_t n,loff_t *l){ssize_t t=0;return t;}
int scull_ioctl(struct inode *i,struct file *f,unsigned int n,unsigned long l){return 1;}
int scull_open(struct inode *inode,struct file *filp)
{
struct scull_cdev *dev;
dev=container_of(inode->i_cdev,struct scull_cdev,cdev);//从inode->i_cdev得到scull_dev的地址
filp->private_data=dev;//为其它的方法
//下面设置:若以写方式打开设备,则将它的长度截断为0
if((filp->f_flags & O_ACCMODE)==O_WRONLY)
{
scull_trim(dev);//一个用于截短的宏
}
return 0;
}
int scull_release(struct inode *i,struct file *f)
{
return 0;
}
struct scull_qset
{
void **data;
struct scull_qset *next;
};
//scull_trim方法实现
int scull_trim(struct scull_cdev *dev)
{
struct scull_qset *next,*dptr;
int qset=dev->qset;
int i;
int scull_quantum=0;//自己加,因为原函数找不到
int scull_qset=0;//自己加,因为原函数找不到
for(dptr=dev->data;dptr;dptr=next)
{
if(dptr->data)
{
for(i=0;i<qset;i++)
kfree(dptr->data[i]);
kfree(dptr->data);
dptr->data=NULL;
}
next=dptr->next;
kfree(dptr);
}
dev->size=0;
dev->quantum=scull_quantum;
dev->qset=scull_qset;
dev->data=NULL;
return 0;
}
//声明init和exit方法
module_init(hello_init); //指定装载时调用的函数
module_exit(hello_exit); //指定卸载时调用的函数
//声明符合GPL
MODULE_LICENSE("Dual BSD/GPL");//告诉内核,该模块才用了自由许可证,否则转载时会遭到内核抱怨