1 /*
2 * PROJECT: ReactOS InPort (Bus) Mouse Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Plug and Play requests handling
5 * COPYRIGHT: Copyright 2020 Dmitry Borisov (di.sean@protonmail.com)
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include "inport.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FUNCTIONS ******************************************************************/
16
17 CODE_SEG("PAGE")
18 NTSTATUS
19 NTAPI
InPortStartDevice(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)20 InPortStartDevice(
21 _In_ PDEVICE_OBJECT DeviceObject,
22 _Inout_ PIRP Irp)
23 {
24 NTSTATUS Status;
25 PCM_RESOURCE_LIST AllocatedResources, AllocatedResourcesTranslated;
26 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, DescriptorTranslated;
27 ULONG i;
28 ULONG RawVector;
29 BOOLEAN FoundBasePort = FALSE, FoundIrq = FALSE;
30 PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
31 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
32
33 PAGED_CODE();
34
35 ASSERT(DeviceExtension->State == dsStopped);
36
37 if (!IoForwardIrpSynchronously(DeviceExtension->Ldo, Irp))
38 {
39 Status = STATUS_UNSUCCESSFUL;
40 goto Complete;
41 }
42 Status = Irp->IoStatus.Status;
43 if (!NT_SUCCESS(Status))
44 {
45 DPRINT1("LDO failed to start 0x%X\n", Status);
46 goto Complete;
47 }
48
49 AllocatedResources = IrpSp->Parameters.StartDevice.AllocatedResources;
50 AllocatedResourcesTranslated = IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated;
51 if (!AllocatedResources || !AllocatedResourcesTranslated)
52 {
53 DPRINT1("No allocated resources\n");
54 Status = STATUS_INSUFFICIENT_RESOURCES;
55 goto Complete;
56 }
57
58 if (AllocatedResources->Count != 1)
59 DPRINT1("Expected FullList count is 1, got %d\n", AllocatedResources->Count);
60
61 for (i = 0; i < AllocatedResources->List[0].PartialResourceList.Count; i++)
62 {
63 Descriptor = &AllocatedResources->List[0].PartialResourceList.PartialDescriptors[i];
64 DescriptorTranslated = &AllocatedResourcesTranslated->List[0].PartialResourceList.PartialDescriptors[i];
65
66 switch (Descriptor->Type)
67 {
68 case CmResourceTypePort:
69 {
70 DPRINT("[%p:%X:%X] I/O ports at [%p-%p]\n",
71 Descriptor,
72 Descriptor->ShareDisposition,
73 Descriptor->Flags,
74 Descriptor->u.Port.Start.LowPart,
75 Descriptor->u.Port.Start.LowPart + (Descriptor->u.Port.Length - 1));
76
77 if (!FoundBasePort)
78 {
79 DeviceExtension->IoBase = ULongToPtr(Descriptor->u.Port.Start.u.LowPart);
80
81 FoundBasePort = TRUE;
82 }
83
84 break;
85 }
86
87 case CmResourceTypeInterrupt:
88 {
89 DPRINT("[%p:%X:%X] INT Vec %d Lev %d Aff %IX\n",
90 Descriptor,
91 Descriptor->ShareDisposition,
92 Descriptor->Flags,
93 Descriptor->u.Interrupt.Vector,
94 Descriptor->u.Interrupt.Level,
95 Descriptor->u.Interrupt.Affinity);
96
97 if (!FoundIrq)
98 {
99 DeviceExtension->InterruptVector = DescriptorTranslated->u.Interrupt.Vector;
100 DeviceExtension->InterruptLevel = (KIRQL)DescriptorTranslated->u.Interrupt.Level;
101 if (DescriptorTranslated->Flags & CM_RESOURCE_INTERRUPT_LATCHED)
102 DeviceExtension->InterruptMode = Latched;
103 else
104 DeviceExtension->InterruptMode = LevelSensitive;
105 DeviceExtension->InterruptShared = (DescriptorTranslated->ShareDisposition == CmResourceShareShared);
106 DeviceExtension->InterruptAffinity = DescriptorTranslated->u.Interrupt.Affinity;
107 RawVector = Descriptor->u.Interrupt.Vector;
108
109 FoundIrq = TRUE;
110 }
111
112 break;
113 }
114
115 default:
116 DPRINT("[%p:%X:%X] Unrecognized resource type %X\n",
117 Descriptor,
118 Descriptor->ShareDisposition,
119 Descriptor->Flags,
120 Descriptor->Type);
121 break;
122 }
123 }
124
125 if (!FoundBasePort || !FoundIrq)
126 {
127 DPRINT1("The device resources were not found\n");
128 Status = STATUS_DEVICE_CONFIGURATION_ERROR;
129 goto Complete;
130 }
131
132 DPRINT("I/O base at %p\n", DeviceExtension->IoBase);
133 DPRINT("IRQ %d\n", RawVector);
134
135 Status = InPortWmiRegistration(DeviceExtension);
136 if (!NT_SUCCESS(Status))
137 {
138 DPRINT1("WMI registration failed 0x%X\n", Status);
139 goto Complete;
140 }
141
142 InPortInitializeMouse(DeviceExtension);
143
144 Status = IoConnectInterrupt(&DeviceExtension->InterruptObject,
145 InPortIsr,
146 DeviceExtension,
147 NULL,
148 DeviceExtension->InterruptVector,
149 DeviceExtension->InterruptLevel,
150 DeviceExtension->InterruptLevel,
151 DeviceExtension->InterruptMode,
152 DeviceExtension->InterruptShared,
153 DeviceExtension->InterruptAffinity,
154 FALSE);
155 if (!NT_SUCCESS(Status))
156 {
157 DPRINT1("Could not connect to interrupt %d\n", DeviceExtension->InterruptVector);
158 goto Complete;
159 }
160
161 KeSynchronizeExecution(DeviceExtension->InterruptObject,
162 InPortStartMouse,
163 DeviceExtension);
164
165 DeviceExtension->State = dsStarted;
166
167 Complete:
168 Irp->IoStatus.Status = Status;
169 IoCompleteRequest(Irp, IO_NO_INCREMENT);
170
171 return Status;
172 }
173
174 CODE_SEG("PAGE")
175 NTSTATUS
176 NTAPI
InPortRemoveDevice(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)177 InPortRemoveDevice(
178 _In_ PDEVICE_OBJECT DeviceObject,
179 _Inout_ PIRP Irp)
180 {
181 NTSTATUS Status;
182 BOOLEAN IsStarted;
183 PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
184
185 PAGED_CODE();
186
187 InPortWmiDeRegistration(DeviceExtension);
188
189 IsStarted = (DeviceExtension->State == dsStarted);
190
191 DeviceExtension->State = dsRemoved;
192
193 Irp->IoStatus.Status = STATUS_SUCCESS;
194 IoSkipCurrentIrpStackLocation(Irp);
195 Status = IoCallDriver(DeviceExtension->Ldo, Irp);
196
197 IoReleaseRemoveLockAndWait(&DeviceExtension->RemoveLock, Irp);
198
199 /* Device is active */
200 if (IsStarted)
201 {
202 KeSynchronizeExecution(DeviceExtension->InterruptObject,
203 InPortStopMouse,
204 DeviceExtension);
205
206 IoDisconnectInterrupt(DeviceExtension->InterruptObject);
207
208 /* Flush DPC for ISR */
209 KeFlushQueuedDpcs();
210 }
211
212 IoDetachDevice(DeviceExtension->Ldo);
213 IoDeleteDevice(DeviceObject);
214
215 return Status;
216 }
217
218 CODE_SEG("PAGE")
219 NTSTATUS
220 NTAPI
InPortPnp(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)221 InPortPnp(
222 _In_ PDEVICE_OBJECT DeviceObject,
223 _Inout_ PIRP Irp)
224 {
225 NTSTATUS Status;
226 PINPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
227 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
228
229 PAGED_CODE();
230
231 DPRINT("%s(%p, %p) %X\n",
232 __FUNCTION__, DeviceObject, Irp, IrpSp->MinorFunction);
233
234 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp);
235 if (!NT_SUCCESS(Status))
236 {
237 Irp->IoStatus.Information = 0;
238 Irp->IoStatus.Status = Status;
239 IoCompleteRequest(Irp, IO_NO_INCREMENT);
240
241 return Status;
242 }
243
244 switch (IrpSp->MinorFunction)
245 {
246 case IRP_MN_START_DEVICE:
247 Status = InPortStartDevice(DeviceObject, Irp);
248 break;
249
250 case IRP_MN_REMOVE_DEVICE:
251 return InPortRemoveDevice(DeviceObject, Irp);
252
253 case IRP_MN_QUERY_STOP_DEVICE:
254 /* Device cannot work with other resources */
255 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
256 IoCompleteRequest(Irp, IO_NO_INCREMENT);
257 break;
258
259 case IRP_MN_QUERY_REMOVE_DEVICE:
260 case IRP_MN_CANCEL_REMOVE_DEVICE:
261 case IRP_MN_STOP_DEVICE:
262 case IRP_MN_CANCEL_STOP_DEVICE:
263 case IRP_MN_SURPRISE_REMOVAL:
264 Irp->IoStatus.Status = STATUS_SUCCESS;
265 IoSkipCurrentIrpStackLocation(Irp);
266 Status = IoCallDriver(DeviceExtension->Ldo, Irp);
267 break;
268
269 default:
270 IoSkipCurrentIrpStackLocation(Irp);
271 Status = IoCallDriver(DeviceExtension->Ldo, Irp);
272 break;
273 }
274
275 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp);
276
277 return Status;
278 }
279