1、字符设备注册
在运行时获得一个独立的cdev结构的代码:
Struct cdev* my_cdev=cdev_alloc();
My_codev->ops=&my_fops;
将cdev结构嵌入自己设备特定的结构:
Void cdev_init(struct cdev* cdev , struct file_operations* fops);
Cdev结构建立后,告诉内核:
Int cdev_add(struct cdev*dev ,dev_t num,unsigned int count);
在驱动完全准备好处理设备上的操作后再调用cdev_add。
为系统去除一个字符设备,调用:
Void cdev_del(struct cdev*dev);
1.1、scull中的设备注册
Scull的结构struct scull_dev:
struct scull_dev {
struct scull_qset *data; /* Pointer to first quantum set */
int quantum; /* the current quantum size */
int qset; /* the current array size */
unsigned long size; /* amount of data stored here */
unsigned int access_key; /* used by sculluid and scullpriv */
struct semaphore sem; /* mutual exclusion semaphore */
struct cdev cdev; /* Char device structure */
};
设备与内核接口的struct cdev这个结构必须初始化,并添加到系统中,scull处理这个任务的代码是:
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;
err = cdev_add (&dev->cdev, devno, 1);
/* Fail gracefully if need be */
if (err)
printk(KERN_NOTICE "Error %d adding scull%d", err, index);
}
2、open和release
至此已经快速浏览了这些成员,并在以后scull的函数中使用它们。
2.1、open方法
Open应当做的工作:
● 检查设备特定的错误(例如设备没准备好, 或者类似的硬件错误)
● 如果它第一次打开, 初始化设备
● 如果需要, 更新 f_op 指针.
● 分配并填充要放进 filp->private_data 的任何数据结构
Open的原型
Int (*open)(struct inode* inode, struct file*filp);
container_of(pointer, container_type, container_field);
这个宏使用一个指向 container_field 类型的成员的指针, 它在一个 container_type 类型的结构中, 并
且返回一个指针指向包含结构. 在 scull_open, 这个宏用来找到适当的设备结构:
struct scull_dev *dev; /* device information */
dev = container_of(inode->i_cdev, struct scull_dev, c
filp->private_data = dev; /* for other methods */
2.2、release方法
应该实现的任务:
● 释放 open 分配在 filp->private_data 中的任何东西
在最后的 close 关闭设备
3、scull的内存使用
scull 驱动引入 2 个核心函数来管理 Linux 内核中的内存. 这些函数, 定义在 <linux/slab.h>, 是:
void *kmalloc(size_t size, int flags);
void kfree(void *ptr);
4、读和写
scull 中的读写代码需要拷贝一整段数据到或者从用户地址空间. 这个能力由下列内核函数提供, 它
们拷贝一个任意的字节数组, 并且位于大部分读写实现的核心中.
unsigned long copy_to_user(void __user *to,const void *from,unsigned long count);
unsigned long copy_from_user(void *to,const void __user *from,unsigned long count);