linux insmod处理流程,参数可以使用insmod加载

);

kfree(dptr->data);//释放一个scull_qset链表项指针的空间

dptr->data = NULL;//赋值为空

}

next = dptr->next;//准备下一个链表项

kfree(dptr);//释放除第一个节点(scull_dev dev)以外的所有节点!也就是释放所有的scull_qset结构体

}

dev->size = 0;

dev->quantum = scull_quantum;//量子的大小,量子的定义:每次申请分配内存的最小单位.

dev->qset = scull_qset;//量子集的大小

dev->data = NULL;

return 0;

}

//Open & Close

//Open函数关键是完成:分配并填写被置于filp->private_data里的数据结构!!

int scull_open(struct inode *inode,struct file *filp)

{

struct scull_dev *dev;

dev = container_of(inode->i_cdev,struct scull_dev,cdev);//通过指针struct cdev*来获得struct scull_dev*这个新指针!注意cdev数据是scull_dev结构体的成员变量名,inode->i_cdev是指向cdev变量类型的指针.

filp->private_data = dev;//for other methods

if((filp->f_flags & O_ACCMODE) == O_WRONLY)//只写的方式打开设备

{

if(down_interruptible(&dev->sem))//获取信号函数!返回值为0表示成功,非0表示失败

return -ERESTARTSYS;//

scull_trim(dev);//ignore errors 清零处理!

up(&dev->sem);//释放信号函数

}

return 0;

}

int scull_release(struct inode *inode,struct file *filp)//释放设备

{

return 0;

}

/*

*以下是scull模块中的一个沿链表前行得到正确scull_set指针的函数,将在read和write方法中被调用

*这个函数的实质是:如果已经存在这个scull_set,就返回这个scull_set的指针。如果不存在这个scull_set,一边沿链表为scull_set分配空间一边沿链表前行,直到所需要的scull_set 被分配到空间并初始化为止,就返回这个scull_set 的指针。

*/

struct scull_qset *scull_follow(struct scull_dev *dev,int n)

{

struct scull_qset *qs = dev->data;//指向第一个量子集

if(!qs)//如果在该索引之前的scull_qset结构不存在的话,为之分配内存

{

qs = dev->data = kmalloc(sizeof(struct scull_qset),GFP_KERNEL);

if(qs == NULL)

return NULL;//创建失败

memset(qs,0,sizeof(struct scull_qset));

}

while(n--)//接下来继续创建节点

{

if(!qs->next)//如果在该索引之前的scull_qset结构不存在的话,为之分配内存

{

qs->next = kmalloc(sizeof(struct scull_qset),GFP_KERNEL);

if(qs->next == NULL)

return NULL;//创建失败

memset(qs->next,0,sizeof(struct scull_qset));

}

qs = qs->next;

continue;

}

return qs;//正好返回第item个scull_qset链表项指针.

}

//read and write

//注意:scull设备的读和写函数仅限在1个量子集中进行!!!

ssize_t scull_read(struct file *filp,char __user *buf,size_t count,loff_t *f_pos)

{

struct scull_dev *dev = filp->private_data;//将设备数据赋值给变量dev,为提取设备数据做准备!

struct scull_qset *dptr;//the first listitem 第一个链表项

int quantum = dev->quantum,qset = dev->qset;

int itemsize = quantum * qset;//该链表项中有多少字节

int item,s_pos,q_pos,rest;

ssize_t retval = 0;//实际读取的字节数,初始化为0

//获取互斥信号

if(down_interruptible(&dev->sem))

return -ERESTARTSYS;

if(*f_pos >= dev->size)//超过了设备数据量,文件指针的位置已经不在设备中了!!

goto out;

if(*f_pos + count > dev->size)//确保提取设备数据的长度是有效的!!

count = dev->size - *f_pos;

//find listitem,qset index,and offset in the quantum

//在量子集中寻找链表项、qset索引以及quantum偏移量

//计算当前偏移对应第几个scull_qset、在scull_qset中data的下标、以及在*data指向的内存区域中的偏移;

item = (long)*f_pos / itemsize;//当前偏移对应第item个scull_qset

rest = (long)*f_pos % itemsize;

s_pos = rest / quantum;//qset索引,scull_qset中data的下标

q_pos = rest % quantum;//量子偏移量的位置,在*data指向的内存区域中的偏移

//遍历链表(如果没有链表则建立链表),直至到达正确的节点位置

//根据当前要操作的sucll_qset的索引item,返回其指针,如果在该索引之前的scull_qset结构不存在的话,为之分配内存

dptr = scull_follow(dev,item);//返回scull_qset*指针

if(dptr == NULL || !dptr->data || !dptr->data[s_pos])

goto out;

if(count > quantum - q_pos)//仅读至当前量子的末尾

count = quantum - q_pos;

//ulong copy_to_user(void __user *to,const void *from,ulong count);

//拷贝数据

if(copy_to_user(buf,dptr->data[s_pos]+q_pos,count))//返回0表示成功,非0表示失败

{

retval = -EFAULT;//无效的地址

goto out;

}

//重置偏移量

*f_pos += count;

retval = count;//返回读取的字节数count

out:

up(&dev->sem);//释放信号量

return retval;

}

//write 将用户空间的数据写入到设备!

ssize_t scull_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_pos)

