struct file_operations scull_fops = {
.owner = THIS_MODULE,
.read = scull_read,
.write = scull_write,
.open = scull_open,
.release = scull_release,
};
/*
* Finally, the module stuff
*/
/*
* The cleanup function is used to handle initialization failures as well.
* Thefore, it must be careful to work correctly even if some of the items
* have not been initialized
*/
void scull_cleanup_module(void)
{
int i;
//主次设备号合成一个dev_t结构,即设备编号
dev_t devno = MKDEV(scull_major, scull_minor);
/* Get rid of our char dev entries */
if (scull_devices) {
//便利释放每个设备的数据区
for (i = 0; i < scull_nr_devs; i++) {
//释放数据区
scull_trim(scull_devices + i);
//移除cdev
cdev_del(&scull_devices[i].cdev);
}
//释放scull_devices本身
kfree(scull_devices);
}
/* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno, scull_nr_devs);
}
/*
* Set up the char_dev structure for this device.
*/
// 建立char_dev结构
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
int err, devno = MKDEV(scull_major, scull_minor + index);
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE;
// dev->cdev.ops = &scull_fops;
//添加字符设备dev->cdev,立即生效
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
int scull_init_module(void)
{
int result, i;
dev_t dev = 0;
/*
* Get a range of minor numbers to work with, asking for a dynamic
* major unless directed otherwise at load time.
*/
//申请设备编号,若在加载时没有指定主设备号就动态分配
if (scull_major) {
dev = MKDEV(scull_major, scull_minor);
result = register_chrdev_region(dev, scull_nr_devs, "scull");
} else {
result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,
"scull");
scull_major = MAJOR(dev);
}
if (result < 0) {
printk(KERN_WARNING "scull: can't get major %d/n", scull_major);
return result;
}
/*
* allocate the devices -- we can't have them static, as the number
* can be specified at load time
*/
//给scull_dev对象申请内存
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
if (!scull_devices) {
result = -ENOMEM;
goto fail; /* Make this more graceful */
}
memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));
/* Initialize each device. */
for (i = 0; i < scull_nr_devs; i++) {
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
//初始化互斥锁,把信号量sem置为1
sema_init(&scull_devices[i].sem, 1);
//init_MUTEX(&scull_devices[i].sem);
//建立char_dev结构
scull_setup_cdev(&scull_devices[i], i);
}
return 0; /* succeed */
fail:
scull_cleanup_module();
return result;
}
module_init(scull_init_module);
module_exit(scull_cleanup_module);
MODULE_AUTHOR("Tekkamanninja");
MODULE_LICENSE("Dual BSD/GPL");