/***************************************************************************************************
scull模块加载卸载
实验步骤:
#make
#insmod scull2.ko
#gcc user2.c
#./a.out 看返回是成功还是失败即可。
#rmmod scull2
注,都在root权限下进行。 若make报找不到函数,是版本问题。需要换函数即可。
张永辉 2012年10月9日
***************************************************************************************************/
/***************************************************************************************************
用户使用函数
user2.c
***************************************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
int main(void)
{
int fd, num,ret;
fd = open("/dev/scull0", O_RDWR, S_IRUSR | S_IWUSR);
printf("fd = %d \n",fd);
if (fd != -1 )
{
printf("scull0 Device open secuss !\n");
close(fd);
}else
{
printf("scull0 Device open failure !\n");
}
return 0;
}
/***************************************************************************************************
scull2.h
***************************************************************************************************/
#ifndef _SCULL_H_
#define _SCULL_H_
/***************************************************************************************************
常量定义
***************************************************************************************************/
#ifndef SCULL_MAJOR
#define SCULL_MAJOR 0 //dynamic major by default 缺省的主设备号
#endif
#ifndef SCULL_NR_DEVS
#define SCULL_NR_DEVS 4 // scull0 1 2 3
#endif
#ifndef SCULL_QUANTUM //量子大小,单位字节
#define SCULL_QUANTUM 400
#endif
#ifndef SCULL_QSET //量子集大小
#define SCULL_QSET 100
#endif
/***************************************************************************************************
数据结构定义
***************************************************************************************************/
/* scull 数据模型
是一个结构,见下表。
scull_qset是一个链表结构
一个指针指向下一个结构。
一个指针指向一个量子集。
量子集是n=1000个指针的数组,每个指针指向一块内存,此内存有m=4000字节大。一块内存即是以个量子。
两模型如下:*/
struct scull_qset
{
void **data;
struct scull_qset *next;
};
struct scull_dev {
struct scull_qset *data; // Pointer to first quantum set 指向第一个 scull_qset结构
int quantum; // the current quantum size 一个量子的大小, 默认4000
int qset; // the current array size 一个量子集的个数,默认1000
unsigned long size; // amount of data stored here 保存了的数据总数
unsigned int access_key; // used by sculluid and scullpriv
struct semaphore sem; // mutual exclusion semaphore 信号量
struct cdev cdev; // Char device structure 设备
};
/***************************************************************************************************
全局变量声明
***************************************************************************************************/
//声明在 scull.c 的全局变量
/***************************************************************************************************
函数声明
***************************************************************************************************/
//-------------------------------file_operations 操作函数声明---------------------------------------
//-------------------------------供调用的函数声明-----------------------------------------------
//**************************************************************************************************
#endif
/***************************************************************************************************
scull2.c
***************************************************************************************************/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h> /* everything... */
#include <linux/kernel.h>
#include <asm/uaccess.h> /* copy_*_user */
#include <linux/cdev.h> //cdev
#include <linux/types.h> /* size_t */
#include <linux/slab.h> /* kmalloc() */
#include <linux/device.h> //class_create
//#include <linux/moduleparam.h>
#include <linux/errno.h> /* error codes */
#include <linux/proc_fs.h>
//#include <linux/fcntl.h> /* O_ACCMODE */
//#include <linux/seq_file.h>
//#include <asm/system.h> /* cli(), *_flags */
#include "scull2.h"
MODULE_LICENSE("Dual BSD/GPL");
/***************************************************************************************************
全局变量声明
***************************************************************************************************/
dev_t scull_num; // 设备号
int scull_major = SCULL_MAJOR; //主设备号 scull.h #define=0
int scull_minor = 0; //次设备号
int scull_quantum = SCULL_QUANTUM; //量子大小 = 400
int scull_qset = SCULL_QSET; //量子集大小 = 100
struct scull_dev *scull_devices=NULL; //在 scull_init_module 分配的设备存储区
static struct class *scull_class=NULL;
/***************************************************************************************************
file_operations 函数实现
***************************************************************************************************/
static ssize_t scull_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
return 0;
}
static ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
return 0;
}
//初始化设备的file_operations结构体,必须的。 此结构
struct file_operations scull_fops =
{
.read = scull_read,
.write = scull_write,
};
/***************************************************************************************************
注册和注销模块
***************************************************************************************************/
static int scull_init_module(void)
{
int result;
printk(KERN_WARNING "scull2 initing ... \n");
//------------------注册设备号:scull2----------------------------------------------------------
result = alloc_chrdev_region(&scull_num, scull_minor, 1,"scull2");
if(result < 0)
{
printk(KERN_WARNING "alloc_chrdev_region error \n");
return result;
}
scull_major = MAJOR(scull_num);
printk(KERN_WARNING "scull_num = %d \n",scull_num);
printk(KERN_WARNING "scull_major = %d \n",scull_major);
//分配存储空间给scull_devices, 也给dev分配了空间。
scull_devices = kmalloc( 1*sizeof(struct scull_dev), GFP_KERNEL);
if (!scull_devices)
{
printk(KERN_WARNING "kmalloc scull_devices error");
result = -ENOMEM;
goto err1;
}
memset(scull_devices, 0, 1 * sizeof(struct scull_dev)); //初始化空间
//------------------初始化cdev并添加到系统------------------------------------------------------
cdev_init(&scull_devices->cdev, &scull_fops);
scull_devices->cdev.owner = THIS_MODULE;
result = cdev_add(&scull_devices->cdev, scull_num, 1);
if (result)
{
printk(KERN_NOTICE "cdev_add error! \n");
goto err2;
}
//-------------------创建设备节点---------------------------------------------------------------
scull_class = class_create(THIS_MODULE, "scull_class2");//在/sys目录下建立了一个scull_class2的目录
if (IS_ERR(scull_class))
{
printk(KERN_INFO "gvar_class2 create error\n");
goto err3;
//class_destroy(gvar_class);
}
class_device_create(scull_class,NULL,scull_num,NULL,"scull" "%d", MINOR(scull_num));
if(0)
{ printk(KERN_INFO "device_create error\n");
goto err4;
//class_device_destroy()
}
printk(KERN_INFO "create device suess !\n");
return 0;
//------------------失败处理:所有操作将回退----------------------------------------------------
err4:
class_destroy(scull_class);
err3:
cdev_del(&scull_devices->cdev);
err2:
kfree(scull_devices);
err1:
unregister_chrdev_region(scull_num,1);
return result;
}
static void scull_cleanup_module(void)
{
class_device_destroy(scull_class,scull_num);
if(scull_class != NULL)
{
class_device_destroy(scull_class, scull_num);
class_destroy(scull_class);
}
if(&scull_devices->cdev != NULL)
{
cdev_del(&scull_devices->cdev);
}
unregister_chrdev_region(scull_num,1);
printk(KERN_WARNING "scull goodbye! \n");
}
module_init(scull_init_module);
module_exit(scull_cleanup_module);
obj-m := scull2.o #模块编译的目标必须以obj-m 这样的形式指出
KERNELDIR ?= /lib/modules/$(shell uname -r)/build #模块的编译必须指定内核源代码的路径
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules #本行开头必须使用 Tab 键
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clearn:
rm -rf *.o *.ko *mod.o [mM]odule* .*.cmd .tmp_versions