一、模块加载与卸载
1.在模块的加载中要实现设备号的申请与cdev的注册。
先用int register_chrdev_region(dev_t from, unsigned count, const char *name)或者int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)申请设备号。
在第一个函数register_chrdev_region中from是指希望申请的设备号,count是希望申请的设备号的数目,name是设备名。
在第二个函数alloc_chrdev_region中,是动态申请设备号,即自动分配系统空闲的设备号。dev是设备号地址,baseminor是申请的设备的第一个次设备号,count是希望申请的设备号的数目,name是设备名。
内核中有cdev结构体,描述一个字符设备。结构体定义如下
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
习惯上,工程师为设备定义一个设备相关的结构体(包含设备涉及的cdev和私有数据和信号量)
struct xxx_dev_t {
struct cdev cdev;
. . .
}xxx_dev;
然后用初始化函数void cdev_init(struct cdev *cdev, const struct file_operations *fops)来初始化cdev的成员。
cdev的注册是通过 int cdev_add(struct cdev *, dev_t, unsigned)向系统添加一个cdev。
2.模块的卸载要实现设备号的释放和cdev的注销
若在模块加载函数中申请了设备结构体内存则要释放设备结构体内存。
void cdev_del(struct cdev *)用来注销cdev。
void unregister_chrdev_region(dev_t from, unsigned count)用来释放设备号。
加载和卸载设备驱动源代码如下:
/* 初始化并注册cdev */
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
int err, devno = MKDEV(globalmem_major, index);
cdev_init(&dev->cdev, &globalmem_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
if (err)
printk(KERN_NOTICE "Error %d adding globalmem %d", err, index);
}
/* 设备驱动模块加载函数 */
int globalmem_init(void)
{
int result;
dev_t devno = MKDEV(globalmem_major, 0); /* devno = (250<<20) | 0 */
/* 申请设