您的位置:首页 > 运维架构 > Linux

linux驱动学习-4th

2014-03-13 22:24 169 查看
接下来安装LDD3的惯例写一个global_mem 的字符驱动程序,这次实现目标,分配一个4k大小的内存实现读写操作。

采用class结构体用于mdev(udev)自动创建设备结点。

/*最简单字符类global_mem驱动模版*/
/*[0].必须的头文件*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>	/* printk() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/errno.h>	/* error codes */
#include <linux/types.h>	/* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h>	/* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <asm/system.h>		/* cli(), *_flags */
#include <asm/uaccess.h>	/* copy_*_user */
/*********************************************************************/
#define __DEBUG__
#ifdef __DEBUG__
#define DEBUG(format,...) printk("[%05d] ""%s:""%s. "  format "",__LINE__, __FILE__, __FUNCTION__,  ##__VA_ARGS__)
#else
#define DEBUG(format,...)
#endif
/*********************************************************************/
/*[1].定义设备名*/
#define DEVICE_NAME "global_mem_dev"
/*[2].定义主设备号 0:动态分配 (!0):手动分配找一个kernel没有使用的*/
#define DEVICE_MAJOR 0
/*[3].定义次设备号个数*/
#define MINOR_COUNT 1
/*[4].定义自己的设备global_mem_dev结构体(包含了基本的cdev字符设结构体)*/
struct global_mem_dev
{
struct cdev cdev;   /*c_dev结构体*/
unsigned char mem[4*1024];
};
/*********************************************************************/
/*[5].定义一个全局变量记录主设备号*/
static int major = DEVICE_MAJOR;
/*[6].定义起始次设备号*/
static int first_minor = 0;
/*[7].定义次设备号个数*/
static int minor_count = MINOR_COUNT;
/*[8].定义一个global_mem_dev结构体指针,其实是一个数组*/
struct global_mem_dev *global_mem_dev_array = NULL;
/*[9].定义一个class结构体用于mdev自动创建设备结点*/
struct class *global_mem_dev_class;
/*********************************************************************/
static int global_mem_dev_open(struct inode *inode,
struct file *filep);
static int global_mem_dev_release(struct inode *inode,
struct file *filep);
static ssize_t global_mem_dev_read(struct file *filep,
char __user *buf,
size_t count,
loff_t *off);
static ssize_t global_mem_dev_write(struct file *filep,
char __user *buf,
size_t count,
loff_t *off);
static ssize_t global_mem_dev_ioctl(struct inode *inode,
struct file *filep,
unsigned int cmd,
unsigned long arg);
static int global_mem_dev_setup_cdev(struct global_mem_dev *mydev,
int minor_index);
static int __init global_mem_dev_init_module(void);
static void __exit global_mem_dev_cleanup_module(void);
/*********************************************************************/
/*打开设备,对应于用户空间的open系统调用*/
static int global_mem_dev_open(struct inode *inode,
struct file *filep)
{
#if 0
int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);
switch(minor)
{
case 0: /* /dev/global_mem */
printk("/dev/global_mem opened!\n");
break;
case 1: /* /dev/global_mem1 */
printk("/dev/global_mem1 opened!\n");
break;
case 2: /* /dev/global_mem2 */
printk("/dev/global_mem2 opened!\n");
break;
case 3: /* /dev/global_mem1 */
printk("/dev/global_mem3 opened!\n");
break;
}
#endif
/*将设备结构体指针赋值给文件私有数据指针*/
filep->private_data = global_mem_dev_array;
printk("/dev/%s opened!\n", DEVICE_NAME);
//填充一些资源的初始化
return 0;
}

/*关闭设备,对应于用户空间的close系统调用*/
static int global_mem_dev_release(struct inode *inode,
struct file *filep)
{
printk("/dev/%s closed!\n", DEVICE_NAME);
//填充一些资源的释放
return 0;
}

/*实现读功能,对应于用户空间的read系统调用*/
static ssize_t global_mem_dev_read(struct file *filep,
char __user *buf,
size_t count,
loff_t *off)
{
struct global_mem_dev *dev = filep->private_data; /*获得设备结构体指针*/
copy_to_user(buf, (void *)dev->mem, count);
return 0;
}

/*实现写功能,对应于用户空间的write系统调用*/
static ssize_t global_mem_dev_write(struct file *filep,
char __user *buf,
size_t count,
loff_t *off)
{
struct global_mem_dev *dev = filep->private_data; /*获得设备结构体指针*/
copy_from_user(dev->mem, buf, count);
return 0;
}

