摘要: Unix 系统已经长时间支持名为 readv 和 writev 的 2 个系统调用. 这些 read 和 write 的"矢量"版本使用一个结构数组, 每个包含一个缓存的指针和一个长度值. 一个 readv 调 用被期望来轮流读取指示的数量到每个缓存. 相反, writev 要收集每个缓存的内容到一 阅读全文
posted @ 2019-07-05 15:39 樊伟胜 阅读(1943) 评论(0) 推荐(0) 编辑
摘要: write, 象 read, 可以传送少于要求的数据, 根据返回值的下列规则: 如果值等于 count, 要求的字节数已被传送. 如果正值, 但是小于 count, 只有部分数据被传送. 程序最可能重试写入剩下的数 据. 如果值为 0, 什么没有写. 这个结果不是一个错误, 没有理由返回一个错误码. 阅读全文
posted @ 2019-07-05 15:38 樊伟胜 阅读(324) 评论(0) 推荐(0) 编辑
摘要: read 的返回值由调用的应用程序解释: 如果这个值等于传递给 read 系统调用的 count 参数, 请求的字节数已经被传送. 这是最好的情况. 如果是正数, 但是小于 count, 只有部分数据被传送. 这可能由于几个原因, 依赖 于设备. 常常, 应用程序重新试着读取. 例如, 如果你使用 阅读全文
posted @ 2019-07-05 15:37 樊伟胜 阅读(331) 评论(0) 推荐(0) 编辑
摘要: 读和写方法都进行类似的任务, 就是, 从和到应用程序代码拷贝数据. 因此, 它们的原型 相当相似, 可以同时介绍它们: ssize_t read(struct file *filp, char user *buff, size_t count, loff_t *offp); ssize_t writ 阅读全文
posted @ 2019-07-05 15:36 樊伟胜 阅读(236) 评论(0) 推荐(0) 编辑
摘要: 在介绍读写操作前, 我们最好看看如何以及为什么 scull 进行内存分配. "如何"是需要全 面理解代码, "为什么"演示了驱动编写者需要做的选择, 尽管 scull 明确地不是典型设备. 本节只处理 scull 中的内存分配策略, 不展示给你编写真正驱动需要的硬件管理技能. 其他风味的设备由不同的 阅读全文
posted @ 2019-07-05 15:35 樊伟胜 阅读(254) 评论(0) 推荐(0) 编辑
摘要: open 方法提供给驱动来做任何的初始化来准备后续的操作. 在大部分驱动中, open 应当 进行下面的工作: 检查设备特定的错误(例如设备没准备好, 或者类似的硬件错误 如果它第一次打开, 初始化设备 如果需要, 更新 f_op 指针. 分配并填充要放进 filp->private_data 的任 阅读全文
posted @ 2019-07-05 15:34 樊伟胜 阅读(322) 评论(0) 推荐(0) 编辑
摘要: 在内部, scull 使用一个 struct scull_dev 类型的结构表示每个设备. 这个结构定义为: struct scull_dev { struct scull_qset *data; /* Pointer to first quantum set */ int quantum; /* 阅读全文
posted @ 2019-07-05 15:33 樊伟胜 阅读(192) 评论(0) 推荐(0) 编辑
摘要: 如我们提过的, 内核在内部使用类型 struct cdev 的结构来代表字符设备. 在内核调用你 的设备操作前, 你编写分配并注册一个或几个这些结构. [11] 11为此, 你的代码应当包含 <linux/cdev.h>, 这个结构和它的关联帮助函数定义在这里. 有 2 种方法来分配和初始化一个这些 阅读全文
posted @ 2019-07-05 15:32 樊伟胜 阅读(501) 评论(0) 推荐(0) 编辑
摘要: inode 结构由内核在内部用来表示文件. 因此, 它和代表打开文件描述符的文件结构是不 同的. 可能有代表单个文件的多个打开描述符的许多文件结构, 但是它们都指向一个单个 inode 结构. inode 结构包含大量关于文件的信息. 作为一个通用的规则, 这个结构只有 2 个成员对于 编写驱动代码 阅读全文
posted @ 2019-07-05 15:31 樊伟胜 阅读(467) 评论(0) 推荐(0) 编辑
摘要: struct file, 定义于 <linux/fs.h>, 是设备驱动中第二个最重要的数据结构. 注意 file 与用户空间程序的 FILE 指针没有任何关系. 一个 FILE 定义在 C 库中, 从不出现在内核 代码中. 一个 struct file, 另一方面, 是一个内核结构, 从不出现在用 阅读全文
posted @ 2019-07-05 15:30 樊伟胜 阅读(794) 评论(0) 推荐(0) 编辑
摘要: 如同你想象的, 注册设备编号仅仅是驱动代码必须进行的诸多任务中的第一个. 我们将很 快看到其他重要的驱动组件, 但首先需要涉及一个别的. 大部分的基础性的驱动操作包括 3 个重要的内核数据结构, 称为 file_operations, file, 和 inode. 需要对这些结构的 基本了解才能够做 阅读全文
posted @ 2019-07-05 15:25 樊伟胜 阅读(954) 评论(0) 推荐(0) 编辑
摘要: 一些主设备编号是静态分派给最普通的设备的. 一个这些设备的列表在内核源码树的 Documentation/devices.txt 中. 分配给你的新驱动使用一个已经分配的静态编号的机会 很小, 但是, 并且新编号没在分配. 因此, 作为一个驱动编写者, 你有一个选择: 你可以 简单地捡一个看来没有用 阅读全文
posted @ 2019-07-05 15:23 樊伟胜 阅读(303) 评论(0) 推荐(0) 编辑
摘要: 在建立一个字符驱动时你的驱动需要做的第一件事是获取一个或多个设备编号来使用. 为 此目的的必要的函数是 register_chrdev_region, 在 <linux/fs.h>中声明: int register_chrdev_region(dev_t first, unsigned int co 阅读全文
posted @ 2019-07-05 15:11 樊伟胜 阅读(443) 评论(0) 推荐(0) 编辑
摘要: 在内核中, dev_t 类型(在 <linux/types.h>中定义)用来持有设备编号 -- 主次部分都包 括. 对于 2.6.0 内核, dev_t 是 32 位的量, 12 位用作主编号, 20 位用作次编号. 你的 代码应当, 当然, 对于设备编号的内部组织从不做任何假设; 相反, 应当利用 阅读全文
posted @ 2019-07-05 15:10 樊伟胜 阅读(630) 评论(0) 推荐(0) 编辑
摘要: 字符设备通过文件系统中的名子来存取. 那些名子称为文件系统的特殊文件, 或者设备文 件, 或者文件系统的简单结点; 惯例上它们位于 /dev 目录. 字符驱动的特殊文件由使用 ls -l 的输出的第一列的"c"标识. 块设备也出现在 /dev 中, 但是它们由"b"标识. 本章 集中在字符设备, 但 阅读全文
posted @ 2019-07-05 15:09 樊伟胜 阅读(347) 评论(0) 推荐(0) 编辑
摘要: 驱动需要知道的几个参数因不同的系统而不同. 从使用的设备号( 如我们在下一章见到的 ) 到驱动应当任何操作的几个方面. 例如, SCSI 适配器的驱动常常有选项控制标记命令队列 的使用, IDE 驱动允许用户控制 DMA 操作. 如果你的驱动控制老的硬件, 还需要被明确告 知哪里去找硬件的 I/O 阅读全文
posted @ 2019-07-05 15:06 樊伟胜 阅读(918) 评论(0) 推荐(0) 编辑
摘要: 编写驱动的第一步是定义驱动将要提供给用户程序的能力(机制).因为我们的"设备"是计算 机内存的一部分, 我们可自由做我们想做的事情. 它可以是一个顺序的或者随机存取的设 备, 一个或多个设备, 等等. 为使 scull 作为一个模板来编写真实设备的真实驱动, 我们将展示给你如何在计算机内存 上实现几 阅读全文
posted @ 2019-07-05 15:06 樊伟胜 阅读(494) 评论(0) 推荐(0) 编辑
摘要: 到目前, 我们的讨论已来到一个模块加载的重要方面: 竞争情况. 如果你在如何编写你的 初始化函数上不小心, 你可能造成威胁到整个系统的稳定的情形. 我们将在本书稍后讨论 竞争情况; 现在, 快速提几点就足够了: 首先时你应该一直记住, 内核的某些别的部分会在注册完成之后马上使用任何你注册的设 施. 阅读全文
posted @ 2019-07-05 15:05 樊伟胜 阅读(162) 评论(0) 推荐(0) 编辑
摘要: 每个非试验性的模块也要求有一个清理函数, 它注销接口, 在模块被去除之前返回所有资 源给系统. 这个函数定义为: static void exit cleanup_function(void) { /* Cleanup code here */ } module_exit(cleanup_funct 阅读全文
posted @ 2019-07-05 15:04 樊伟胜 阅读(310) 评论(0) 推荐(0) 编辑
摘要: 你必须记住一件事, 在注册内核设施时, 注册可能失败. 即便最简单的动作常常需要内存 分配, 分配的内存可能不可用. 因此模块代码必须一直检查返回值, 并且确认要求的操作 实际上已经成功. 如果在你注册工具时发生任何错误, 首先第一的事情是决定模块是否能够无论如何继续初 始化它自己. 常常, 在一个 阅读全文
posted @ 2019-07-05 15:04 樊伟胜 阅读(570) 评论(0) 推荐(0) 编辑