11 PDRIVER_OBJECT DriverObject
,
12 PUNICODE_STRING RegistryPath
16 #pragma alloc_text (INIT, DriverEntry)
17 #pragma alloc_text (PAGE, Bus_AddDevice)
21 extern struct acpi_device
*sleep_button
;
22 extern struct acpi_device
*power_button
;
24 UNICODE_STRING ProcessorHardwareIds
= {0, 0, NULL
};
25 LPWSTR ProcessorIdString
= NULL
;
26 LPWSTR ProcessorNameString
= NULL
;
32 PDRIVER_OBJECT DriverObject
,
33 PDEVICE_OBJECT PhysicalDeviceObject
38 PDEVICE_OBJECT deviceObject
= NULL
;
39 PFDO_DEVICE_DATA deviceData
= NULL
;
41 PWCHAR deviceName
= NULL
;
47 DPRINT("Add Device: 0x%p\n", PhysicalDeviceObject
);
49 DPRINT("#################### Bus_CreateClose Creating FDO Device ####################\n");
50 status
= IoCreateDevice(DriverObject
,
51 sizeof(FDO_DEVICE_DATA
),
54 FILE_DEVICE_SECURE_OPEN
,
57 if (!NT_SUCCESS(status
))
59 DPRINT1("IoCreateDevice() failed with status 0x%X\n", status
);
63 deviceData
= (PFDO_DEVICE_DATA
) deviceObject
->DeviceExtension
;
64 RtlZeroMemory (deviceData
, sizeof (FDO_DEVICE_DATA
));
67 // Set the initial state of the FDO
70 INITIALIZE_PNP_STATE(deviceData
->Common
);
72 deviceData
->Common
.IsFDO
= TRUE
;
74 deviceData
->Common
.Self
= deviceObject
;
76 ExInitializeFastMutex (&deviceData
->Mutex
);
78 InitializeListHead (&deviceData
->ListOfPDOs
);
80 // Set the PDO for use with PlugPlay functions
82 deviceData
->UnderlyingPDO
= PhysicalDeviceObject
;
85 // Set the initial powerstate of the FDO
88 deviceData
->Common
.DevicePowerState
= PowerDeviceUnspecified
;
89 deviceData
->Common
.SystemPowerState
= PowerSystemWorking
;
91 deviceObject
->Flags
|= DO_POWER_PAGABLE
;
94 // Attach our FDO to the device stack.
95 // The return value of IoAttachDeviceToDeviceStack is the top of the
96 // attachment chain. This is where all the IRPs should be routed.
99 deviceData
->NextLowerDriver
= IoAttachDeviceToDeviceStack (
101 PhysicalDeviceObject
);
103 if (NULL
== deviceData
->NextLowerDriver
) {
105 status
= STATUS_NO_SUCH_DEVICE
;
112 // We will demonstrate here the step to retrieve the name of the PDO
115 status
= IoGetDeviceProperty (PhysicalDeviceObject
,
116 DevicePropertyPhysicalDeviceObjectName
,
121 if (status
!= STATUS_BUFFER_TOO_SMALL
)
123 DPRINT1("AddDevice:IoGDP failed (0x%x)\n", status
);
127 deviceName
= ExAllocatePoolWithTag(NonPagedPool
, nameLength
, 'MpcA');
129 if (NULL
== deviceName
) {
130 DPRINT1("AddDevice: no memory to alloc for deviceName(0x%x)\n", nameLength
);
131 status
= STATUS_INSUFFICIENT_RESOURCES
;
135 status
= IoGetDeviceProperty (PhysicalDeviceObject
,
136 DevicePropertyPhysicalDeviceObjectName
,
141 if (!NT_SUCCESS (status
)) {
143 DPRINT1("AddDevice:IoGDP(2) failed (0x%x)", status
);
147 DPRINT("AddDevice: %p to %p->%p (%ws) \n",
149 deviceData
->NextLowerDriver
,
150 PhysicalDeviceObject
,
156 // We are done with initializing, so let's indicate that and return.
157 // This should be the final step in the AddDevice process.
159 deviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
164 ExFreePoolWithTag(deviceName
, 'MpcA');
167 if (!NT_SUCCESS(status
) && deviceObject
){
168 if (deviceData
&& deviceData
->NextLowerDriver
){
169 IoDetachDevice (deviceData
->NextLowerDriver
);
171 IoDeleteDevice (deviceObject
);
179 ACPIDispatchCreateClose(
180 IN PDEVICE_OBJECT DeviceObject
,
183 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
184 Irp
->IoStatus
.Information
= 0;
186 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
188 return STATUS_SUCCESS
;
193 ButtonWaitThread(PVOID Context
)
197 struct acpi_bus_event event
;
200 while (ACPI_SUCCESS(result
= acpi_bus_receive_event(&event
)) &&
201 event
.type
!= ACPI_BUTTON_NOTIFY_STATUS
);
203 if (!ACPI_SUCCESS(result
))
205 Irp
->IoStatus
.Status
= STATUS_UNSUCCESSFUL
;
209 if (strstr(event
.bus_id
, "PWRF"))
210 ButtonEvent
= SYS_BUTTON_POWER
;
211 else if (strstr(event
.bus_id
, "SLPF"))
212 ButtonEvent
= SYS_BUTTON_SLEEP
;
216 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, &ButtonEvent
, sizeof(ButtonEvent
));
217 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
218 Irp
->IoStatus
.Information
= sizeof(ULONG
);
221 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
227 ACPIDispatchDeviceControl(
228 IN PDEVICE_OBJECT DeviceObject
,
231 PIO_STACK_LOCATION irpStack
;
232 NTSTATUS status
= STATUS_NOT_SUPPORTED
;
233 PCOMMON_DEVICE_DATA commonData
;
239 irpStack
= IoGetCurrentIrpStackLocation (Irp
);
240 ASSERT (IRP_MJ_DEVICE_CONTROL
== irpStack
->MajorFunction
);
242 commonData
= (PCOMMON_DEVICE_DATA
) DeviceObject
->DeviceExtension
;
244 Irp
->IoStatus
.Information
= 0;
246 if (!commonData
->IsFDO
)
248 switch (irpStack
->Parameters
.DeviceIoControl
.IoControlCode
)
250 case IOCTL_ACPI_EVAL_METHOD
:
251 status
= Bus_PDO_EvalMethod((PPDO_DEVICE_DATA
)commonData
,
255 case IOCTL_GET_SYS_BUTTON_CAPS
:
256 if (irpStack
->Parameters
.DeviceIoControl
.OutputBufferLength
< sizeof(ULONG
))
258 status
= STATUS_BUFFER_TOO_SMALL
;
262 if (wcsstr(((PPDO_DEVICE_DATA
)commonData
)->HardwareIDs
, L
"PNP0C0D"))
264 DPRINT1("Lid button reported to power manager\n");
265 Caps
|= SYS_BUTTON_LID
;
267 else if (((PPDO_DEVICE_DATA
)commonData
)->AcpiHandle
== NULL
)
269 /* We have to return both at the same time because since we
270 * have a NULL handle we are the fixed feature DO and we will
271 * only be called once (not once per device)
275 DPRINT("Fixed power button reported to power manager\n");
276 Caps
|= SYS_BUTTON_POWER
;
280 DPRINT("Fixed sleep button reported to power manager\n");
281 Caps
|= SYS_BUTTON_SLEEP
;
284 else if (wcsstr(((PPDO_DEVICE_DATA
)commonData
)->HardwareIDs
, L
"PNP0C0C"))
286 DPRINT("Control method power button reported to power manager\n");
287 Caps
|= SYS_BUTTON_POWER
;
289 else if (wcsstr(((PPDO_DEVICE_DATA
)commonData
)->HardwareIDs
, L
"PNP0C0E"))
291 DPRINT("Control method sleep reported to power manager\n");
292 Caps
|= SYS_BUTTON_SLEEP
;
296 DPRINT1("IOCTL_GET_SYS_BUTTON_CAPS sent to a non-button device\n");
297 status
= STATUS_INVALID_PARAMETER
;
302 RtlCopyMemory(Irp
->AssociatedIrp
.SystemBuffer
, &Caps
, sizeof(Caps
));
303 Irp
->IoStatus
.Information
= sizeof(Caps
);
304 status
= STATUS_SUCCESS
;
308 case IOCTL_GET_SYS_BUTTON_EVENT
:
309 PsCreateSystemThread(&ThreadHandle
, THREAD_ALL_ACCESS
, 0, 0, 0, ButtonWaitThread
, Irp
);
310 ZwClose(ThreadHandle
);
312 status
= STATUS_PENDING
;
316 DPRINT1("Unsupported IOCTL: %x\n", irpStack
->Parameters
.DeviceIoControl
.IoControlCode
);
321 DPRINT1("IOCTL sent to the ACPI FDO! Kill the caller!\n");
323 if (status
!= STATUS_PENDING
)
325 Irp
->IoStatus
.Status
= status
;
326 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
329 IoMarkIrpPending(Irp
);
336 AcpiRegOpenKey(IN HANDLE ParentKeyHandle
,
338 IN ACCESS_MASK DesiredAccess
,
339 OUT HANDLE KeyHandle
)
341 OBJECT_ATTRIBUTES ObjectAttributes
;
344 RtlInitUnicodeString(&Name
, KeyName
);
346 InitializeObjectAttributes(&ObjectAttributes
,
348 OBJ_CASE_INSENSITIVE
,
352 return ZwOpenKey(KeyHandle
,
359 AcpiRegQueryValue(IN HANDLE KeyHandle
,
361 OUT PULONG Type OPTIONAL
,
362 OUT PVOID Data OPTIONAL
,
363 IN OUT PULONG DataLength OPTIONAL
)
365 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
367 ULONG BufferLength
= 0;
370 RtlInitUnicodeString(&Name
, ValueName
);
372 if (DataLength
!= NULL
)
373 BufferLength
= *DataLength
;
375 /* Check if the caller provided a valid buffer */
376 if ((Data
!= NULL
) && (BufferLength
!= 0))
378 BufferLength
+= FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION
, Data
);
380 /* Allocate memory for the value */
381 ValueInfo
= ExAllocatePoolWithTag(PagedPool
, BufferLength
, 'MpcA');
382 if (ValueInfo
== NULL
)
383 return STATUS_NO_MEMORY
;
387 /* Caller didn't provide a valid buffer, assume he wants the size only */
392 /* Query the value */
393 Status
= ZwQueryValueKey(KeyHandle
,
395 KeyValuePartialInformation
,
400 if (DataLength
!= NULL
)
401 *DataLength
= BufferLength
;
403 /* Check if we have the size only */
404 if (ValueInfo
== NULL
)
406 /* Check for unexpected status */
407 if ((Status
!= STATUS_BUFFER_OVERFLOW
) &&
408 (Status
!= STATUS_BUFFER_TOO_SMALL
))
414 Status
= STATUS_SUCCESS
;
416 /* Otherwise the caller wanted data back, check if we got it */
417 else if (NT_SUCCESS(Status
))
420 *Type
= ValueInfo
->Type
;
423 RtlMoveMemory(Data
, ValueInfo
->Data
, ValueInfo
->DataLength
);
425 /* if the type is REG_SZ and data is not 0-terminated
426 * and there is enough space in the buffer NT appends a \0 */
427 if (((ValueInfo
->Type
== REG_SZ
) ||
428 (ValueInfo
->Type
== REG_EXPAND_SZ
) ||
429 (ValueInfo
->Type
== REG_MULTI_SZ
)) &&
430 (ValueInfo
->DataLength
<= *DataLength
- sizeof(WCHAR
)))
432 WCHAR
*ptr
= (WCHAR
*)((ULONG_PTR
)Data
+ ValueInfo
->DataLength
);
433 if ((ptr
> (WCHAR
*)Data
) && ptr
[-1])
438 /* Free the memory and return status */
439 if (ValueInfo
!= NULL
)
441 ExFreePoolWithTag(ValueInfo
, 'MpcA');
449 GetProcessorInformation(VOID
)
451 LPWSTR ProcessorIdentifier
= NULL
;
452 LPWSTR ProcessorVendorIdentifier
= NULL
;
453 LPWSTR HardwareIdsBuffer
= NULL
;
454 HANDLE ProcessorHandle
= NULL
;
455 ULONG Length
= 0, Level1Length
= 0, Level2Length
= 0, Level3Length
= 0;
456 SIZE_T HardwareIdsLength
= 0;
457 SIZE_T VendorIdentifierLength
;
462 DPRINT("GetProcessorInformation()\n");
464 /* Open the key for CPU 0 */
465 Status
= AcpiRegOpenKey(NULL
,
466 L
"\\Registry\\Machine\\Hardware\\Description\\System\\CentralProcessor\\0",
469 if (!NT_SUCCESS(Status
))
471 DPRINT1("Failed to open CentralProcessor registry key: 0x%lx\n", Status
);
475 /* Query the processor identifier length */
476 Status
= AcpiRegQueryValue(ProcessorHandle
,
481 if (!NT_SUCCESS(Status
))
483 DPRINT1("Failed to query Identifier value: 0x%lx\n", Status
);
487 /* Remember the length as fallback for level 1-3 length */
488 Level1Length
= Level2Length
= Level3Length
= Length
;
490 /* Allocate a buffer large enough to be zero terminated */
491 Length
+= sizeof(UNICODE_NULL
);
492 ProcessorIdentifier
= ExAllocatePoolWithTag(PagedPool
, Length
, 'IpcA');
493 if (ProcessorIdentifier
== NULL
)
495 DPRINT1("Failed to allocate 0x%lx bytes\n", Length
);
496 Status
= STATUS_INSUFFICIENT_RESOURCES
;
500 /* Query the processor identifier string */
501 Status
= AcpiRegQueryValue(ProcessorHandle
,
506 if (!NT_SUCCESS(Status
))
508 DPRINT1("Failed to query Identifier value: 0x%lx\n", Status
);
512 /* Query the processor name length */
514 Status
= AcpiRegQueryValue(ProcessorHandle
,
515 L
"ProcessorNameString",
519 if (!NT_SUCCESS(Status
))
521 DPRINT1("Failed to query ProcessorNameString value: 0x%lx\n", Status
);
525 /* Allocate a buffer large enough to be zero terminated */
526 Length
+= sizeof(UNICODE_NULL
);
527 ProcessorNameString
= ExAllocatePoolWithTag(PagedPool
, Length
, 'IpcA');
528 if (ProcessorNameString
== NULL
)
530 DPRINT1("Failed to allocate 0x%lx bytes\n", Length
);
531 Status
= STATUS_INSUFFICIENT_RESOURCES
;
535 /* Query the processor name string */
536 Status
= AcpiRegQueryValue(ProcessorHandle
,
537 L
"ProcessorNameString",
541 if (!NT_SUCCESS(Status
))
543 DPRINT1("Failed to query ProcessorNameString value: 0x%lx\n", Status
);
547 /* Query the vendor identifier length */
549 Status
= AcpiRegQueryValue(ProcessorHandle
,
554 if (!NT_SUCCESS(Status
) || (Length
== 0))
556 DPRINT1("Failed to query VendorIdentifier value: 0x%lx\n", Status
);
560 /* Allocate a buffer large enough to be zero terminated */
561 Length
+= sizeof(UNICODE_NULL
);
562 ProcessorVendorIdentifier
= ExAllocatePoolWithTag(PagedPool
, Length
, 'IpcA');
563 if (ProcessorVendorIdentifier
== NULL
)
565 DPRINT1("Failed to allocate 0x%lx bytes\n", Length
);
566 Status
= STATUS_INSUFFICIENT_RESOURCES
;
570 /* Query the vendor identifier string */
571 Status
= AcpiRegQueryValue(ProcessorHandle
,
574 ProcessorVendorIdentifier
,
576 if (!NT_SUCCESS(Status
))
578 DPRINT1("Failed to query VendorIdentifier value: 0x%lx\n", Status
);
582 /* Change spaces to underscores */
583 for (i
= 0; i
< wcslen(ProcessorIdentifier
); i
++)
585 if (ProcessorIdentifier
[i
] == L
' ')
586 ProcessorIdentifier
[i
] = L
'_';
589 Ptr
= wcsstr(ProcessorIdentifier
, L
"Stepping");
593 Level1Length
= (ULONG
)(Ptr
- ProcessorIdentifier
);
596 Ptr
= wcsstr(ProcessorIdentifier
, L
"Model");
600 Level2Length
= (ULONG
)(Ptr
- ProcessorIdentifier
);
603 Ptr
= wcsstr(ProcessorIdentifier
, L
"Family");
607 Level3Length
= (ULONG
)(Ptr
- ProcessorIdentifier
);
610 VendorIdentifierLength
= (USHORT
)wcslen(ProcessorVendorIdentifier
);
612 /* Calculate the size of the full REG_MULTI_SZ data (see swprintf below) */
613 HardwareIdsLength
= (5 + VendorIdentifierLength
+ 3 + Level1Length
+ 1 +
614 1 + VendorIdentifierLength
+ 3 + Level1Length
+ 1 +
615 5 + VendorIdentifierLength
+ 3 + Level2Length
+ 1 +
616 1 + VendorIdentifierLength
+ 3 + Level2Length
+ 1 +
617 5 + VendorIdentifierLength
+ 3 + Level3Length
+ 1 +
618 1 + VendorIdentifierLength
+ 3 + Level3Length
+ 1 +
621 /* Allocate a buffer to the data */
622 HardwareIdsBuffer
= ExAllocatePoolWithTag(PagedPool
, HardwareIdsLength
, 'IpcA');
623 if (HardwareIdsBuffer
== NULL
)
625 Status
= STATUS_INSUFFICIENT_RESOURCES
;
630 Length
+= swprintf(&HardwareIdsBuffer
[Length
], L
"ACPI\\%s_-_%.*s", ProcessorVendorIdentifier
, Level1Length
, ProcessorIdentifier
);
631 HardwareIdsBuffer
[Length
++] = UNICODE_NULL
;
633 Length
+= swprintf(&HardwareIdsBuffer
[Length
], L
"*%s_-_%.*s", ProcessorVendorIdentifier
, Level1Length
, ProcessorIdentifier
);
634 HardwareIdsBuffer
[Length
++] = UNICODE_NULL
;
636 Length
+= swprintf(&HardwareIdsBuffer
[Length
], L
"ACPI\\%s_-_%.*s", ProcessorVendorIdentifier
, Level2Length
, ProcessorIdentifier
);
637 HardwareIdsBuffer
[Length
++] = UNICODE_NULL
;
639 Length
+= swprintf(&HardwareIdsBuffer
[Length
], L
"*%s_-_%.*s", ProcessorVendorIdentifier
, Level2Length
, ProcessorIdentifier
);
640 HardwareIdsBuffer
[Length
++] = UNICODE_NULL
;
642 Length
+= swprintf(&HardwareIdsBuffer
[Length
], L
"ACPI\\%s_-_%.*s", ProcessorVendorIdentifier
, Level3Length
, ProcessorIdentifier
);
643 HardwareIdsBuffer
[Length
++] = UNICODE_NULL
;
645 Length
+= swprintf(&HardwareIdsBuffer
[Length
], L
"*%s_-_%.*s", ProcessorVendorIdentifier
, Level3Length
, ProcessorIdentifier
);
646 HardwareIdsBuffer
[Length
++] = UNICODE_NULL
;
647 HardwareIdsBuffer
[Length
++] = UNICODE_NULL
;
649 /* Make sure we counted correctly */
650 NT_ASSERT(Length
* sizeof(WCHAR
) == HardwareIdsLength
);
652 ProcessorHardwareIds
.Length
= (SHORT
)HardwareIdsLength
;
653 ProcessorHardwareIds
.MaximumLength
= ProcessorHardwareIds
.Length
;
654 ProcessorHardwareIds
.Buffer
= HardwareIdsBuffer
;
656 Length
= (5 + VendorIdentifierLength
+ 3 + Level1Length
+ 1) * sizeof(WCHAR
);
657 ProcessorIdString
= ExAllocatePoolWithTag(PagedPool
, Length
, 'IpcA');
658 if (ProcessorIdString
!= NULL
)
660 Length
= swprintf(ProcessorIdString
, L
"ACPI\\%s_-_%.*s", ProcessorVendorIdentifier
, Level1Length
, ProcessorIdentifier
);
661 ProcessorIdString
[Length
++] = UNICODE_NULL
;
662 DPRINT("ProcessorIdString: %S\n", ProcessorIdString
);
666 if (ProcessorHandle
!= NULL
)
667 ZwClose(ProcessorHandle
);
669 if (ProcessorIdentifier
!= NULL
)
670 ExFreePoolWithTag(ProcessorIdentifier
, 'IpcA');
672 if (ProcessorVendorIdentifier
!= NULL
)
673 ExFreePoolWithTag(ProcessorVendorIdentifier
, 'IpcA');
675 if (!NT_SUCCESS(Status
))
677 if (HardwareIdsBuffer
!= NULL
)
678 ExFreePoolWithTag(HardwareIdsBuffer
, 'IpcA');
687 PDRIVER_OBJECT DriverObject
,
688 PUNICODE_STRING RegistryPath
692 DPRINT("Driver Entry \n");
694 Status
= GetProcessorInformation();
695 if (!NT_SUCCESS(Status
))
702 // Set entry points into the driver
704 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = ACPIDispatchDeviceControl
;
705 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = Bus_PnP
;
706 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = Bus_Power
;
707 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = ACPIDispatchCreateClose
;
708 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = ACPIDispatchCreateClose
;
710 DriverObject
->DriverExtension
->AddDevice
= Bus_AddDevice
;
712 return STATUS_SUCCESS
;