/*实现控制功能,对应于用户空间的ioctl系统调用*/
static ssize_t global_mem_dev_ioctl(struct inode *inode,
struct file *filep,
unsigned int cmd,
unsigned long arg)
{
return 0;
}

/*设置file_operations 结构体,提供给应用空间的接口*/
static struct file_operations global_mem_dev_fops =
{
.owner   = THIS_MODULE,
.open    = global_mem_dev_open,
.release = global_mem_dev_release,
.read    = global_mem_dev_read,
.write   = global_mem_dev_write,
.ioctl   = global_mem_dev_ioctl,
};

/*设备建立子函数,被global_mem_dev_init_module函数调用*/
static int global_mem_dev_setup_cdev(struct global_mem_dev *mydev,
int minor_index)       /*minor_index*/
{
int err;
dev_t devno = MKDEV(major, first_minor + minor_index);

cdev_init(&mydev->cdev, &global_mem_dev_fops);
mydev->cdev.owner = THIS_MODULE;           //这里要用.
mydev->cdev.ops   = &global_mem_dev_fops;         //这里要用.

err = cdev_add(&mydev->cdev, devno, 1);
if (err)
{
printk("[errno = %d] Faiglobal_mem to add %s , minor_index=%d\n", err, DEVICE_NAME, minor_index);
}
return err;
}

/*驱动模块的初始化*/
static int __init global_mem_dev_init_module(void)
{
int result;
int i;
dev_t dev_no = 0;					   /*设备号 高12bits:major 低20bits:minor*/

/*注册设备号*/
if (major) /*静态分配主设备号的注册*/
{
dev_no = MKDEV(major, first_minor);
result = register_chrdev_region(dev_no,      /*分配设备号起始值*/
minor_count, /*请求的连续设备号的个数*/
DEVICE_NAME);/*设备号范围内关联的设备名称
*出现在/proc/devices和sysfs中*/
}
else  /*动态分配主设备号的注册*/
{
result = alloc_chrdev_region(&dev_no,
first_minor,
minor_count,    /*请求的连续设备号的个数*/
DEVICE_NAME);
major = MAJOR(dev_no);/*保存动态分配的主设备号*/
}
if (result < 0)
{
printk("%s : Faiglobal_mem to  get major %d\n", DEVICE_NAME, major);
result = -1;
goto fail;  /*失败了,应该回滚前面的操作撒*/
}
else
{
DEBUG("%s : Successed to  get major %d\n", DEVICE_NAME, major);
}
/*字符设备文件的注册*/
global_mem_dev_array = kmalloc(minor_count * sizeof(struct global_mem_dev), GFP_KERNEL);
if (!global_mem_dev_array)
{
result = -ENOMEM;
printk("%s : Faiglobal_mem to kmalloc *global_mem_dev_array(%d * sizeof(struct %s))\n",
DEVICE_NAME, minor_count, DEVICE_NAME);
goto fail;  /* Make this more graceful */
}
memset(global_mem_dev_array, 0, minor_count * sizeof(struct global_mem_dev));
for(i = 0; i < minor_count; i++)
{
result = global_mem_dev_setup_cdev(&global_mem_dev_array[i], i);
if (result < 0)
goto fail;
}
/*mdev动态的在/dev/下创建DEVICE_NAME节点*/
global_mem_dev_class = class_create(THIS_MODULE, DEVICE_NAME);
device_create(global_mem_dev_class,
NULL,
dev_no,
NULL,
DEVICE_NAME);
DEBUG("%s : Successed to init!\n", DEVICE_NAME);
return 0;

fail:
global_mem_dev_cleanup_module();
return result;
}

/*驱动模块的清除*/
static void __exit global_mem_dev_cleanup_module(void)
{
int i;
dev_t devno = MKDEV(major, first_minor);

if (global_mem_dev_array)
{
for (i = 0; i < minor_count; i++)
{
cdev_del(&global_mem_dev_array[i].cdev);	//注意是.
}
kfree(global_mem_dev_array);
}
/* cleanup_module is never calglobal_mem if registering faiglobal_mem */
unregister_chrdev_region(devno, 1);
device_destroy(global_mem_dev_class, devno);
class_destroy(global_mem_dev_class);
DEBUG("%s : successed to exit!\n", DEVICE_NAME);
}

/**/
MODULE_AUTHOR("onejacky wanshijie@126.com");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("simple cdev driver module for global_mem");

module_init(global_mem_dev_init_module);   //insmod
module_exit(global_mem_dev_cleanup_module);	//rmmod
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: