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