IO_Card 驱动

超、凢脫俗 2022-08-03 00:11 328阅读 0赞
  1. 公司别人写的。
  2. </pre><pre name="code" class="cpp">/*
  3. IO_Card 驱动
  4. 1、系统找到DriverEntry()函数,初始化驱动程序。
  5. 2、系统调用AddDevice例程添加设备对象。
  6. 3FDO收到IRP_MN_START_DEVICE IRP,将其设置完成例程(实际设置在下个IO堆栈)后传递给PDO。接着FDO等待同步。(实际上PDO完成资源分配)
  7. 4、当PDO完成IRP_MN_START_DEVICE IRP,设备堆栈回滚时。执行完成例程,并将IRP再次交给FDO
  8. 5FDO根据IRP提供的IO堆栈得到设备资源,并完成例程。
  9. 6、等待各种IRP和中断
  10. 6.1、中断(主要用于操作)
  11. 6.2PNP IRP(主要用于配置)
  12. 6.3、普通IRP(主要用于操作)
  13. 7、当驱动处理完IRP_MN_REMOVE_DEVICE例程后,系统调用HelloWDMUnload例程完成后续工作。
  14. */
  15. #include <initguid.h>
  16. #include "Guid.h"
  17. #include "IO_Card.h"
  18. #include "Ioctls.h"
  19. #pragma INITCODE
  20. // INIT指明该函数只用于初始化,用完后就释放。(节约内存)
  21. // 代码放在代码段,数据放在数据段。
  22. extern "C" NTSTATUS DriverEntry(
  23. // IN、OUT和INOUT是空宏定义,主要起注释作用。
  24. IN PDRIVER_OBJECT pDriverObject, // I/O管理器传递过来的驱动对象。
  25. IN PUNICODE_STRING pRegistryPath // 驱动对象注册表路径。
  26. )
  27. // extern "C"用于在CPP模式下引用C代码,保证符号链接的正确性。
  28. {
  29. KdPrint(("Enter DriverEntry\n")); // 调试信息打印函数,它只在check版本中生效。
  30. pDriverObject->DriverExtension->AddDevice = IO_CardAddDevice; // 设置添加设备回调函数。
  31. pDriverObject->MajorFunction[IRP_MJ_PNP] = IO_CardPnp; // 设置PNP IRP处理回调函数。
  32. pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl; // 设置IO操作回调函数。
  33. pDriverObject->MajorFunction[IRP_MJ_CREATE] = IO_CardDispatchRoutine;
  34. pDriverObject->MajorFunction[IRP_MJ_CLOSE] = IO_CardDispatchRoutine;
  35. pDriverObject->MajorFunction[IRP_MJ_READ] = IO_CardDispatchRoutine;
  36. pDriverObject->MajorFunction[IRP_MJ_WRITE] = IO_CardDispatchRoutine; // 设置缺省IRP处理回调函数。
  37. pDriverObject->DriverUnload = IO_CardUnload; // 设置删除设备回调函数(实际上在PNP IRP中就被处理了)。
  38. KdPrint(("Leave DriverEntry\n")); // 调试信息打印函数,它只在check版本中生效。
  39. return STATUS_SUCCESS;
  40. }
  41. #pragma PAGEDCODE
  42. // IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
  43. // 代码放在代码段,数据放在数据段。
  44. NTSTATUS IO_CardAddDevice(
  45. // IN、OUT和INOUT是空宏定义,主要起注释作用。
  46. IN PDRIVER_OBJECT DriverObject, // I/O管理器传递过来的驱动对象。
  47. IN PDEVICE_OBJECT PhysicalDeviceObject // 从I/O管理器传递过来的物理设备对象。
  48. )
  49. {
  50. PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
  51. KdPrint(("Enter IO_CardAddDevice\n")); // 调试信息打印函数,它只在check版本中生效。
  52. NTSTATUS status;
  53. PDEVICE_OBJECT fdo;
  54. // 创建设备驱动。
  55. status = IoCreateDevice(DriverObject,sizeof(DEVICE_EXTENSION),NULL,FILE_DEVICE_UNKNOWN,0,FALSE,&fdo);
  56. // 是否创建成功。
  57. if( !NT_SUCCESS(status))
  58. return status;
  59. PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension; // 获取设备扩展对象的指针。
  60. pdx->fdo = fdo; // 当前设备。
  61. pdx->NextStackDevice = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject); // 附着FDO到PDO上,并且把返回的PDO记录在FDO的扩展对象中。
  62. // 创建设备接口。(不能指定设备名)
  63. status = IoRegisterDeviceInterface(PhysicalDeviceObject, &IO_CARD_DEVICE, NULL, &pdx->interfaceName);
  64. if( !NT_SUCCESS(status))
  65. {
  66. IoDeleteDevice(fdo); // 失败则删除FDO。
  67. return status;
  68. }
  69. IoSetDeviceInterfaceState(&pdx->interfaceName, TRUE); // 使设备名有效。
  70. if( !NT_SUCCESS(status))
  71. {
  72. if( !NT_SUCCESS(status))
  73. {
  74. return status;
  75. }
  76. }
  77. KdPrint(("%wZ\n",&pdx->interfaceName)); // 调试信息打印函数,它只在check版本中生效。
  78. // 设置标志位。
  79. fdo->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
  80. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  81. KdPrint(("Leave IO_CardAddDevice\n")); // 调试信息打印函数,它只在check版本中生效。
  82. return STATUS_SUCCESS;
  83. }
  84. // 中断响应例程。
  85. BOOLEAN OnInterrupt(PKINTERRUPT InterruptObject, PDEVICE_EXTENSION pdx)
  86. {
  87. // 关中断。
  88. UCHAR HSR = READ_PORT_UCHAR(pdx->portbase);
  89. HSR = HSR | 0x04;
  90. WRITE_PORT_UCHAR(pdx->portbase,HSR);
  91. KdPrint(("==============interrupt!!!\n"));
  92. // 恢复中断信号电平。
  93. WRITE_REGISTER_UCHAR((PUCHAR)pdx->MemBar0+0x400000,0x10);
  94. IoRequestDpc(pdx->fdo, NULL, pdx); // 中断处理标志,DPC处理事件。
  95. return TRUE;
  96. }
  97. #pragma PAGEDCODE
  98. // IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
  99. // 代码放在代码段,数据放在数据段。
  100. NTSTATUS InitMyPCI(IN PDEVICE_EXTENSION pdx,IN PCM_PARTIAL_RESOURCE_LIST list) // 主要用于将系统分配的资源初始化。
  101. {
  102. PHYSICAL_ADDRESS portbase; // 端口物理地址。
  103. BOOLEAN gotport = FALSE;
  104. ULONG vector; // 中断向量。
  105. KIRQL irql; // 中断请求级。
  106. KINTERRUPT_MODE mode; // 中断模式。
  107. KAFFINITY affinity; // CPU的亲缘关系。
  108. BOOLEAN irqshare; // 是否共享中断。
  109. BOOLEAN gotinterrupt = FALSE;
  110. ULONG nres = list->Count; // 资源总数。
  111. PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = &list->PartialDescriptors[0];
  112. // 每次循环获取一种资源。
  113. for (ULONG i = 0; i < nres; ++i, ++resource)
  114. {
  115. // 判断是何种资源。
  116. switch(resource->Type)
  117. {
  118. // I/O端口资源。
  119. case CmResourceTypePort:
  120. // I/O端口地址。
  121. portbase = resource->u.Port.Start;
  122. // I/O端口地址长度。
  123. pdx->nports = resource->u.Port.Length;
  124. // 是否需要地址映射。
  125. pdx->mappedport = (resource->Flags & CM_RESOURCE_PORT_IO) == 0;
  126. // 表示已经得到I/O端口资源。
  127. gotport = TRUE;
  128. break;
  129. // 物理内存资源。
  130. case CmResourceTypeMemory:
  131. pdx->MemBar0 = (PUCHAR)MmMapIoSpace(resource->u.Memory.Start,resource->u.Memory.Length,MmNonCached);
  132. pdx->nMem0 = resource->u.Memory.Length;
  133. break;
  134. // 中断资源。
  135. case CmResourceTypeInterrupt:
  136. // 获得中断请求级。
  137. irql = (KIRQL) resource->u.Interrupt.Level;
  138. // 获得中断向量。
  139. vector = resource->u.Interrupt.Vector;
  140. // 获取CPU亲缘关系。
  141. affinity = resource->u.Interrupt.Affinity;
  142. // 获得中断模式。
  143. mode = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive;
  144. // 判断是否需要共享中断。
  145. irqshare = resource->ShareDisposition == CmResourceShareShared;
  146. // 表示已经得到中断。
  147. gotinterrupt = TRUE;
  148. break;
  149. default:
  150. KdPrint(("Unexpected I/O resource type %d\n", resource->Type));
  151. break;
  152. }
  153. }
  154. if (!(TRUE&& gotport&& gotinterrupt))
  155. {
  156. KdPrint((" Didn't get expected I/O resources\n"));
  157. return STATUS_DEVICE_CONFIGURATION_ERROR;
  158. }
  159. // 判断是够需要I/O端口映射。(为了操作方便,把IO空间映射到MEM空间)
  160. if (pdx->mappedport)
  161. {
  162. // 获得I/O端口地址。
  163. pdx->portbase = (PUCHAR) MmMapIoSpace(portbase, pdx->nports, MmNonCached);
  164. if (!pdx->mappedport)
  165. {
  166. KdPrint(("Unable to map port range %I64X, length %X\n", portbase, pdx->nports));
  167. return STATUS_INSUFFICIENT_RESOURCES;
  168. }
  169. }
  170. else
  171. // 获得I/O端口地址。
  172. pdx->portbase = (PUCHAR) portbase.QuadPart;
  173. // 链接中断。(中断对象与中断响应例程链接)
  174. NTSTATUS status = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE)OnInterrupt, (PVOID)pdx, NULL, vector, irql, irql, LevelSensitive, TRUE, affinity, FALSE);
  175. if (!NT_SUCCESS(status))
  176. {
  177. KdPrint(("IoConnectInterrupt failed - %X\n", status));
  178. if (pdx->portbase && pdx->mappedport)
  179. MmUnmapIoSpace(pdx->portbase, pdx->nports);
  180. pdx->portbase = NULL;
  181. return status;
  182. }
  183. return STATUS_SUCCESS;
  184. }
  185. #pragma LOCKEDCODE
  186. // IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
  187. // 代码放在代码段,数据放在数据段。
  188. NTSTATUS OnRequestComplete(PDEVICE_OBJECT junk, PIRP Irp, PKEVENT pev)
  189. {
  190. KeSetEvent(pev, 0, FALSE); // 把IRP事件设置为完成。
  191. return STATUS_MORE_PROCESSING_REQUIRED; // 再次完成IRP事件 。
  192. }
  193. #pragma PAGEDCODE
  194. // IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
  195. // 代码放在代码段,数据放在数据段。
  196. // 上层设备的完成例程设置在下层设备IO堆栈。
  197. NTSTATUS ForwardAndWait(PDEVICE_EXTENSION pdx, PIRP Irp)
  198. {
  199. PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
  200. KEVENT event;
  201. KeInitializeEvent(&event, NotificationEvent, FALSE); // 初始化事件,用于同步IPR。
  202. IoCopyCurrentIrpStackLocationToNext(Irp); // 本层对IRP有所处理,故需将本层堆栈拷贝到下一层堆栈。(使下层设备处理环境一样)
  203. // 设置完成例程。
  204. IoSetCompletionRoutine(Irp,(PIO_COMPLETION_ROUTINE) OnRequestComplete,(PVOID) &event, TRUE, TRUE, TRUE);
  205. //调用底层驱动,即PDO。
  206. IoCallDriver(pdx->NextStackDevice, Irp);
  207. //等待PDO完成。
  208. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  209. return Irp->IoStatus.Status;
  210. }
  211. #pragma PAGEDCODE
  212. NTSTATUS HandleStartDevice(PDEVICE_EXTENSION pdx, PIRP Irp)
  213. {
  214. PAGED_CODE();
  215. KdPrint(("Enter HandleStartDevice\n"));
  216. // 转发IRP并等待(利用事件同步)返回,IRP_MN_START_DEVICE必须由PDO处理。
  217. NTSTATUS status = ForwardAndWait(pdx,Irp);
  218. if (!NT_SUCCESS(status))
  219. {
  220. Irp->IoStatus.Status = status;
  221. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  222. return status;
  223. }
  224. // 得到当前堆栈。
  225. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
  226. // 从当前堆栈得到翻译信息。
  227. PCM_PARTIAL_RESOURCE_LIST translated;
  228. if (stack->Parameters.StartDevice.AllocatedResourcesTranslated)
  229. translated = &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList;
  230. else
  231. translated = NULL;
  232. KdPrint(("Init the PCI card!\n"));
  233. InitMyPCI(pdx,translated); // 获取设备资源。
  234. // 完成IRP。
  235. Irp->IoStatus.Status = STATUS_SUCCESS;
  236. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  237. KdPrint(("Leave HandleStartDevice\n"));
  238. return status;
  239. }
  240. #pragma PAGEDCODE
  241. // IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
  242. // 代码放在代码段,数据放在数据段。
  243. NTSTATUS DefaultPnpHandler(
  244. PDEVICE_EXTENSION pdx, // 扩展对象。
  245. PIRP Irp // IRP包对象。
  246. )
  247. {
  248. PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
  249. KdPrint(("Enter DefaultPnpHandler\n")); // 调试信息打印函数,它只在check版本中生效。
  250. IoSkipCurrentIrpStackLocation(Irp); // 使IRP的IO堆栈指针后退一格,因为FDO没有对IRP处理,故不需要对其记录,将此堆栈留给PDO使用。(节约内存)
  251. KdPrint(("Leave DefaultPnpHandler\n")); // 调试信息打印函数,它只在check版本中生效。
  252. return IoCallDriver(pdx->NextStackDevice, Irp); // 调用下层驱动。
  253. }
  254. #pragma PAGEDCODE
  255. // IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
  256. // 代码放在代码段,数据放在数据段。
  257. NTSTATUS HandleRemoveDevice(
  258. PDEVICE_EXTENSION pdx, // 扩展对象。
  259. PIRP Irp // IRP包对象。
  260. )
  261. {
  262. PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
  263. KdPrint(("Enter HandleRemoveDevice\n")); // 调试信息打印函数,它只在check版本中生效。
  264. Irp->IoStatus.Status = STATUS_SUCCESS; // 本层IRP包处理完毕,设置标志。
  265. NTSTATUS status = DefaultPnpHandler(pdx, Irp); // 将修改后的IRP包传递给下层驱动。
  266. IoSetDeviceInterfaceState(&pdx->interfaceName, FALSE); // 使设备名失效。
  267. RtlFreeUnicodeString(&pdx->interfaceName); // 释放UnicodeString。
  268. // 调用IoDetachDevice()把fdo从设备栈中脱开。
  269. if (pdx->NextStackDevice)
  270. IoDetachDevice(pdx->NextStackDevice);
  271. IoDeleteDevice(pdx->fdo); // 删除FDO。
  272. IoDisconnectInterrupt(pdx->InterruptObject); // 删除中断。
  273. KdPrint(("Leave HandleRemoveDevice\n")); // 调试信息打印函数,它只在check版本中生效。
  274. return status;
  275. }
  276. #pragma PAGEDCODE
  277. // IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
  278. // 代码放在代码段,数据放在数据段。
  279. NTSTATUS IO_CardPnp(
  280. IN PDEVICE_OBJECT fdo, // 本层FDO设备对象。
  281. IN PIRP Irp // 传进来的IRP对象。
  282. )
  283. {
  284. PAGED_CODE(); // 它会检查当前函数是否运行低于DISPATCH_LEVEL的中断请求级,如果等于或高于这个中断请求级,将产生一个断言。它只在check版本中生效。
  285. KdPrint(("Enter IO_CardPnp\n")); // 调试信息打印函数,它只在check版本中生效。
  286. NTSTATUS status = STATUS_SUCCESS;
  287. PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension; // 获取设备扩展对象的指针。
  288. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); // 获取驱动IO堆栈指针。
  289. static NTSTATUS (*fcntab[])(PDEVICE_EXTENSION pdx, PIRP Irp) = // 声明函数指针数组。
  290. {
  291. HandleStartDevice, // IRP_MN_START_DEVICE
  292. DefaultPnpHandler, // IRP_MN_QUERY_REMOVE_DEVICE
  293. HandleRemoveDevice, // IRP_MN_REMOVE_DEVICE
  294. DefaultPnpHandler, // IRP_MN_CANCEL_REMOVE_DEVICE
  295. DefaultPnpHandler, // IRP_MN_STOP_DEVICE
  296. DefaultPnpHandler, // IRP_MN_QUERY_STOP_DEVICE
  297. DefaultPnpHandler, // IRP_MN_CANCEL_STOP_DEVICE
  298. DefaultPnpHandler, // IRP_MN_QUERY_DEVICE_RELATIONS
  299. DefaultPnpHandler, // IRP_MN_QUERY_INTERFACE
  300. DefaultPnpHandler, // IRP_MN_QUERY_CAPABILITIES
  301. DefaultPnpHandler, // IRP_MN_QUERY_RESOURCES
  302. DefaultPnpHandler, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
  303. DefaultPnpHandler, // IRP_MN_QUERY_DEVICE_TEXT
  304. DefaultPnpHandler, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
  305. DefaultPnpHandler, //
  306. DefaultPnpHandler, // IRP_MN_READ_CONFIG
  307. DefaultPnpHandler, // IRP_MN_WRITE_CONFIG
  308. DefaultPnpHandler, // IRP_MN_EJECT
  309. DefaultPnpHandler, // IRP_MN_SET_LOCK
  310. DefaultPnpHandler, // IRP_MN_QUERY_ID
  311. DefaultPnpHandler, // IRP_MN_QUERY_PNP_DEVICE_STATE
  312. DefaultPnpHandler, // IRP_MN_QUERY_BUS_INFORMATION
  313. DefaultPnpHandler, // IRP_MN_DEVICE_USAGE_NOTIFICATION
  314. DefaultPnpHandler, // IRP_MN_SURPRISE_REMOVAL
  315. };
  316. ULONG fcn = stack->MinorFunction; // 获取IRP的子类型。
  317. if(fcn >= arraysize(fcntab)) // 未知的子类型。
  318. {
  319. status = DefaultPnpHandler(pdx, Irp); // 进行默认操作。
  320. return status;
  321. }
  322. #if DBG // 仅用于调试。
  323. static char* fcnname[] =
  324. {
  325. "IRP_MN_START_DEVICE",
  326. "IRP_MN_QUERY_REMOVE_DEVICE",
  327. "IRP_MN_REMOVE_DEVICE",
  328. "IRP_MN_CANCEL_REMOVE_DEVICE",
  329. "IRP_MN_STOP_DEVICE",
  330. "IRP_MN_QUERY_STOP_DEVICE",
  331. "IRP_MN_CANCEL_STOP_DEVICE",
  332. "IRP_MN_QUERY_DEVICE_RELATIONS",
  333. "IRP_MN_QUERY_INTERFACE",
  334. "IRP_MN_QUERY_CAPABILITIES",
  335. "IRP_MN_QUERY_RESOURCES",
  336. "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
  337. "IRP_MN_QUERY_DEVICE_TEXT",
  338. "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
  339. "",
  340. "IRP_MN_READ_CONFIG",
  341. "IRP_MN_WRITE_CONFIG",
  342. "IRP_MN_EJECT",
  343. "IRP_MN_SET_LOCK",
  344. "IRP_MN_QUERY_ID",
  345. "IRP_MN_QUERY_PNP_DEVICE_STATE",
  346. "IRP_MN_QUERY_BUS_INFORMATION",
  347. "IRP_MN_DEVICE_USAGE_NOTIFICATION",
  348. "IRP_MN_SURPRISE_REMOVAL",
  349. };
  350. KdPrint(("PNP Request (%s)\n", fcnname[fcn]));
  351. #endif
  352. status = (*fcntab[fcn])(pdx, Irp); // 响应IRP请求。
  353. KdPrint(("Leave IO_CardPnp\n"));
  354. return status;
  355. }
  356. #pragma PAGEDCODE
  357. // IRQL优先级高的使用分页内存,反之使用非分页内存。(维持系统稳定性)
  358. // 代码放在代码段,数据放在数据段。
  359. NTSTATUS IO_CardDispatchRoutine(IN PDEVICE_OBJECT fdo, IN PIRP Irp)
  360. {
  361. PAGED_CODE();
  362. KdPrint(("Enter IO_CardDispatchRoutine\n"));
  363. Irp->IoStatus.Status = STATUS_SUCCESS; // 设置IRP对象状态。
  364. Irp->IoStatus.Information = 0; // 设置实际传递比特数 。
  365. IoCompleteRequest( Irp, IO_NO_INCREMENT ); // 完成请求。
  366. KdPrint(("Leave IO_CardDispatchRoutine\n"));
  367. return STATUS_SUCCESS;
  368. }
  369. // 完成IRP例程。
  370. NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG_PTR info)
  371. {
  372. Irp->IoStatus.Status = status;
  373. Irp->IoStatus.Information = info;
  374. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  375. return status;
  376. }
  377. // IO处理例程。
  378. // 每个IRP创建时,随之生成一个IO堆栈,IO堆栈与设备堆栈对应。
  379. NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp)
  380. {
  381. PAGED_CODE();
  382. NTSTATUS status;
  383. ULONG info = 0;
  384. PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension; // 获取设备扩展对象。
  385. PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); // 获取设备IO堆栈。
  386. ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength; // 获取需要输入字符长度。
  387. ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength; // 获取需要输出字符长度。
  388. ULONG code = stack->Parameters.DeviceIoControl.IoControlCode; // 获取操作码。
  389. // 判断使用何种操作。
  390. switch(code)
  391. {
  392. case IOCTL_READ_BASE_BAR0:
  393. {
  394. ULONG offset = *(ULONG*)(Irp->AssociatedIrp.SystemBuffer);
  395. PUCHAR buff = (PUCHAR)ExAllocatePool(NonPagedPool,cbout);
  396. READ_REGISTER_BUFFER_UCHAR((PUCHAR)pdx->MemBar0+offset,buff,cbout);
  397. RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, buff, cbout);
  398. ExFreePool(buff);
  399. info = cbout;
  400. break;
  401. }
  402. case IOCTL_WRITE_BASE_BAR0:
  403. {
  404. int* tempPointer = (int*)Irp->AssociatedIrp.SystemBuffer;
  405. ULONG offset = *(ULONG*)(tempPointer);
  406. tempPointer++;
  407. PUCHAR buff = *(PUCHAR*)(tempPointer);
  408. tempPointer++;
  409. ULONG nInputNumber = *(ULONG*)(tempPointer);
  410. WRITE_REGISTER_BUFFER_UCHAR((PUCHAR)pdx->MemBar0+offset,buff,nInputNumber);
  411. break;
  412. }
  413. case IOCTL_ENABLE_INT:
  414. {
  415. UCHAR HSR = READ_PORT_UCHAR(pdx->portbase);
  416. HSR = HSR & 0xFB;
  417. WRITE_PORT_UCHAR(pdx->portbase,HSR);
  418. break;
  419. }
  420. case IOCTL_DISABLE_INT:
  421. {
  422. UCHAR HSR = READ_PORT_UCHAR(pdx->portbase);
  423. HSR = HSR | 0x04;
  424. WRITE_PORT_UCHAR(pdx->portbase,HSR);
  425. break;
  426. }
  427. default:
  428. {
  429. status = STATUS_INVALID_DEVICE_REQUEST;
  430. break;
  431. }
  432. }
  433. return CompleteRequest(Irp, status, info); // 调用完成IRP例程。
  434. }
  435. #pragma PAGEDCODE
  436. // 实际卸载处理在PNP IRP中完成
  437. void IO_CardUnload(IN PDRIVER_OBJECT DriverObject)
  438. {
  439. PAGED_CODE();
  440. KdPrint(("Enter IO_CardUnload\n"));
  441. KdPrint(("Leave IO_CardUnload\n"));
  442. }
  443. </pre><pre name="code" class="cpp">
  444. </pre><pre name="code" class="cpp">
  445. </pre><pre name="code" class="cpp">
  446. </pre><pre name="code" class="cpp">
  447. </pre><pre name="code" class="cpp"><pre name="code" class="cpp">/************************************************************************
  448. * 文件名称:IO_Card.h
  449. * 者:丁观亮
  450. * 完成日期:2014-1-23
  451. *************************************************************************/
  452. #ifdef __cplusplus
  453. extern "C"
  454. {
  455. #endif
  456. #include <wdm.h>
  457. #ifdef __cplusplus
  458. }
  459. #endif
  460. #define PAGEDCODE code_seg("PAGE")
  461. #define LOCKEDCODE code_seg()
  462. #define INITCODE code_seg("INIT")
  463. #define PAGEDDATA data_seg("PAGE")
  464. #define LOCKEDDATA data_seg()
  465. #define INITDATA data_seg("INIT")
  466. #define arraysize(p) (sizeof(p)/sizeof((p)[0])) // 数组大小计算宏
  467. // 扩展结构体,用来存储本层设备需要的信息
  468. typedef struct _DEVICE_EXTENSION
  469. {
  470. PDEVICE_OBJECT fdo; // 上层设备
  471. PDEVICE_OBJECT NextStackDevice; // 下层设备
  472. UNICODE_STRING interfaceName; // 设备名(符号链接)
  473. PKINTERRUPT InterruptObject; // 中断对象名
  474. PUCHAR portbase; // IO端口地址
  475. ULONG nports; // IO端口地址的数量
  476. PVOID MemBar0; // 内存基地址0
  477. ULONG nMem0; // 基地址BAR0占用字节数
  478. BOOLEAN mappedport; // 如果为真需要做IO端口映射
  479. } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
  480. // 函数声明,在此声明可被外部引用
  481. extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath);
  482. NTSTATUS IO_CardAddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT PhysicalDeviceObject);
  483. NTSTATUS IO_CardPnp(IN PDEVICE_OBJECT fdo,IN PIRP Irp);
  484. NTSTATUS IO_CardDispatchRoutine(IN PDEVICE_OBJECT fdo,IN PIRP Irp);
  485. NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp);
  486. void IO_CardUnload(IN PDRIVER_OBJECT DriverObject);

