课堂实践3
简单Memory驱动程序
//memory.c 文件
/* Necessary includes for device drivers */
#include <linux/init.h>
//#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/cdev.h> //linux2.6设备驱动的头文件,包含cdev_alloc、cdev_init、cdev_add和cdev_del函数的定义
#include <linux/device.h> //class_create(),class_destroy(),class_device_create(),class_device_destroy()函数定义在device.h头文件中
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
MODULE_LICENSE("Dual BSD/GPL");
/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);
/* Structure that declares the usual file */
/* access functions */
struct file_operations memory_fops = {
.owner = THIS_MODULE,
.read = memory_read,
.write = memory_write,
.open = memory_open,
.release = memory_release
};
/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);
/* Global variables of the driver */
/* Major number */
//int memory_major = 360;
/* 设备号 */
dev_t dev_num;
static struct cdev *pcdev;
struct class *myclass=NULL;
/* Buffer to store data */
char *memory_buffer;
/* ------------------<memory init module>开始--------------------- */
//该段代码使用了kmalloc函数。这个函数工作在内核空间,用于为该驱动程序的缓冲区分配内存。
//它和我们熟悉的malloc函数很相似。最后,如果注册主设备号或者分配内存失败,模块将退出。
int memory_init(void)
{
int result = -1;
/* Registering device */
//result = register_chrdev(memory_major, "memory", &memory_fops);
//动态申请一个 字符设备内存。
pcdev = cdev_alloc();
//字符设备初始化
cdev_init(pcdev, &memory_fops);
//动态注册一个字符设备
result = alloc_chrdev_region(&dev_num, 0, 1, "my_memory"); //次设备号从0开始,注册1个设备,设备名为my_memory。
printk("<0>major = %d, minor = %d\n", MAJOR(dev_num), MINOR(dev_num));
pcdev->owner = THIS_MODULE;
//向系统中 添加一个字符设备
cdev_add(pcdev, dev_num, 1);
//创建设备文件
myclass=class_create(THIS_MODULE, "test");
//利用udev创建设备文件创建设备文件,linux2.26及以后的版本,可能用device_create()
//class_device_create(myclass,NULL,dev_num,NULL,"my_memory"); //error: implicit declaration of function 'class_device_create'
device_create(myclass, NULL, dev_num, NULL,"my_memory");
printk("<0>test_init ok,device create ok\n");
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 1);
printk("<0>Inserting memory module\n");
return 0;
fail:
memory_exit();
return result;
}
/* ------------------<memory init module>结束--------------------- */
/* ------------------<memory exit module>开始--------------------- */
//为了完全的卸载该驱动,缓冲区也需要通过该函数进行释放。
void memory_exit(void)
{
/* Freeing the major number */
//unregister_chrdev(memory_major, "memory");
// 从系统中删除字符设备
cdev_del(pcdev);
//注销字符设备
unregister_chrdev_region(dev_num, 1);
//删除/dev目录下相应的设备文件,linux2.26及以后的版本,可能用device_destroy()
//class_device_destroy(myclass,dev_num); //error: implicit declaration of function 'class_device_destroy'
//device_destroy(myclass); //error: too few arguments to function 'device_destroy'
device_destroy(myclass, dev_num);
/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}
printk("<0>Removing memory module\n");
}
/* ------------------<memory exit module>结束--------------------- */
/* ------------------<memory open>开始--------------------- */
//当设备文件被打开后,通常就需要初始化驱动的各个变量,对设备进行复位。但在本例中,这些操作都没进行。
int memory_open(struct inode *inode, struct file *filp)
{
/* Success */
return 0;
}
/* ------------------<memory open>结束--------------------- */
/* ------------------<memory release>开始--------------------- */
//当设备文件关闭后,通常需要释放该设备使用的内存,释放各种操作该设备相关的变量。但是,为简单起见,例子里没有进行这些操作。
int memory_release(struct inode *inode, struct file *filp)
{
/* Success */
return 0;
}
/* ------------------<memory release>结束--------------------- */
/* ------------------<memory read>开始--------------------- */
//本例中,memory_read函数通过copy_to_user函数从驱动的缓冲区(memory_buffer)向用户空间传送一个简单的字节。
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
unsigned long ret;
/* Transfering data to user space */
ret = copy_to_user(buf,memory_buffer,1);
/* Changing reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
}
else {
return 0;
}
}
/* ------------------<memory read>结束--------------------- */
/* ------------------<memory write>开始--------------------- */
//本例中的memory_write函数,它有如下几个参数:
//一个file结构;
//buf,一个缓冲区,用户空间函数fwrite将向该该缓冲区写数据;
//count,统计将传送的字节数的计数器,和用户空间函数fwrite的计数器有相同的数值;
//最后是f_pos,指示从哪里开始写文件。。
ssize_t memory_write( struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
//char *tmp;
unsigned long ret;
//tmp=buf+count-1;
ret = copy_from_user(memory_buffer,buf+count-1, 1);
return 1;
}
/* ------------------<memory write>结束--------------------- */
编译的的时候,开发板可以正常加载,虚拟机里面red hat 5.5下面编译没问题,但是加载模块,虚拟机会卡死,暂时没解决,可能是 main函数 动态创建设备的问题,先不搞了, 留着。