从 Windows 向 Linux 迁移设备控制应用程序 – 爱码网
从 Windows 向 Linux 迁移设备控制应用程序
通过认识 Windows 和 Linux 在设备控制方面的差异,克服迁移中的难题
Sun Ling 和 Yang Yi
2008 年 7 月 14 日发布
如果读者开发过不同平台的设备控制应用程序,那么肯定了解 Windows 和 Linux 的设备控制方式的差别,从一个平台向另一个平台迁移应用程序相当复杂。本文分析两种操作系统的设备控制原理,探究从架构到系统调用的各个方面,重点比较二者差别。本文还给出一个迁移示例(用 C/C++ 编写),详细演示迁移过程。
工作条件:
根据本文的写作目的,“Windows” 是指 Windows 2000 或其后续版本,且安装有 Microsoft Visual C++® 6.0 或其后续版本。Linux应当基于 2.6 版内核,且安装有 GNU GCC。
比较设备控制的架构
Windows 和 Linux 设备控制的方式是不同的。
Windows 设备控制架构
Windows 的 I/O 子系统将用户应用程序和设备驱动程序联系起来,并定义基础结构支持设备驱动程序。设备驱动程序为具体设备提供 I/O 接口(参见图 1)。
图 1:Windows 设备控制架构
在设备控制过程中,I/O 操作封装为 IRP(I/O 请求数据包)。I/O 管理器创建 IRP,并将它发送到堆栈顶部。然后,设备驱动程序获取 IRP 的堆栈地址。IRP 包含着 I/O 请求的参数。根据 IRP 包含的请求(比如 创建
、 读取
、写入
、设备 I/O 控制
、清除
或 关闭
),各驱动程序通过硬件接口工作。
Linux 设备控制架构
Linux 的设备控制架构有所不同。主要区别是,Linux 的普通文件、目录、设备和 socket 都是文件 —Linux 的所有东西都是文件。为了访问设备,Linux 内核将设备操作调用通过文件系统映射到设备驱动程序。Linux 没有 I/O 管理器。所有 I/O 请求从开始就进入文件系统(参见图 2)。
图 2. Linux 设备控制架构
比较设备文件名和路径名
从开发的角度来看,获取设备句柄是设备控制的先决条件。但是,由于设备控制架构的差异,获取设备句柄会根据所用平台不同(Windows 还是 Linux)而有不同的过程。
一般而言,设备句柄由具体设备驱动程序的名称决定。
Windows 设备驱动程序的文件名不同于普通文件,通常称为设备路径名。它具有固定格式,形如 \.DeviceName
。在 C/C++ 编程中,这个字符串应当是 \\.\DeviceName
。在代码中表示为 \\\\.\\DeviceName
。DeviceName
应当与相应设备驱动程序定义的设备名称相同。
有些设备名称由 Microsoft 定义,因此不能修改(如表 1 所示)。
表 1. Windows 设备名称(x = 0,1,2 等)
设备 | 路径名 |
---|---|
软盘驱动器 | A: B: |
硬盘逻辑子区 | C: D: E: . . . |
物理驱动器 | PhysicalDrivex |
CD-ROM、DVD/ROM | CdRomx |
磁带驱动器 | Tapex |
COM 端口 | COMx |
例如,我们在 C/C++ 编程中使用设备路径名,比如 \\\\.\\PhysicalDrive1
、\\\\.\\CdRom0
和 \\\\.\\Tape0
。 关于这个列表未收录的其他设备的详细情况,请查看本文后面的 参考资料 小节。
因为 Linux 将设备描述为文件,所以可以在目录 ./dev 中找到所有设备文件。这个目录的设备驱动程序包括:
- IDE(Integrated Drive Electronics)硬盘驱动器,比如 /dev/hda 和 /dev/hdb
- CD-ROM 驱动器,有些是 IDE;也有些是模拟 SCSI(Small Computer Systems Interface)设备的 CD-RW(CD 读/写)驱动器,比如 /dev/scd0
- 串行口,例如 /dev/ttyS0 表示 COM1,/dev/ttyS1 表示 COM2,依此类推
- 定位设备,包括 /dev/input/mice 等
- 打印机,比如 /dev/lp0
常见设备文件大多可以按照上述描述找到。有关其他设备文件名和设备的详细信息,请使用命令 dmesg
。
比较主系统调用
设备控制的主系统调用包括下列操作:打开、关闭、I/O 控制、读/写等。参见表 2 所示的 Windows/Linux 映射。
表 2. 设备控制函数的映射
Windows | Linux |
---|---|
CreateFile | open |
CloseHandle | close |
DeviceIoControl | ioctl |
ReadFile | read |
WriteFile | write |
现在,我们深入探讨三个最常用的函数:create
、close
和 devioctl
。
Windows 的设备打开和关闭
我们讨论 Windows 函数 CreateFile
和 CloseHandle
。函数 CreateFile
用于打开设备。该函数返回句柄,用以访问清单 1 所示的对象。
清单 1. Windows 的 CreateFile 函数
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
参数 lpFileName
是前面讲过的设备路径名。通常,打开设备需要将 dwDesiredAccess
设置为 0 或GENERIC_READ
|GENERIC_WRITE
,将 dwShareMode
设置为 FILE_SHARE_READ
|FILE_SHARE_WRITE
,将 dwCreationDisposition
设置为 OPEN_EXISTING
,以及将 dwFlagsAndAttributes
和 hTemplateFile
设置为 0 或 NULL。返回句柄将用于后续设备控制操作。
关闭设备使用函数 CloseHandle
。将参数 hObject
设置为设备打开时返回的句柄:BOOL WINAPI CloseHandle (HANDLE hObject);
。
Linux 的设备打开和关闭
在 Linux 中,我们讨论的是函数 open
和 close
。 如前所述,打开设备就像打开普通文件一样。清单 2 显示如何使用 open
获取设备句柄。
清单 2. Linux 的 open 函数
1 2 3 |
|
调用成功将返回文件描述符,它是进程尚未打开的序号最小的文件描述符。如果调用失败,将返回 -1。文件描述符用作设备句柄。
参数标志必须包含 O_RDONLY
、O_WRONLY
或 O_RDWR
的其中之一。其他标志可选。参数模式在新文件创立时说明文件访问权。
在 Linux 中,函数 close
关闭设备就像关闭文件一样:int close(int fd);
。
Windows 的 DeviceIoControl
设备控制(Windows 的 DeviceIoControl
和 Linux 的 ioctl
)是最常用的设备控制函数,可以完成设备访问、信息获取、命令发送和数据交换等任务。清单 3 举例说明了 DeviceIoControl
:
清单 3. Windows 的 DeviceIoControl 函数
1 2 3 4 5 6 7 8 |
|
这个系统调用向指定设备发送控制代码和其他数据。相应设备驱动程序按照控制代码 dwIoControlCode
的指示工作。例如,使用IOCTL_DISK_GET_DRIVE_GEOMETRY
可以从物理驱动器获取结构参数(介质类型、柱面数、每柱面磁道数、每磁道扇区数等)。可以在 MSDN 网站上找到所有控制代码定义、头文件和其他详细内容(参见 参考资料 获得相关链接)。
是否需要输入/输出缓冲,以及它们结构和大小怎样,都取决于实际 ioctl
过程涉及的设备和操作,并由该调用指定的 dwIoControlCode
确定。
如果重叠操作的指针设为 NULL,那么 DeviceIoControl
将以阻塞(同步)方式工作。否则,它以异步方式工作。
Linux 函数 ioctl
Linux 可以使用 ioctl
—int ioctl(int fildes, int request, /* arg */ ...);
— 向指定设备发送控制信息。第一个参数 fildes
是函数 open()
返回的文件描述符,用于指称具体设备。
与对应的系统调用 DeviceIOControl
不同,ioctl
的输入参数列表并不固定。它取决于 ioctl
进行何种请求,以及请求参数有何说明,正如 Windows 函数 DeviceIOControl
的参数 dwIoControlCode
一样。但是,迁移期间需要注意何时选择正确的请求参数,因为 DeviceIOControl
的 dwIoControlCode
和 ioctl
的 request
具有不同的取值。而且 dwIoControlCode
与 request
之间没有显式映射列表。通常可以在相关头文件中查找请求参数值的定义来选择参数值。所有控制代码的定义在 /usr/include/{asm,linux}/*.h 文件中。
参数 arg
为具体设备的运转提供详细的命令信息。arg
的数据类型取决于特定控制请求。这个参数可以用于发送详细命令和接收返回数据。
迁移示例
我们查看一个从 Windows 向 Linux 迁移的过程的示例。这个示例涉及从个人电脑主 IDE 硬盘驱动器读取 SMART 日志。
步骤 1. 识别设备类型
如前所述,Linux 的各个设备被当作文件。首先要描述设备在 Linux 上的文件名。只有使用这个文件名,才能获取设备控制需要的设备句柄。
在这个示例中,对象是 IDE 硬盘驱动器。Linux 将其描述为 /dev/hda、/dev/hdb 等。本例将要迁移的硬盘设备路径名是 \\\\.\\PhysicalDrive0。/dev/hda 是该设备对应的 Linux 文件名。
步骤 2. 改变包含头文件
必须将 #include
头文件改为 Linux 形式(参见表 3):
表 3. #include 头文件
Windows | Linux |
---|---|
#include <windows.h> | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> |
#include <devioctl.h> | #include <sys/ioctl.h> |
#include <ntddscsi.h> | #include <linux/hdreg.h> |
windows.h
包含打开和关闭设备的函数(CreateFile
和 CloseHandle
)。相应地,在 Linux 中用于 open()
和 close()
的函数应当包含头文件 sys/types.h、sys/stat.h 和 fcntl.h。
Windows 的 devioctl.h
用于函数 DeviceIoControl
,我们将其改为 sys/ioctl.h 以确保该函数 ioctl
能够工作。
ntddscsi.h
(它是来自 DDK 的头文件)定义了一组用于设备控制的控制代码。因为本例只处理 IDE 硬盘驱动器,所以只需将 linux/hdreg.h 添加到 Linux 程序。
对于其他情况,应当确保包含所有头文件(它们带有所需的控制代码的定义)。例如,如果访问 CD-ROM 而非硬盘驱动器,那么应当包含 linux/cdrom.h。
步骤 3. 改正函数和参数
现在我们详细查看代码。清单 4 显示命令的详细信息。
清单 4. 命令详解
1 2 3 4 5 6 7 8 |
|
命令信息来自 ATA 命令说明书。因为将此代码移植到 Linux 不需要修改,所以没有必要进一步分析。
清单 5 所示代码打开 Windows 主硬盘驱动器。
清单 5. 打开 Windows 主硬盘驱动器
1 2 3 4 |
|
从有关设备打开和关闭的讲解可知,我们需要两个参数(文件路径名和设备访问模式)来打开 Linux 设备。根据前面的原始代码,第一个参数应当是 /dev/hda,第二个是 O_RDONLY
|O_NONBLOCK
。修改过的代码如下所示:HANDLE devHandle = open("/dev/hda", O_RDONLY | O_NONBLOCK);
。相应将 CloseHandle(devHandle);
更改为 close(devHandle);
。
移植的主要部分是如何使用 ioctl
访问特定设备和获取需要的信息。原始 Windows 代码如清单 6 所示:
清单 6. Windows 上 DeviceIoControl 的源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
DeviceIoControl
比 ioctl
需要更多的参数。设备句柄在两个平台上都是第一个参数,它从 CreateFile
和 Linux 的 open()
返回。但是 Windows 的控制代码和 Linux 的请求在定义上差别很大,以致没有固定规则能够找出这两个参数的映射关系,如前文所述。 IOCTL_IDE_PASS_THROUGH
在头文件 ntddscsi.h 中定义为 CTL_CODE (IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
。通过在头文件 /usr/include/linux/hdreg.h 中查找定义,可以选用相应 Linux 控制代码 HDIO_DRIVE_CMD
。
另外,设备要完成具体任务需要详细的命令信息。该命令存放在缓存中,与返回数据的内存空间在进程中交换数据。我们使用同一缓存来发送命令和获取所需日志信息。Linux 的缓存大小可以改变;不一定用完八个字节。本例只用了命令的四个字节。
对应的 Linux 代码(清单 7)看起来简单很多,因为它的结构和函数参数比 Windows 简单。
清单 7. Linux 函数 ioctl 的源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
步骤 4. Linux 环境下的测试
在改正头文件、函数和参数之后,该程序准备在 Linux 上运行。现在的任务是在 Linux 平台上编译该程序并纠正剩余的语法错误。根据 Linux 版本和编译环境,可能需要另做修改。
从 Windows 向 Linux 迁移设备控制应用程序
通过认识 Windows 和 Linux 在设备控制方面的差异,克服迁移中的难题
Sun Ling 和 Yang Yi
2008 年 7 月 14 日发布
如果读者开发过不同平台的设备控制应用程序,那么肯定了解 Windows 和 Linux 的设备控制方式的差别,从一个平台向另一个平台迁移应用程序相当复杂。本文分析两种操作系统的设备控制原理,探究从架构到系统调用的各个方面,重点比较二者差别。本文还给出一个迁移示例(用 C/C++ 编写),详细演示迁移过程。
工作条件:
根据本文的写作目的,“Windows” 是指 Windows 2000 或其后续版本,且安装有 Microsoft Visual C++® 6.0 或其后续版本。Linux应当基于 2.6 版内核,且安装有 GNU GCC。
比较设备控制的架构
Windows 和 Linux 设备控制的方式是不同的。
Windows 设备控制架构
Windows 的 I/O 子系统将用户应用程序和设备驱动程序联系起来,并定义基础结构支持设备驱动程序。设备驱动程序为具体设备提供 I/O 接口(参见图 1)。
图 1:Windows 设备控制架构
在设备控制过程中,I/O 操作封装为 IRP(I/O 请求数据包)。I/O 管理器创建 IRP,并将它发送到堆栈顶部。然后,设备驱动程序获取 IRP 的堆栈地址。IRP 包含着 I/O 请求的参数。根据 IRP 包含的请求(比如 创建
、 读取
、写入
、设备 I/O 控制
、清除
或 关闭
),各驱动程序通过硬件接口工作。
Linux 设备控制架构
Linux 的设备控制架构有所不同。主要区别是,Linux 的普通文件、目录、设备和 socket 都是文件 —Linux 的所有东西都是文件。为了访问设备,Linux 内核将设备操作调用通过文件系统映射到设备驱动程序。Linux 没有 I/O 管理器。所有 I/O 请求从开始就进入文件系统(参见图 2)。
图 2. Linux 设备控制架构
比较设备文件名和路径名
从开发的角度来看,获取设备句柄是设备控制的先决条件。但是,由于设备控制架构的差异,获取设备句柄会根据所用平台不同(Windows 还是 Linux)而有不同的过程。
一般而言,设备句柄由具体设备驱动程序的名称决定。
Windows 设备驱动程序的文件名不同于普通文件,通常称为设备路径名。它具有固定格式,形如 \.DeviceName
。在 C/C++ 编程中,这个字符串应当是 \\.\DeviceName
。在代码中表示为 \\\\.\\DeviceName
。DeviceName
应当与相应设备驱动程序定义的设备名称相同。
有些设备名称由 Microsoft 定义,因此不能修改(如表 1 所示)。
表 1. Windows 设备名称(x = 0,1,2 等)
设备 | 路径名 |
---|---|
软盘驱动器 | A: B: |
硬盘逻辑子区 | C: D: E: . . . |
物理驱动器 | PhysicalDrivex |
CD-ROM、DVD/ROM | CdRomx |
磁带驱动器 | Tapex |
COM 端口 | COMx |
例如,我们在 C/C++ 编程中使用设备路径名,比如 \\\\.\\PhysicalDrive1
、\\\\.\\CdRom0
和 \\\\.\\Tape0
。 关于这个列表未收录的其他设备的详细情况,请查看本文后面的 参考资料 小节。
因为 Linux 将设备描述为文件,所以可以在目录 ./dev 中找到所有设备文件。这个目录的设备驱动程序包括:
- IDE(Integrated Drive Electronics)硬盘驱动器,比如 /dev/hda 和 /dev/hdb
- CD-ROM 驱动器,有些是 IDE;也有些是模拟 SCSI(Small Computer Systems Interface)设备的 CD-RW(CD 读/写)驱动器,比如 /dev/scd0
- 串行口,例如 /dev/ttyS0 表示 COM1,/dev/ttyS1 表示 COM2,依此类推
- 定位设备,包括 /dev/input/mice 等
- 打印机,比如 /dev/lp0
常见设备文件大多可以按照上述描述找到。有关其他设备文件名和设备的详细信息,请使用命令 dmesg
。
比较主系统调用
设备控制的主系统调用包括下列操作:打开、关闭、I/O 控制、读/写等。参见表 2 所示的 Windows/Linux 映射。
表 2. 设备控制函数的映射
Windows | Linux |
---|---|
CreateFile | open |
CloseHandle | close |
DeviceIoControl | ioctl |
ReadFile | read |
WriteFile | write |
现在,我们深入探讨三个最常用的函数:create
、close
和 devioctl
。
Windows 的设备打开和关闭
我们讨论 Windows 函数 CreateFile
和 CloseHandle
。函数 CreateFile
用于打开设备。该函数返回句柄,用以访问清单 1 所示的对象。
清单 1. Windows 的 CreateFile 函数
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
参数 lpFileName
是前面讲过的设备路径名。通常,打开设备需要将 dwDesiredAccess
设置为 0 或GENERIC_READ
|GENERIC_WRITE
,将 dwShareMode
设置为 FILE_SHARE_READ
|FILE_SHARE_WRITE
,将 dwCreationDisposition
设置为 OPEN_EXISTING
,以及将 dwFlagsAndAttributes
和 hTemplateFile
设置为 0 或 NULL。返回句柄将用于后续设备控制操作。
关闭设备使用函数 CloseHandle
。将参数 hObject
设置为设备打开时返回的句柄:BOOL WINAPI CloseHandle (HANDLE hObject);
。
Linux 的设备打开和关闭
在 Linux 中,我们讨论的是函数 open
和 close
。 如前所述,打开设备就像打开普通文件一样。清单 2 显示如何使用 open
获取设备句柄。
清单 2. Linux 的 open 函数
1 2 3 |
|
调用成功将返回文件描述符,它是进程尚未打开的序号最小的文件描述符。如果调用失败,将返回 -1。文件描述符用作设备句柄。
参数标志必须包含 O_RDONLY
、O_WRONLY
或 O_RDWR
的其中之一。其他标志可选。参数模式在新文件创立时说明文件访问权。
在 Linux 中,函数 close
关闭设备就像关闭文件一样:int close(int fd);
。
Windows 的 DeviceIoControl
设备控制(Windows 的 DeviceIoControl
和 Linux 的 ioctl
)是最常用的设备控制函数,可以完成设备访问、信息获取、命令发送和数据交换等任务。清单 3 举例说明了 DeviceIoControl
:
清单 3. Windows 的 DeviceIoControl 函数
1 2 3 4 5 6 7 8 |
|
这个系统调用向指定设备发送控制代码和其他数据。相应设备驱动程序按照控制代码 dwIoControlCode
的指示工作。例如,使用IOCTL_DISK_GET_DRIVE_GEOMETRY
可以从物理驱动器获取结构参数(介质类型、柱面数、每柱面磁道数、每磁道扇区数等)。可以在 MSDN 网站上找到所有控制代码定义、头文件和其他详细内容(参见 参考资料 获得相关链接)。
是否需要输入/输出缓冲,以及它们结构和大小怎样,都取决于实际 ioctl
过程涉及的设备和操作,并由该调用指定的 dwIoControlCode
确定。
如果重叠操作的指针设为 NULL,那么 DeviceIoControl
将以阻塞(同步)方式工作。否则,它以异步方式工作。
Linux 函数 ioctl
Linux 可以使用 ioctl
—int ioctl(int fildes, int request, /* arg */ ...);
— 向指定设备发送控制信息。第一个参数 fildes
是函数 open()
返回的文件描述符,用于指称具体设备。
与对应的系统调用 DeviceIOControl
不同,ioctl
的输入参数列表并不固定。它取决于 ioctl
进行何种请求,以及请求参数有何说明,正如 Windows 函数 DeviceIOControl
的参数 dwIoControlCode
一样。但是,迁移期间需要注意何时选择正确的请求参数,因为 DeviceIOControl
的 dwIoControlCode
和 ioctl
的 request
具有不同的取值。而且 dwIoControlCode
与 request
之间没有显式映射列表。通常可以在相关头文件中查找请求参数值的定义来选择参数值。所有控制代码的定义在 /usr/include/{asm,linux}/*.h 文件中。
参数 arg
为具体设备的运转提供详细的命令信息。arg
的数据类型取决于特定控制请求。这个参数可以用于发送详细命令和接收返回数据。
迁移示例
我们查看一个从 Windows 向 Linux 迁移的过程的示例。这个示例涉及从个人电脑主 IDE 硬盘驱动器读取 SMART 日志。
步骤 1. 识别设备类型
如前所述,Linux 的各个设备被当作文件。首先要描述设备在 Linux 上的文件名。只有使用这个文件名,才能获取设备控制需要的设备句柄。
在这个示例中,对象是 IDE 硬盘驱动器。Linux 将其描述为 /dev/hda、/dev/hdb 等。本例将要迁移的硬盘设备路径名是 \\\\.\\PhysicalDrive0。/dev/hda 是该设备对应的 Linux 文件名。
步骤 2. 改变包含头文件
必须将 #include
头文件改为 Linux 形式(参见表 3):
表 3. #include 头文件
Windows | Linux |
---|---|
#include <windows.h> | #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> |
#include <devioctl.h> | #include <sys/ioctl.h> |
#include <ntddscsi.h> | #include <linux/hdreg.h> |
windows.h
包含打开和关闭设备的函数(CreateFile
和 CloseHandle
)。相应地,在 Linux 中用于 open()
和 close()
的函数应当包含头文件 sys/types.h、sys/stat.h 和 fcntl.h。
Windows 的 devioctl.h
用于函数 DeviceIoControl
,我们将其改为 sys/ioctl.h 以确保该函数 ioctl
能够工作。
ntddscsi.h
(它是来自 DDK 的头文件)定义了一组用于设备控制的控制代码。因为本例只处理 IDE 硬盘驱动器,所以只需将 linux/hdreg.h 添加到 Linux 程序。
对于其他情况,应当确保包含所有头文件(它们带有所需的控制代码的定义)。例如,如果访问 CD-ROM 而非硬盘驱动器,那么应当包含 linux/cdrom.h。
步骤 3. 改正函数和参数
现在我们详细查看代码。清单 4 显示命令的详细信息。
清单 4. 命令详解
1 2 3 4 5 6 7 8 |
|
命令信息来自 ATA 命令说明书。因为将此代码移植到 Linux 不需要修改,所以没有必要进一步分析。
清单 5 所示代码打开 Windows 主硬盘驱动器。
清单 5. 打开 Windows 主硬盘驱动器
1 2 3 4 |
|
从有关设备打开和关闭的讲解可知,我们需要两个参数(文件路径名和设备访问模式)来打开 Linux 设备。根据前面的原始代码,第一个参数应当是 /dev/hda,第二个是 O_RDONLY
|O_NONBLOCK
。修改过的代码如下所示:HANDLE devHandle = open("/dev/hda", O_RDONLY | O_NONBLOCK);
。相应将 CloseHandle(devHandle);
更改为 close(devHandle);
。
移植的主要部分是如何使用 ioctl
访问特定设备和获取需要的信息。原始 Windows 代码如清单 6 所示:
清单 6. Windows 上 DeviceIoControl 的源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
DeviceIoControl
比 ioctl
需要更多的参数。设备句柄在两个平台上都是第一个参数,它从 CreateFile
和 Linux 的 open()
返回。但是 Windows 的控制代码和 Linux 的请求在定义上差别很大,以致没有固定规则能够找出这两个参数的映射关系,如前文所述。 IOCTL_IDE_PASS_THROUGH
在头文件 ntddscsi.h 中定义为 CTL_CODE (IOCTL_SCSI_BASE, 0x040a, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
。通过在头文件 /usr/include/linux/hdreg.h 中查找定义,可以选用相应 Linux 控制代码 HDIO_DRIVE_CMD
。
另外,设备要完成具体任务需要详细的命令信息。该命令存放在缓存中,与返回数据的内存空间在进程中交换数据。我们使用同一缓存来发送命令和获取所需日志信息。Linux 的缓存大小可以改变;不一定用完八个字节。本例只用了命令的四个字节。
对应的 Linux 代码(清单 7)看起来简单很多,因为它的结构和函数参数比 Windows 简单。
清单 7. Linux 函数 ioctl 的源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
步骤 4. Linux 环境下的测试
在改正头文件、函数和参数之后,该程序准备在 Linux 上运行。现在的任务是在 Linux 平台上编译该程序并纠正剩余的语法错误。根据 Linux 版本和编译环境,可能需要另做修改。