"); //-->
http://blog.chinaunix.net/u1/34474/showart.php?id=404280 基本抄自
主编号标识设备相连的驱动,次编号被内核用来决定引用哪个设备。
在内核中, dev_t 类型(在 <linux/types.h>中定义)用来持有设备编号。对于 2.6.0 内核, dev_t 是 32 位的量, 12 位用作主编号, 20 位用作次编号.
应当利用在 <linux/kdev_t.h>中的一套宏定义. 为获得一个 dev_t 的主或者次编号, 使用:
(dev_t)-->主设备号、次设备号 |
MAJOR(dev_t dev) |
主设备号、次设备号-->(dev_t) |
MKDEV(int major,int minor) |
在建立一个字符驱动时你的驱动需要做的第一件事是获取一个或多个设备编号来使用。并且应当在不再使用它们时释放它。
int register_chrdev_region(dev_t first, unsigned int count, |
安排主编号最好的方式, 我们认为, 是缺省使用动态分配, 而留给自己在加载时或者甚至在编译时指定主编号的选项权.
以下是在scull.c中用来获取主设备好的代码:
if (scull_major) { |
动态分配的缺点是你无法提前创建设备节点, 因为分配给你的模块的主编号会变化. 对于驱动的正常使用, 这不是问题, 因为一旦编号分配了, 你可从 /proc/devices 中读取它.
一些重要数据结构大部分的基础性的驱动操作包括 3 个重要的内核数据结构,file_operations, file 和 inode.
file_operations结构定义在 <linux/fs.h>
struct file_operations scull_fops = { |
struct file,定义于 <linux/fs.h>与用户空间程序的 FILE 指针没有任何关系。文件结构代表一个打开的文件.它由内核在 open 时创建, 并传递给在文件上操作的任何函数, 直到最后的关闭. 在文件的所有实例都关闭后, 内核释放这个数据结构.
inode 结构,是在内核内部用来表示文件的。因此, 它和代表打开文件描述符的文件结构是不同的. 可能有代表单个文件的多个打开描述符的许多文件结构, 但是它们都指向一个单个 inode 结构.
字符设备注册struct cdev *my_cdev = cdev_alloc();
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
cdev.owner = THIS_MODULE;
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
从系统中移除一个字符设备:void cdev_del(struct cdev *p)
以下是scull中的初始化代码(之前已经为struct scull_dev 分配了空间):
/* |
open 方法提供给驱动来做任何的初始化来准备后续的操作. 在大部分驱动中, open 应当进行下面的工作:
●检查设备特定的错误(例如设备没准备好, 或者类似的硬件错误)
●如果它第一次打开, 初始化设备
●如果需要, 更新 f_op 指针.
●分配并填充要放进 filp->private_data 的任何数据结构
但是, 事情的第一步常常是确定打开哪个设备. 记住 open 方法的原型是:
int (*open)(struct inode *inode, struct file *filp); |
inode 参数有我们需要的信息,以它的 i_cdev 成员的形式, 里面包含我们之前建立的 cdev 结构.
container_of(pointer, container_type, container_field); |
这个宏使用一个指向 container_field 类型的成员的指针, 它在一个 container_type 类型的结构中, 并且返回一个指针指向包含结构. 在 scull_open, 这个宏用来找到适当的设备结构:
struct scull_dev *dev; /* device information */ |
识别打开的设备的另外的方法是查看存储在 inode 结构的次编号. 如果你使用 register_chrdev 注册你的设备, 你必须使用这个技术. 确认使用 iminor 从 inode 结构中获取次编号, 并且确定它对应一个你的驱动真正准备好处理的设备.
int scull_open(struct inode *inode, struct file *filp) |
release 方法
●释放 open 分配在 filp->private_data 中的任何东西
●在最后的 close 关闭设备
scull 的基本形式没有硬件去关闭, 因此需要的代码是最少的:
int scull_release(struct inode *inode, struct file *filp) |
以下是scull模型的结构体:
/* |
scull驱动程序引入了两个Linux内核中用于内存管理的核心函数,它们的定义都在<linux/slab.h>:
void *kmalloc(size_t size, int flags); |
以下是scull模块中的一个释放整个数据区的函数(类似清零),将在scull以写方式打开和scull_cleanup_module中被调用:
int scull_trim(struct scull_dev *dev) |