Ioctls.h

  1. #ifndef IOCTLS_H
  2. #define IOCTLS_H
  3. #ifndef CTL_CODE
  4. #pragma message("CTL_CODE undefined. Include winioctl.h or wdm.h")
  5. #endif
  6. // 读取BAR0基地址
  7. #define IOCTL_READ_BASE_BAR0 CTL_CODE( \
  8. FILE_DEVICE_UNKNOWN, \
  9. 0x800, \
  10. METHOD_BUFFERED, \
  11. FILE_ANY_ACCESS)
  12. // 读取BAR0基地址
  13. #define IOCTL_WRITE_BASE_BAR0 CTL_CODE( \
  14. FILE_DEVICE_UNKNOWN, \
  15. 0x801, \
  16. METHOD_BUFFERED, \
  17. FILE_ANY_ACCESS)
  18. // 开中断
  19. #define IOCTL_ENABLE_INT CTL_CODE( \
  20. FILE_DEVICE_UNKNOWN, \
  21. 0x802, \
  22. METHOD_BUFFERED, \
  23. FILE_ANY_ACCESS)
  24. // 关中断
  25. #define IOCTL_DISABLE_INT CTL_CODE( \
  26. FILE_DEVICE_UNKNOWN, \
  27. 0x803, \
  28. METHOD_BUFFERED, \
  29. FILE_ANY_ACCESS)
  30. #endif

