内核在内部使用类型 struct cdev 的结构来代表字符设备. 在内核调用你的设备操作前, 你编写分配并注册一个或几个这些结构.
有 2 种方法来分配和初始化一个这些结构. 如果你想在运行时获得一个独立的 cdev 结构, 你可以为此使用这样的代码:
struct cdev *my_cdev = cdev_alloc();my_cdev->ops = &my_fops;
但是, 偶尔你会想将 cdev 结构嵌入一个你自己的设备特定的结构; scull 这样做了. 在这种情况下, 你应当初始化你已经分配的结构, 使用:
void cdev_init(struct cdev *cdev, struct file_operations *fops);
任一方法, 有一个其他的 struct cdev 成员你需要初始化. 象 file_operations 结构, struct cdev 有一个拥有者成员, 应当设置为 THIS_MODULE. 一旦 cdev 结构建立, 最后的步骤是把它告诉内核, 调用:
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
dev 是 cdev 结构, num 是这个设备响应的第一个设备号, count 是应当关联到设备的设备号的数目. 常常 count 是 1, 但是有多个设备号对应于一个特定的设备的情形. 例如, 设想 SCSI 磁带驱动, 它允许用户空间来选择操作模式(例如密度), 通过安排多个次编号给每一个物理设备.
在使用 cdev_add 是有几个重要事情要记住. 第一个是这个调用可能失败. 如果它返回一个负的错误码, 你的设备没有增加到系统中. 它几乎会一直成功, 但是, 并且带起了其他的点: cdev_add 一返回, 你的设备就是"活的"并且内核可以调用它的操作. 除非你的驱动完全准备好处理设备上的操作, 你不应当调用 cdev_add.
为从系统去除一个字符设备, 调用:
void cdev_del(struct cdev *dev);
-
/**
-
* 注册设备
-
* Lzy 2012\7\24
-
*/
-
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <linux/cdev.h>
-
#include <linux/slab.h>
-
-
#include "hello.h"
-
-
/************************* 设备号 ******************************/
-
int mem_major = MEMDEV_MAJOR; /* 定义主设备号 */
-
module_param(mem_major, int, S_IRUGO); /* 主设备号设置为模块参数 */
-
int mem_minor = MEMDEV_MINOR; /* 定义次设备号 */
-
module_param(mem_minor, int, S_IRUGO); /* 次设备号设置为模块参数 */
-
-
-
struct mem_dev *my_devices;
-
-
-
-
struct file_operations my_fops =
-
{
-
.owner = THIS_MODULE,
-
};
-
-
-
/**
-
* 注册字符设备
-
*/
-
static void mem_init_cdev(struct mem_dev *dev, int index)
-
{
-
int err, devno = MKDEV(mem_major, mem_minor index);
-
-
cdev_init(&dev->cdev, &my_fops);
-
dev->cdev.owner = THIS_MODULE;
-
dev->cdev.ops = &my_fops;
-
-
err = cdev_add (&dev->cdev, devno, 1); /* */
-
if (err)
-
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
-
}
-
-
static int mem_module_init(void)
-
{
-
int ret,i;
-
dev_t mem_dev; /* 声明设备号 */
-
-
/************ 注册设备号 ****************/
-
if(mem_major)
-
{
-
mem_dev = MKDEV(mem_major,mem_minor); /* 获得设备号 */
-
ret = register_chrdev_region(mem_dev, MEMDEV_NR_DEVS, MEMDEV_NAME); /* 静态注册设备号 */
-
}
-
else
-
{
-
ret = alloc_chrdev_region(&mem_dev, mem_minor, MEMDEV_NR_DEVS, MEMDEV_NAME); /* 动态注册设备号 */
-
mem_major = MAJOR(mem_dev); /* 获得主设备号 */
-
}
-
-
if(ret < 0) /* 判断设备号注册是否成功 */
-
{
-
printk(KERN_WARNING "scull: can't get major %d\n", mem_major);
-
return ret;
-
}
-
-
/****************** 为设备分配空间 *****************************/
-
my_devices = kmalloc((MEMDEV_NR_DEVS * sizeof(struct mem_dev)), GFP_KERNEL);
-
if (!my_devices)
-
{
-
ret = -ENOMEM;
-
goto fail;
-
}
-
memset(my_devices, 0, MEMDEV_NR_DEVS * sizeof(struct mem_dev));
-
-
/************************ 设备初始化 **************************************/
-
for(i=0; i<MEMDEV_NR_DEVS;i )
-
{
-
my_devices[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
-
memset(my_devices[i].data, 0, MEMDEV_SIZE);
-
-
mem_init_cdev(&my_devices[i], i); /* 设备增加至系统 */
-
}
-
-
return ret;
-
-
fail:
-
unregister_chrdev_region(MKDEV(mem_major,mem_minor), MEMDEV_NR_DEVS); /* 注销设备号 */
-
-
return ret;
-
}
-
-
static void mem_module_exit(void)
-
{
-
int i;
-
-
for(i=0; i<MEMDEV_NR_DEVS;i )
-
cdev_del(&(my_devices[i].cdev)); /* 从系统去除字符设备 */
-
-
unregister_chrdev_region(MKDEV(mem_major,mem_minor), MEMDEV_NR_DEVS); /* 注销设备号 */
-
}
-
-
-
module_init(mem_module_init);
-
module_exit(mem_module_exit);
-
-
MODULE_LICENSE("GPL"); /* 模块许可证 */
-
MODULE_AUTHOR("Lzy"); /* 作者声明 */
-
MODULE_DESCRIPTION("memdev module"); /* 模块描述 */
-
MODULE_VERSION("V1.0"); /* 模块版本声明 */
源码: test.rar
阅读(1891) | 评论(0) | 转发(4) |