Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

435 lines
12 KiB

  1. /*
  2. * UNIMODEM "Fakemodem" controllerless driver illustrative example
  3. *
  4. * (C) 2000 Microsoft Corporation
  5. * All Rights Reserved
  6. *
  7. */
  8. #include "fakemodem.h"
  9. #ifdef ALLOC_PRAGMA
  10. #pragma alloc_text(PAGE,FakeModemPnP)
  11. #pragma alloc_text(PAGE,FakeModemDealWithResources)
  12. #endif
  13. NTSTATUS
  14. ForwardIrp(
  15. PDEVICE_OBJECT NextDevice,
  16. PIRP Irp
  17. )
  18. {
  19. IoSkipCurrentIrpStackLocation(Irp);
  20. return IoCallDriver(NextDevice, Irp);
  21. }
  22. NTSTATUS
  23. FakeModemAdapterIoCompletion(
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN PIRP Irp,
  26. IN PKEVENT pdoIoCompletedEvent
  27. )
  28. {
  29. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  30. KeSetEvent(pdoIoCompletedEvent, IO_NO_INCREMENT, FALSE);
  31. return STATUS_MORE_PROCESSING_REQUIRED;
  32. }
  33. NTSTATUS
  34. WaitForLowerDriverToCompleteIrp(
  35. PDEVICE_OBJECT TargetDeviceObject,
  36. PIRP Irp,
  37. PKEVENT Event
  38. )
  39. {
  40. NTSTATUS Status;
  41. KeResetEvent(Event);
  42. IoSetCompletionRoutine(Irp, FakeModemAdapterIoCompletion, Event, TRUE,
  43. TRUE, TRUE);
  44. Status = IoCallDriver(TargetDeviceObject, Irp);
  45. if (Status == STATUS_PENDING)
  46. {
  47. D_ERROR(DbgPrint("MODEM: Waiting for PDO\n");)
  48. KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
  49. }
  50. return Irp->IoStatus.Status;
  51. }
  52. NTSTATUS
  53. FakeModemPnP(
  54. IN PDEVICE_OBJECT DeviceObject,
  55. IN PIRP Irp
  56. )
  57. {
  58. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  59. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  60. KEVENT pdoStartedEvent;
  61. NTSTATUS status;
  62. PDEVICE_RELATIONS deviceRelations = NULL;
  63. PDEVICE_RELATIONS *DeviceRelations;
  64. ULONG newRelationsSize, oldRelationsSize = 0;
  65. switch (irpSp->MinorFunction) {
  66. case IRP_MN_START_DEVICE:
  67. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_START_DEVICE\n");)
  68. // Send this down to the PDO first so the bus driver can setup
  69. // our resources so we can talk to the hardware
  70. KeInitializeEvent(&deviceExtension->PdoStartEvent,
  71. SynchronizationEvent, FALSE);
  72. IoCopyCurrentIrpStackLocationToNext(Irp);
  73. status=WaitForLowerDriverToCompleteIrp(
  74. deviceExtension->LowerDevice, Irp,
  75. &deviceExtension->PdoStartEvent);
  76. if (status == STATUS_SUCCESS)
  77. {
  78. deviceExtension->Started=TRUE;
  79. //
  80. // do something useful with resources
  81. //
  82. FakeModemDealWithResources(DeviceObject, Irp);
  83. }
  84. Irp->IoStatus.Status = status;
  85. Irp->IoStatus.Information=0L;
  86. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  87. return status;
  88. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  89. PDEVICE_RELATIONS CurrentRelations=
  90. (PDEVICE_RELATIONS)Irp->IoStatus.Information;
  91. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_QUERY_DEVICE_RELATIONS type=%d\n",irpSp->Parameters.QueryDeviceRelations.Type);)
  92. D_PNP(DbgPrint(" Information=%08lx\n",Irp->IoStatus.Information);)
  93. switch (irpSp->Parameters.QueryDeviceRelations.Type )
  94. {
  95. case TargetDeviceRelation:
  96. default: {
  97. IoCopyCurrentIrpStackLocationToNext(Irp);
  98. return IoCallDriver(deviceExtension->LowerDevice, Irp);
  99. }
  100. }
  101. }
  102. case IRP_MN_QUERY_REMOVE_DEVICE:
  103. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_QUERY_REMOVE_DEVICE\n");)
  104. deviceExtension->Removing=TRUE;
  105. return ForwardIrp(deviceExtension->LowerDevice,Irp);
  106. case IRP_MN_CANCEL_REMOVE_DEVICE:
  107. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_CANCEL_REMOVE_DEVICE\n");)
  108. deviceExtension->Removing=FALSE;
  109. return ForwardIrp(deviceExtension->LowerDevice,Irp);
  110. case IRP_MN_SURPRISE_REMOVAL:
  111. // Fall through
  112. case IRP_MN_REMOVE_DEVICE: {
  113. ULONG NewReferenceCount;
  114. NTSTATUS StatusToReturn;
  115. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_REMOVE_DEVICE\n");)
  116. // the device is going away, block new requests
  117. deviceExtension->Removing=TRUE;
  118. // Complete all pending requests
  119. FakeModemKillPendingIrps(DeviceObject);
  120. // send it down to the PDO
  121. IoCopyCurrentIrpStackLocationToNext(Irp);
  122. StatusToReturn=IoCallDriver(deviceExtension->LowerDevice, Irp);
  123. // remove the ref for the AddDevice
  124. NewReferenceCount=InterlockedDecrement
  125. (&deviceExtension->ReferenceCount);
  126. if (NewReferenceCount != 0) {
  127. // Still have outstanding request, wait
  128. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_REMOVE_DEVICE- waiting for refcount to drop, %d\n",NewReferenceCount);)
  129. KeWaitForSingleObject(&deviceExtension->RemoveEvent,
  130. Executive, KernelMode, FALSE, NULL);
  131. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_REMOVE_DEVICE- Done waiting\n");)
  132. }
  133. ASSERT(deviceExtension->ReferenceCount == 0);
  134. IoDetachDevice(deviceExtension->LowerDevice);
  135. IoDeleteDevice(DeviceObject);
  136. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_REMOVE_DEVICE %08lx\n",StatusToReturn);)
  137. return StatusToReturn;
  138. }
  139. case IRP_MN_QUERY_STOP_DEVICE:
  140. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_QUERY_STOP_DEVICE\n");)
  141. if (deviceExtension->OpenCount != 0) {
  142. // no can do
  143. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_QUERY_STOP_DEVICE -- failing\n");)
  144. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  145. IoCompleteRequest( Irp, IO_NO_INCREMENT);
  146. return STATUS_UNSUCCESSFUL;
  147. }
  148. deviceExtension->Started=FALSE;
  149. return ForwardIrp(deviceExtension->LowerDevice,Irp);
  150. case IRP_MN_CANCEL_STOP_DEVICE:
  151. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_CANCEL_STOP_DEVICE\n");)
  152. deviceExtension->Started=TRUE;
  153. return ForwardIrp(deviceExtension->LowerDevice,Irp);
  154. case IRP_MN_STOP_DEVICE:
  155. D_PNP(DbgPrint("FAKEMODEM: IRP_MN_STOP_DEVICE\n");)
  156. deviceExtension->Started=FALSE;
  157. return ForwardIrp(deviceExtension->LowerDevice,Irp);
  158. case IRP_MN_QUERY_CAPABILITIES: {
  159. ULONG i;
  160. KEVENT WaitEvent;
  161. // Send this down to the PDO first
  162. KeInitializeEvent(&WaitEvent, SynchronizationEvent, FALSE);
  163. IoCopyCurrentIrpStackLocationToNext(Irp);
  164. status=WaitForLowerDriverToCompleteIrp
  165. (deviceExtension->LowerDevice, Irp, &WaitEvent);
  166. irpSp = IoGetCurrentIrpStackLocation(Irp);
  167. for (i = PowerSystemUnspecified; i < PowerSystemMaximum; i++)
  168. {
  169. deviceExtension->SystemPowerStateMap[i]=PowerDeviceD3;
  170. }
  171. for (i = PowerSystemWorking; i < PowerSystemHibernate; i++) {
  172. D_POWER(DbgPrint("FAKEMODEM: DevicePower for System %d is %d\n",i,irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceState[i]);)
  173. deviceExtension->SystemPowerStateMap[i]=irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceState[i];
  174. }
  175. deviceExtension->SystemPowerStateMap[PowerSystemWorking]=PowerDeviceD0;
  176. deviceExtension->SystemWake=irpSp->Parameters.DeviceCapabilities.Capabilities->SystemWake;
  177. deviceExtension->DeviceWake=irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceWake;
  178. D_POWER(DbgPrint("FAKEMODEM: DeviceWake=%d, SystemWake=%d\n",
  179. deviceExtension->DeviceWake,
  180. deviceExtension->SystemWake);)
  181. IoCompleteRequest( Irp, IO_NO_INCREMENT);
  182. return status;
  183. }
  184. default:
  185. D_PNP(DbgPrint("FAKEMODEM: PnP IRP, MN func=%d\n",irpSp->MinorFunction);)
  186. return ForwardIrp(deviceExtension->LowerDevice,Irp);
  187. }
  188. // If device has started again then we can continue processing
  189. if (deviceExtension->Started)
  190. {
  191. WriteIrpWorker(DeviceObject);
  192. }
  193. return STATUS_SUCCESS;
  194. }
  195. NTSTATUS
  196. FakeModemDealWithResources(
  197. IN PDEVICE_OBJECT Fdo,
  198. IN PIRP Irp
  199. )
  200. {
  201. NTSTATUS status = STATUS_SUCCESS;
  202. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  203. ULONG count;
  204. ULONG i;
  205. PCM_RESOURCE_LIST pResourceList;
  206. PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
  207. PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialResourceDesc;
  208. PCM_FULL_RESOURCE_DESCRIPTOR pFullResourceDesc = NULL;
  209. // Get resource list
  210. pResourceList = irpSp->Parameters.StartDevice.AllocatedResources;
  211. if (pResourceList != NULL) {
  212. pFullResourceDesc = &pResourceList->List[0];
  213. } else {
  214. pFullResourceDesc=NULL;
  215. }
  216. // Ok, if we have a full resource descriptor. Let's take it apart.
  217. if (pFullResourceDesc) {
  218. pPartialResourceList = &pFullResourceDesc->PartialResourceList;
  219. pPartialResourceDesc = pPartialResourceList->PartialDescriptors;
  220. count = pPartialResourceList->Count;
  221. // Pull out the stuff that is in the full descriptor.
  222. // Now run through the partial resource descriptors looking for the
  223. // port interrupt, and clock rate.
  224. for (i = 0; i < count; i++, pPartialResourceDesc++) {
  225. switch (pPartialResourceDesc->Type) {
  226. case CmResourceTypeMemory: {
  227. D_PNP(DbgPrint("FAKEMODEM: Memory resource at %x, length %d, addressSpace=%d\n",
  228. pPartialResourceDesc->u.Memory.Start.LowPart,
  229. pPartialResourceDesc->u.Memory.Length,
  230. pPartialResourceDesc->Flags
  231. );)
  232. break;
  233. }
  234. case CmResourceTypePort: {
  235. D_PNP(DbgPrint("FAKEMODEM: Port resource at %x, length %d, addressSpace=%d\n",
  236. pPartialResourceDesc->u.Port.Start.LowPart,
  237. pPartialResourceDesc->u.Port.Length,
  238. pPartialResourceDesc->Flags
  239. );)
  240. break;
  241. }
  242. case CmResourceTypeDma: {
  243. D_PNP(DbgPrint("FAKEMODEM: DMA channel %d, port %d, addressSpace=%d\n",
  244. pPartialResourceDesc->u.Dma.Channel,
  245. pPartialResourceDesc->u.Dma.Port
  246. );)
  247. break;
  248. break;
  249. }
  250. case CmResourceTypeInterrupt: {
  251. D_PNP(DbgPrint("FAKEMODEM: Interrupt resource, level=%d, vector=%d, %s\n",
  252. pPartialResourceDesc->u.Interrupt.Level,
  253. pPartialResourceDesc->u.Interrupt.Vector,
  254. (pPartialResourceDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? "Latched" : "Level"
  255. );)
  256. break;
  257. }
  258. default: {
  259. D_PNP(DbgPrint("FAKEMODEM: Other resources\n");)
  260. break;
  261. }
  262. }
  263. }
  264. }
  265. return status;
  266. }