Guid.h

  1. // 定义设备的全局标识符(可用算法随机生成)
  2. DEFINE_GUID(IO_CARD_DEVICE, 0xe57c50f, 0xccc, 0x4ad2, 0xa8, 0x95, 0x93, 0xc5, 0xed, 0x11, 0x98, 0x60);
  3. <span style="font-family:Microsoft YaHei;font-size:24px;"><strong>IO_Card.inf</strong></span>
  4. <span style="font-family:Microsoft YaHei;font-size:24px;"><strong>
  5. </strong></span>
  6. <span style="font-family:Microsoft YaHei;font-size:24px;"><strong></strong></span><pre name="code" class="cpp">;-------------------------------------------------------------------------------------------
  7. ;版本节,INF文件的开始。
  8. [Version]
  9. ;inf文件实用的系统,指明驱动程序的签名,其取值为:$Windows NT$$Windows 95$$Chicago$
  10. Signature="$CHICAGO$"
  11. ;inf文件的提供商。
  12. Provider=CPC_TECH
  13. ;指明驱动程序的版本信息,其格式为:mm/dd/yyyy,x.y.v.z
  14. DriverVer=23/1/2014,1.0.0.1
  15. ;指明驱动程序所属的类别。
  16. Class=CPC_TECH_DEV
  17. ;指明设备类的GUID,其格式为:{nnnnnnnn-nnnn-nnnn-nnnnnnnnnnnn}。
  18. ClassGUID={EF2962F0-0D55-4bff-B8AA-2221EE8A79B0}
  19. ;指明数字签名文件的文件名,其扩展名为.cat
  20. ;CatalogFile=
  21. ;仅由操作系统内部提供的INF文件使用。
  22. ;LayoutFile=
  23. ;-------------------------------------------------------------------------------------------
  24. ;指明设备驱动程序所在的磁盘或CD-ROM
  25. [SourceDisksNames]
  26. ;格式为diskid=disk-description,tagfile,unused,path
  27. ;disked:指出磁盘驱动器的编号
  28. ;disk-description:表示磁盘的描述信息,他通常为一个字符串。
  29. ;tagfile:指出磁盘标签文件的文件名。
  30. ;unused:为保留字段。
  31. ;path:指出驱动程序所在的路径。
  32. 1 = "IO_Card",Disk1,,
  33. ;指明设备驱动程序的文件名。
  34. [SourceDisksFiles]
  35. ;格式为filename=diskid,subdir,size
  36. ;filename:指出驱动程序的文件名。
  37. ;diskid:指出磁盘驱动器的编号。
  38. ;subdir:指出该文件在磁盘上的路径。
  39. ;size:指出该文件未经压缩时的大小,以字节为单位。
  40. IO_Card.sys = 1,,
  41. ;目的路径
  42. [DestinationDirs]
  43. ;格式为File-list-section=dirid,subdir
  44. ;file-list-section:指出CopyFilesDelFilesRenFiles指令所引用的节。
  45. ;dirid:指出目标目录值。
  46. ;subdir:指出dirid目录下的子目录。
  47. YouMark_Files_Driver = 10,System32\Drivers
  48. ;-------------------------------------------------------------------------------------------
  49. ;安装NT类到注册表中
  50. [ClassInstall32]
  51. Addreg=Class_AddReg
  52. [Class_AddReg]
  53. HKR,,,,%DeviceClassName%
  54. HKR,,Icon,,"-5"
  55. ;-------------------------------------------------------------------------------------------
  56. ;指明供应商及其对应Models接的名称。
  57. [Manufacturer]
  58. ;格式为%strkey%=models-section-name
  59. ;strkey:代表设备制造的名字,其字符串值在String节中定义。
  60. ;models-section-name:指出Models节的名称。
  61. %MfgName%=Mfg0
  62. ;指明Install/DDInstall节的名称、设备的硬件ID和兼容ID等信息,其节名称由Manufacturer节指定。
  63. [Mfg0]
  64. ;格式为device-description=install-section-name,hw-id,compatiable-id
  65. ;device-description:指出设备的表述信息,他可以是一个字符串,也可以是一个%strkey%。
  66. ;install-section-name:指出Install/DDInstall节的名称。
  67. ;hw-id:指出设备的硬件ID
  68. ;compatiable-id:指出设备的兼容ID
  69. %DeviceDesc%=YouMark_DDI, PCI\VEN_10b5&DEV_9054
  70. ;-------------------------------------------------------------------------------------------
  71. ;指明需复制的文件、想注册表中添加的内容等信息,其节名称由Models节指定。
  72. [YouMark_DDI.NT]
  73. ;格式为CopyFiles=@filename|file-list-section
  74. ;filename:指出目标文件名。
  75. ;file-list-section:是其创建的文件列表节。
  76. CopyFiles=YouMark_Files_Driver
  77. ;格式为AddReg=add-registry-section
  78. ;add-registry-section:创建的添加注册表节。
  79. AddReg=YouMark_NT_AddReg
  80. ;文件列表节。
  81. [YouMark_Files_Driver]
  82. IO_Card.sys
  83. ;注册表节。
  84. [YouMark_NT_AddReg]
  85. ;格式为reg-root, [subkey], [value-entry-name], [flags], [value]。
  86. ;reg-root:指出注册表树的根目录。
  87. ;subkey:指出reg-root下的子目录。
  88. ;value-entry-name:指出要增加的注册表值。
  89. ;flags:指出其对注册表的一些处理方。
  90. ;value:指出新增加注册表值的数据。
  91. HKLM, "System\CurrentControlSet\Services\IO_Card\Parameters",\
  92. "BreakOnEntry", 0x00010001, 0
  93. ;用于控制设备驱动程序的安装过程。
  94. [YouMark_DDI.NT.Services]
  95. ;格式为AddService=ServiceName,[flags],service-install-section[,event-log-install-section[,[EventLogType][,EventName]]]…。
  96. ;ServiceName:指出驱动程序的名字。
  97. ;flags:指出一个或多个系统定义的标识。
  98. ;service-install-section:是其创建的服务安装节。
  99. ;event-log-install-section:是其创建的事件日志安装。
  100. ;EventLogType:指出事件日志的类型。
  101. ;EventName:指出事件日志的名字。
  102. Addservice = IO_Card, 0x00000002, YouMark_AddService
  103. ;创建的服务安装节。
  104. [YouMark_AddService]
  105. ;服务显示名称要和设备名称相同。
  106. DisplayName = %SvcDesc%
  107. ;指明驱动程序的类型。
  108. ServiceType = 1 ; SERVICE_KERNEL_DRIVER
  109. ;指明驱动程序的启动类型。
  110. StartType = 3 ; SERVICE_DEMAND_START
  111. ;指明驱动程序的差错控制级别。
  112. ErrorControl = 1 ; SERVICE_ERROR_NORMAL
  113. ;指明驱动程序的路径。
  114. ServiceBinary = %10%\System32\Drivers\IO_Card.sys
  115. ;-------------------------------------------------------------------------------------------
  116. ;指明一些列字符串,当某些字符串频繁地出现在INF文件中,为简化输入,可以在该节中定义一个字符串变量,代表该字符串出现在INF文件中。
  117. [Strings]
  118. ProviderName="Ding Guanliang."
  119. MfgName="CPC_TECH"
  120. DeviceDesc="IO_Card"
  121. DeviceClassName="CPC_TECH_Device"
  122. SvcDesc="Ding Guanliang"

发表评论

表情:
评论列表 (有 0 条评论,328人围观)

还没有评论,来说两句吧...

相关阅读

    相关 chrome驱动(chrome驱动最新版本)

    chrome浏览器怎么样? 设置,只有5项,数量上属于短期记忆的能力范围内,减少了用户的认知负担,此时用户关注点只在浏览本身上,几乎不需要对浏览器进行额外的学习 ![c

    相关 驱动科普

    驱动干的事情,简单可以说成是:初始化和配置硬件;实现硬件的数据的接受和发送   转载于:https://www.cnblogs.com/yangxingsha/

    相关 数据驱动

    Vue.js    ⼀个核⼼思想是数据驱动。所谓数据驱动,是指视图是由数据驱动⽣成的,我们对视图的修改, 不会直接操作    DOM,⽽是通过修改数据。它相⽐我们传统的前端开发