前面提到,内核内部使用struct cdev结构来表示字符设备。在内核调用设备的操作之前,必须分配并注册一个或者多个上述结构。在<linux/cdev.h>中定义了这个结构以及与其相关的一些辅助函数。
如果需要动态的初始化,应该编写如下代码:
struct cdev *my_cdev = cdev_alloc();
my_cdev->ops = &my_ops;
这时,你可以将cdev结构嵌入到自己的设备特定结构中。这种情况下,我们需要用下面的代码来初始化已分配到的结构:
void cdev_init(struct cdev *cdev, struct file_operations *fops);
另外还需要初始化一个所有者,可以设置为THIS_MODULE。
在cdev结构设置好之后,最后的步骤是通过下面的调用来告诉内核该结构的信息:
int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
num:设备编号
count:经常为1
移除一个字符设备
void cdev_del(struct cdev *dev);
还有比较老的注册字符设备的方式如下:
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
major:主设备号
name:驱动名称(出现在/proc/devices)
fops:file_operations结构
对应的移除函数:
int unregister_chrdev(unsigned int major, const char *name);
其中major和name必须要和register_chrdev传递的一致。
sucll 设备的注册实例
static void scull_setup_cdev(struct scull_dev *dev, int index)
{
/* 转换主次设备号为dev_t结构 */
int err, devno = MKDEV(scull_major, scull_minor + index);
/* 将struct cdev类型的结构体变量和file_operations结构体进行绑定 */
cdev_init(&dev->cdev, &scull_fops);
dev->cdev.owner = THIS_MODULE; /* 初始化所有者 */
dev->cdev.ops = &scull_fops;
err = cdev_add (&dev->cdev, devno, 1); /* 注册驱动 */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
int scull_init_module(void)
{
/* ...others code... */
/* 分配和初始化设备的内存空间 */
scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL);
if (!scull_devices) {
result = -ENOMEM;
goto fail;
}
memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev));
for (i = 0; i < scull_nr_devs; i++) {
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
init_MUTEX(&scull_devices[i].sem);
scull_setup_cdev(&scull_devices[i], i); /* 注册设备驱动 */
}
/* ...others code... */
}