{

struct scull_dev *dev = filp->private_data;//scull设备的信息,在scull_open函数中赋值给了filp->private_data

struct scull_qset *dptr;//准备保存写入的信息

int quantum = dev->quantum,qset = dev->qset;

int itemsize = quantum * qset;

int item,s_pos,q_pos,rest;

ssize_t retval = -ENOMEM;//写入数据的报错

if(down_interruptible(&dev->sem))//获取信号量函数

return -ERESTARTSYS;

//计算当前偏移对应第几个scull_qset、在scull_qset中data的下标、以及在*data指向的内存区域中的偏移;

//find listitem,qset index,offset in the quantum

item = (long)*f_pos / itemsize;//listitem 得到当前偏移对应第item个scull_qset

rest = (long)*f_pos % itemsize;//得到当前链表项的偏移量

s_pos = rest / quantum;//scull_qset中data的下标

q_pos = rest % quantum;//在*data指向的内存区域中的偏移

//follow the list up to the right position

dptr = scull_follow(dev,item);//根据当前要操作的sucll_qset的索引item,返回其指针,如果在该索引之前的scull_qset结构不存在的话,为之分配内存

if(dptr == NULL)//查找的链表项不存在,或者其他错误

goto out;

if(!dptr->data)//分配内存(地址空间),用作数据的存储!!

{

dptr->data = kmalloc(qset * sizeof(char *),GFP_KERNEL);//分配qset字节的空间,sizeof(char *)表示单位是字节

if(dptr->data == NULL)

goto out;

memset(dptr->data,0,qset * sizeof(char *));

}

if(!dptr->data[s_pos])//给qset分配空间,用作数据的存储.

{

dptr->data[s_pos] = kmalloc(quantum,GFP_KERNEL);

if(dptr->data[s_pos] == NULL)

goto out;

}

if(count > quantum - q_pos)//仅写至当前量子的末尾

count = quantum - q_pos;

//ulong copy_from_user(void *to,const void __user *from,ulong count);

//拷贝数据

if(copy_from_user(dptr->data[s_pos]+q_pos,buf,count))//返回0表示成功,非0表示失败

{

retval = -EFAULT;

goto out;

}

//重置偏移量

*f_pos += count;

retval = count;

/* update the size */

if (dev->size < *f_pos)

dev->size = *f_pos;

out:

up(&dev->sem);//释放信号量

return retval;

}

//文件操作结构

struct file_operations scull_fops = {

.owner = THIS_MODULE,

.read = scull_read,

.write = scull_write,

.open = scull_open,

.release = scull_release,

};

//为scull设备建立字符设备结构体

static void scull_setup_cdev(struct scull_dev *dev,int index)

{

int err,devno = MKDEV(scull_major,scull_minor + index);

cdev_init(&dev->cdev,&scull_fops);//初始化建立cdev和file_operations之间的连接,struct file_operations scull_fops

dev->cdev.owner = THIS_MODULE;//所属模块

err = cdev_add(&dev->cdev,devno,1);//注册设备,返回0表示成功,非0表示失败

if(err)

printk(KERN_NOTICE "Error %d adding scull%d",err,index);

}

//卸载模块的函数!

//scull_dev结构中*data指向一个有scull_qset的链表,链表中每个scull_qset结构中的**data指向一个指针数组,数组中每个指针指向一片内存区域,这些内存区域用来 存储数据。而scull_trim函数则使用循环的方式释放这些内存区域和scull_qset结构

void scull_cleanup_module(void)

{

int i;

dev_t devno = MKDEV(scull_major,scull_minor);

//卸载设备,清零处理

if(scull_devices)

{

for(i=0;i {

scull_trim(scull_devices+i);//调用scull_trim()函数释放每个设备中存储数据的内存区域

cdev_del(&scull_devices.cdev);//调用cde_del()函数移除该设备对应的字符设备结构

}

kfree(scull_devices);//释放设备scull_dev结构

}

unregister_chrdev_region(devno,scull_nr_devs);//释放设备号

}

//初始化模块的函数

int scull_init_module(void)

{

int result,i;

dev_t dev = 0;

//注册设备号

if(scull_major)//根据已知的主设备号,静态注册设备

{

dev = MKDEV(scull_major,scull_minor);//调用MKDEV宏定义,利用主次设备号得到dev_t

result = register_chrdev_region(dev,scull_nr_devs,"scull");

}

else //动态注册设备

{

result = alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,"scull");

scull_major = MAJOR(dev);

}

if(result < 0)//注册失败

{

printk(KERN_WARNING "scull:can't get major %d\n",scull_major);

return result;

}

//全局scull设备变量,struct scull_dev *scull_devices;

//为scull_nr_devs个设备分配scull_dev的内存空间,并清空

scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev),GFP_KERNEL);

if(!scull_devices)//返回0,表示分配内存失败

{

result = -ENOMEM;

goto fail;

}

//分配的内存空间初始化为0

memset(scull_devices,0,scull_nr_devs * sizeof(struct scull_dev));

//Initialize each device

//在循环中初始化每个scull_dev设备:初始化quantnum、qset等变量,初始化信号量、调用函数scull_setup_cdev()

for(i=0;i {

scull_devices.quantum = scull_quantum;

scull_devices.qset = scull_qset;

init_MUTEX(&scull_devices.sem);//互斥信号量,scull设备用不上.

scull_setup_cdev(&scull_devices,i);

}

return 0;

fail:

scull_cleanup_module();

return result;

}

module_init(scull_init_module);

module_exit(scull_cleanup_module);

MODULE_LICENSE("Dual BSD/GPL");

MODULE_AUTHOR("beyond2010-6-4");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值