Sync with trunk head (part 1 or 2)
[reactos.git] / drivers / bus / acpi / main.c
1 #include <ntddk.h>
2
3 #include <acpi.h>
4 #include <acpisys.h>
5
6 #include <acpi_bus.h>
7 #include <acpi_drivers.h>
8
9 #include <acpiioct.h>
10 #include <poclass.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 #ifdef ALLOC_PRAGMA
16 #pragma alloc_text (INIT, DriverEntry)
17 #pragma alloc_text (PAGE, Bus_AddDevice)
18
19 #endif
20
21 extern struct acpi_device *sleep_button;
22 extern struct acpi_device *power_button;
23
24 NTSTATUS
25 NTAPI
26 Bus_AddDevice(
27 PDRIVER_OBJECT DriverObject,
28 PDEVICE_OBJECT PhysicalDeviceObject
29 )
30
31 {
32 NTSTATUS status;
33 PDEVICE_OBJECT deviceObject = NULL;
34 PFDO_DEVICE_DATA deviceData = NULL;
35 PWCHAR deviceName = NULL;
36 #ifndef NDEBUG
37 ULONG nameLength;
38 #endif
39
40 PAGED_CODE ();
41
42 DPRINT("Add Device: 0x%p\n", PhysicalDeviceObject);
43
44 DPRINT("#################### Bus_CreateClose Creating FDO Device ####################\n");
45 status = IoCreateDevice(DriverObject,
46 sizeof(FDO_DEVICE_DATA),
47 NULL,
48 FILE_DEVICE_ACPI,
49 FILE_DEVICE_SECURE_OPEN,
50 TRUE,
51 &deviceObject);
52 if (!NT_SUCCESS(status))
53 {
54 DPRINT1("IoCreateDevice() failed with status 0x%X\n", status);
55 goto End;
56 }
57
58 deviceData = (PFDO_DEVICE_DATA) deviceObject->DeviceExtension;
59 RtlZeroMemory (deviceData, sizeof (FDO_DEVICE_DATA));
60
61 //
62 // Set the initial state of the FDO
63 //
64
65 INITIALIZE_PNP_STATE(deviceData->Common);
66
67 deviceData->Common.IsFDO = TRUE;
68
69 deviceData->Common.Self = deviceObject;
70
71 ExInitializeFastMutex (&deviceData->Mutex);
72
73 InitializeListHead (&deviceData->ListOfPDOs);
74
75 // Set the PDO for use with PlugPlay functions
76
77 deviceData->UnderlyingPDO = PhysicalDeviceObject;
78
79 //
80 // Set the initial powerstate of the FDO
81 //
82
83 deviceData->Common.DevicePowerState = PowerDeviceUnspecified;
84 deviceData->Common.SystemPowerState = PowerSystemWorking;
85
86 deviceObject->Flags |= DO_POWER_PAGABLE;
87
88 //
89 // Attach our FDO to the device stack.
90 // The return value of IoAttachDeviceToDeviceStack is the top of the
91 // attachment chain. This is where all the IRPs should be routed.
92 //
93
94 deviceData->NextLowerDriver = IoAttachDeviceToDeviceStack (
95 deviceObject,
96 PhysicalDeviceObject);
97
98 if (NULL == deviceData->NextLowerDriver) {
99
100 status = STATUS_NO_SUCH_DEVICE;
101 goto End;
102 }
103
104
105 #ifndef NDEBUG
106 //
107 // We will demonstrate here the step to retrieve the name of the PDO
108 //
109
110 status = IoGetDeviceProperty (PhysicalDeviceObject,
111 DevicePropertyPhysicalDeviceObjectName,
112 0,
113 NULL,
114 &nameLength);
115
116 if (status != STATUS_BUFFER_TOO_SMALL)
117 {
118 DPRINT1("AddDevice:IoGDP failed (0x%x)\n", status);
119 goto End;
120 }
121
122 deviceName = ExAllocatePoolWithTag (NonPagedPool,
123 nameLength, 'IPCA');
124
125 if (NULL == deviceName) {
126 DPRINT1("AddDevice: no memory to alloc for deviceName(0x%x)\n", nameLength);
127 status = STATUS_INSUFFICIENT_RESOURCES;
128 goto End;
129 }
130
131 status = IoGetDeviceProperty (PhysicalDeviceObject,
132 DevicePropertyPhysicalDeviceObjectName,
133 nameLength,
134 deviceName,
135 &nameLength);
136
137 if (!NT_SUCCESS (status)) {
138
139 DPRINT1("AddDevice:IoGDP(2) failed (0x%x)", status);
140 goto End;
141 }
142
143 DPRINT("AddDevice: %p to %p->%p (%ws) \n",
144 deviceObject,
145 deviceData->NextLowerDriver,
146 PhysicalDeviceObject,
147 deviceName);
148
149 #endif
150
151 //
152 // We are done with initializing, so let's indicate that and return.
153 // This should be the final step in the AddDevice process.
154 //
155 deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
156
157 End:
158 if (deviceName){
159 ExFreePool(deviceName);
160 }
161 if (!NT_SUCCESS(status) && deviceObject){
162 if (deviceData && deviceData->NextLowerDriver){
163 IoDetachDevice (deviceData->NextLowerDriver);
164 }
165 IoDeleteDevice (deviceObject);
166 }
167 return status;
168
169 }
170
171 NTSTATUS
172 NTAPI
173 ACPIDispatchCreateClose(
174 IN PDEVICE_OBJECT DeviceObject,
175 IN PIRP Irp)
176 {
177 Irp->IoStatus.Status = STATUS_SUCCESS;
178 Irp->IoStatus.Information = 0;
179
180 IoCompleteRequest(Irp, IO_NO_INCREMENT);
181
182 return STATUS_SUCCESS;
183 }
184
185 VOID
186 NTAPI
187 ButtonWaitThread(PVOID Context)
188 {
189 PIRP Irp = Context;
190 int result;
191 struct acpi_bus_event event;
192 ULONG ButtonEvent;
193
194 while (ACPI_SUCCESS(result = acpi_bus_receive_event(&event)) &&
195 event.type != ACPI_BUTTON_NOTIFY_STATUS);
196
197 if (!ACPI_SUCCESS(result))
198 {
199 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
200 }
201 else
202 {
203 if (strstr(event.bus_id, "PWRF"))
204 ButtonEvent = SYS_BUTTON_POWER;
205 else if (strstr(event.bus_id, "SLPF"))
206 ButtonEvent = SYS_BUTTON_SLEEP;
207 else
208 ButtonEvent = 0;
209
210 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &ButtonEvent, sizeof(ButtonEvent));
211 Irp->IoStatus.Status = STATUS_SUCCESS;
212 Irp->IoStatus.Information = sizeof(ULONG);
213 }
214
215 IoCompleteRequest(Irp, IO_NO_INCREMENT);
216 }
217
218
219 NTSTATUS
220 NTAPI
221 ACPIDispatchDeviceControl(
222 IN PDEVICE_OBJECT DeviceObject,
223 IN PIRP Irp)
224 {
225 PIO_STACK_LOCATION irpStack;
226 NTSTATUS status = STATUS_NOT_SUPPORTED;
227 PCOMMON_DEVICE_DATA commonData;
228 ULONG Caps = 0;
229 HANDLE ThreadHandle;
230
231 PAGED_CODE ();
232
233 irpStack = IoGetCurrentIrpStackLocation (Irp);
234 ASSERT (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction);
235
236 commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
237
238 Irp->IoStatus.Information = 0;
239
240 if (!commonData->IsFDO)
241 {
242 switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
243 {
244 case IOCTL_ACPI_EVAL_METHOD:
245 status = Bus_PDO_EvalMethod((PPDO_DEVICE_DATA)commonData,
246 Irp);
247 break;
248
249 case IOCTL_GET_SYS_BUTTON_CAPS:
250 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
251 {
252 status = STATUS_BUFFER_TOO_SMALL;
253 break;
254 }
255
256 if (wcsstr(((PPDO_DEVICE_DATA)commonData)->HardwareIDs, L"PNP0C0D"))
257 {
258 DPRINT1("Lid button reported to power manager\n");
259 Caps |= SYS_BUTTON_LID;
260 }
261 else if (((PPDO_DEVICE_DATA)commonData)->AcpiHandle == NULL)
262 {
263 /* We have to return both at the same time because since we
264 * have a NULL handle we are the fixed feature DO and we will
265 * only be called once (not once per device)
266 */
267 if (power_button)
268 {
269 DPRINT1("Fixed power button reported to power manager\n");
270 Caps |= SYS_BUTTON_POWER;
271 }
272 if (sleep_button)
273 {
274 DPRINT1("Fixed sleep button reported to power manager\n");
275 Caps |= SYS_BUTTON_SLEEP;
276 }
277 }
278 else if (wcsstr(((PPDO_DEVICE_DATA)commonData)->HardwareIDs, L"PNP0C0C"))
279 {
280 DPRINT1("Control method power button reported to power manager\n");
281 Caps |= SYS_BUTTON_POWER;
282 }
283 else if (wcsstr(((PPDO_DEVICE_DATA)commonData)->HardwareIDs, L"PNP0C0E"))
284 {
285 DPRINT1("Control method sleep reported to power manager\n");
286 Caps |= SYS_BUTTON_SLEEP;
287 }
288 else
289 {
290 DPRINT1("IOCTL_GET_SYS_BUTTON_CAPS sent to a non-button device\n");
291 status = STATUS_INVALID_PARAMETER;
292 }
293
294 if (Caps != 0)
295 {
296 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &Caps, sizeof(Caps));
297 Irp->IoStatus.Information = sizeof(Caps);
298 status = STATUS_SUCCESS;
299 }
300 break;
301
302 case IOCTL_GET_SYS_BUTTON_EVENT:
303 PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0, ButtonWaitThread, Irp);
304 ZwClose(ThreadHandle);
305
306 status = STATUS_PENDING;
307 break;
308
309 default:
310 DPRINT1("Unsupported IOCTL: %x\n", irpStack->Parameters.DeviceIoControl.IoControlCode);
311 break;
312 }
313 }
314 else
315 DPRINT1("IOCTL sent to the ACPI FDO! Kill the caller!\n");
316
317 if (status != STATUS_PENDING)
318 {
319 Irp->IoStatus.Status = status;
320 IoCompleteRequest(Irp, IO_NO_INCREMENT);
321 }
322 else
323 IoMarkIrpPending(Irp);
324
325 return status;
326 }
327
328 NTSTATUS
329 NTAPI
330 DriverEntry (
331 PDRIVER_OBJECT DriverObject,
332 PUNICODE_STRING RegistryPath
333 )
334 {
335 DPRINT("Driver Entry \n");
336
337 //
338 // Set entry points into the driver
339 //
340 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ACPIDispatchDeviceControl;
341 DriverObject->MajorFunction [IRP_MJ_PNP] = Bus_PnP;
342 DriverObject->MajorFunction [IRP_MJ_POWER] = Bus_Power;
343 DriverObject->MajorFunction [IRP_MJ_CREATE] = ACPIDispatchCreateClose;
344 DriverObject->MajorFunction [IRP_MJ_CLOSE] = ACPIDispatchCreateClose;
345
346 DriverObject->DriverExtension->AddDevice = Bus_AddDevice;
347
348 return STATUS_SUCCESS;
349 }