现在介绍在windows XP下开发虚拟串口的方法。可以开发一个虚拟串口,将读写请求传递给USB驱动,这样就可以利用现成的串口调试工具向USB设备读取了。 1、DDK串口开发框架
DDK对串口驱动提供了专门接口。只要编写的驱动满足这些接口,并按照串口标准的命名方法,不管是真实的串口设备,还是虚拟设备,Windows操作系统都会认为
这个设备是一个标准的串口设备。用标准的串口调试工具都可以与这个设备进行通信。
1、1 串口驱动的入口函数
本章的实例程序是在HelloWDM驱动的基础上修改而来,入口函数依然是DriverEntry,在DriverEntry函数中指定各种IRP的派遣函数,以及AddDevice 例程、卸载例程等。
[cpp] view plaincopy
1. /************************************************************************
2. * 函数名称:DriverEntry
3. * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象 4. * 参数列表:
5. pDriverObject:从I/O管理器中传进来的驱动对象
6. pRegistryPath:驱动程序在注册表的中的路径
7. * 返回 值:返回初始化驱动状态
8. *************************************************************************/
9. #pragma INITCODE
10. extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,
11. IN PUNICODE_STRING pRegistryPath)
12. {
13. KdPrint(("Enter DriverEntry\n"));
14.
15. pDriverObject->DriverExtension->AddDevice = HelloWDMAddDevice;
16. pDriverObject->MajorFunction[IRP_MJ_PNP] = HelloWDMPnp;
17. pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HelloWDMDispatchControlp;
18. pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloWDMCreate;
19. 格兰杰检验 pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloWDMClose;
20. pDriverObject->MajorFunction[IRP_MJ_READ] = HelloWDMRead;
户外广告登记管理规定21. pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloWDMWrite;
22. pDriverObject->DriverUnload = HelloWDMUnload;
23.
24. KdPrint(("Leave DriverEntry\n"));
25. return榆林杀人案 STATUS_SUCCESS;
26. }
其中在AddDevice例程中,需要创建设备对象,这些都是和以前的HelloWDM驱动程序类似。在创建完设备对象后,需要将设备对象指定一个符号链接,该符号链接必须是
COM开头,并接一下数字,如本例就采用了COM7。因为COM1和COM2在有些计算机中有时会被占用,因此,当该设备对象在指定符号链接时,应该避免采用这些名称。
[cpp] view plaincopy
1. /************************************************************************
2. * 函数名称:HelloWDMAddDevice
3. * 功能描述:添加新设备
4. * 参数列表:
5. DriverObject:从I/O管理器中传进来的驱动对象
6. PhysicalDeviceObject:从I/O管理器中传进来的物理设备对象
7. * 返回 值:返回添加新设备状态
8. *************************************************************************/
9. #pragma PAGEDCODE
10. NTSTATUS HelloWDMAddDevice(IN PDRIVER_OBJECT DriverObject,
11. IN PDEVICE_OBJECT PhysicalDeviceObject)
12. {
13. PAGED_CODE();
14. KdPrint(("Enter HelloWDMAddDevice\n"));
15.
16. NTSTATUS status;
17. PDEVICE_OBJECT fdo;
18. UNICODE_STRING devName;
19. RtlInitUnicodeString(&devName,L"\\Device\\MyWDMDevice");
20. status = IoCreateDevice(
21. DriverObject,
22. 说出你的故事2011sizeof(DEVICE_EXTENSION),
23. &(UNICODE_STRING)devName,
24. FILE_DEVICE_UNKNOWN,
25. 0,
26. FALSE,
27. &fdo);
28. if( !NT_SUCCESS(status))
29. return status;
30. 网络安全控制技术 PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
31. pdx->fdo = fdo;
32. pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject);
33. UNICODE_STRING symLinkName;
34. RtlInitUnicodeString(&symLinkName,L"\\DosDevices\\COM7");
35.
36. pdx->ustrDeviceName = devName;
37. pdx->ustrSymLinkName = symLinkName;
38. status = IoCreateSymbolicLink(&(UNICODE_STRING)symLinkName,&(UNICODE_STRING)devName);
39.
40. if( !NT_SUCCESS(status))
41. {
42. IoDeleteSymbolicLink(&pdx->ustrSymLinkName);
43. status = IoCreateSymbolicLink(&symLinkName,&devName);
44. if( !NT_SUCCESS(status))
45. {
46. 饶宗颐书画 return status;
47. }
48. }
49. // 设置为缓冲区设备
50. fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
51. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
52.
53. KdPrint(("Leave HelloWDMAddDevice\n"));
54. return STATUS_SUCCESS;
55. }
在创建完符号链接后,还不能保证应用程序能出这个虚拟的串口设备,还需要进一步修改注册表。具体位置是HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM,可以在这里加入新项目。本例的项目名是MyWDMDevice,类型为REG_SZ,内容是COM7。
在上述步骤后,即在AddDevice例程中创建COM7的符号链接,并且在注册表进行相应设置,系统会认为有这个串口驱动,用任何一个串口调试软件,都可以枚举到
该串口。
1、2 应用程序与串口驱动的通信
其实对于一个真实的串口驱动,或者这个介绍的虚拟串口驱动,都需要遵循一组接口。这组接口由微软事先定义好了,只要符合这组接口,
windows就会认为这是一个串口设备。这里所指的接口就是应用程序发的IO控制码和读写命令,因此对于串口驱动只要对这些IRP的派遣函数编写适当,就能实现一个串口驱动。
首先用IRPTrace看一下,需要对哪些IRP进行处理,笔者加载本章已经介绍的虚拟串口驱动,并用IRPTrace 拦截其IRP处理信息,在打开串口工具后,会发现IRPTrace立刻跟踪到若干个IO控制码,如下所示:
下面依次解释这些IO控制码,理解这些IO控制码,并处理好这些控制码,是编写串口驱动的核心。关于这些IO控制码在ntddser.件中,都有相应的定义,并且还有
相应的数据结构定义。
(1)IOCTL_SERIAL_SET_QUEUE_SIZE
这个控制码是应用程序向驱动请求设置串口驱动内部的缓冲区大小,它是向驱动传递SEA
RIAL_QUEUE_SIZE 数据结构来进行设置的,对于虚拟串口驱动来说,这是不需要
关心的。用IRPTrace可以看出,串口调试工具会向驱动发送的请求是0x400大小的缓冲区大小。