xref: /reactos/drivers/input/inport/pnp.c (revision 3adf4508)
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