ReactOS 0.4.16-dev-2633-g8dc9e50
acpi.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS ATA Bus Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: ACPI interface with SATA ports, IDE controllers and drives
5 * COPYRIGHT: Copyright 2026 <di.sean@protonmail.com>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include "pciidex.h"
11
12#include <acpiioct.h>
13
14/* FUNCTIONS ******************************************************************/
15
17static
19AtaAcpiEvaluateObject(
25{
26 PIRP Irp;
27 PIO_STACK_LOCATION IoStack;
30 PDEVICE_OBJECT TopDeviceObject;
31
32 /* Get the ACPI bus filter device for this DO */
34
35 /*
36 * We could be called at DISPATCH_LEVEL,
37 * so use IoAllocateIrp() rather going through IoBuildDeviceIoControlRequest().
38 */
39 Irp = IoAllocateIrp(TopDeviceObject->StackSize, 0);
40 if (!Irp)
41 {
43 goto Exit;
44 }
45 Irp->AssociatedIrp.SystemBuffer = InputBuffer;
46 Irp->UserBuffer = OutputBuffer;
48 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
49
50 /*
51 * Submit an asynchronous evaluation request.
52 * Note that _STM should be evaluated while the device queue has been paused,
53 * so we must not cause *any* page faults and use IOCTL_ACPI_EVAL_METHOD.
54 * AtaAcpiEvaluateObject() also has to be non-pageable.
55 */
59 IoStack->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
60 IoStack->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
61
65 &Event,
66 TRUE,
67 TRUE,
68 TRUE);
69
70 Status = IoCallDriver(TopDeviceObject, Irp);
72 {
74 Status = Irp->IoStatus.Status;
75 }
76
78
80 {
82
84 (OutputBuffer->Count == 0))
85 {
86 ERR("Invalid ACPI output buffer\n");
87
89 }
90 }
91
92Exit:
93 ObDereferenceObject(TopDeviceObject);
94 return Status;
95}
96
101{
103 ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*TimingMode))];
107
108 RtlZeroMemory(Buffer, sizeof(Buffer));
109
110 InputBuffer.MethodNameAsUlong = 'MTG_'; // _GTM
112
113 /* Evaluate the _GTM method */
114 Status = AtaAcpiEvaluateObject(DeviceObject,
116 sizeof(InputBuffer),
118 sizeof(Buffer));
119
120 if (!NT_SUCCESS(Status))
121 {
123
124 TRACE("Failed to evaluate the _GTM method, status 0x%lx\n", Status);
125 return FALSE;
126 }
127
128 if (OutputBuffer->Argument[0].DataLength < sizeof(*TimingMode))
129 {
130 ERR("Buffer too small, size %u/%u\n",
131 OutputBuffer->Argument[0].DataLength, sizeof(*TimingMode));
132 return FALSE;
133 }
134
135 if (OutputBuffer->Argument[0].Type != ACPI_METHOD_ARGUMENT_BUFFER)
136 {
137 ERR("Unexpected method type %u\n", OutputBuffer->Argument[0].Type);
138 return FALSE;
139 }
140
141 RtlCopyMemory(TimingMode, OutputBuffer->Argument[0].Data, sizeof(*TimingMode));
142
143 return TRUE;
144}
145
152{
154 PACPI_METHOD_ARGUMENT Argument;
156 ULONG InputSize;
157
158 InputSize = FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) +
159 ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*TimingMode)) +
160 ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*IdBlock1)) +
161 ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*IdBlock2));
162
164 if (!InputBuffer)
165 {
166 ERR("Failed to allocate memory\n");
168 }
169 InputBuffer->MethodNameAsUlong = 'MTS_'; // _STM
171 InputBuffer->ArgumentCount = 3;
172 InputBuffer->Size = InputSize;
173
174 /* Argument 1: The channel timing information block */
175 Argument = InputBuffer->Argument;
176 ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, TimingMode, sizeof(*TimingMode));
177
178 /* Argument 2: The ATA drive ID block */
179 Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
180 Argument->Type = ACPI_METHOD_ARGUMENT_BUFFER;
181 Argument->DataLength = sizeof(*IdBlock1);
182 if (IdBlock1)
183 RtlCopyMemory(Argument->Data, IdBlock1, sizeof(*IdBlock1));
184 else
185 RtlZeroMemory(Argument->Data, sizeof(*IdBlock1));
186
187 /* Argument 3: The ATA drive ID block */
188 Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument);
189 Argument->Type = ACPI_METHOD_ARGUMENT_BUFFER;
190 Argument->DataLength = sizeof(*IdBlock2);
191 if (IdBlock2)
192 RtlCopyMemory(Argument->Data, IdBlock2, sizeof(*IdBlock2));
193 else
194 RtlZeroMemory(Argument->Data, sizeof(*IdBlock2));
195
196 /* Evaluate the _STM method */
197 Status = AtaAcpiEvaluateObject(DeviceObject, InputBuffer, InputSize, NULL, 0);
198 if (!NT_SUCCESS(Status))
199 {
201 INFO("Failed to set transfer timings, status 0x%lx\n", Status);
202 else
203 ERR("Failed to set transfer timings, status 0x%lx\n", Status);
204 }
205
207 return Status;
208}
209
210CODE_SEG("PAGE")
211PVOID
214{
217 ULONG RetryCount, OutputSize;
219
220 PAGED_CODE();
221 /*
222 * We invoke this routine within the PnP START handler only,
223 * and thus specify that the code is in a pageable section.
224 */
226
227 InputBuffer.MethodNameAsUlong = 'FTG_'; // _GTF
229
230 /*
231 * The output buffer must be large enough to hold the list of ATA commands to the drive.
232 * We assume that 10 commands is the common case.
233 */
234 OutputSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
236
237 for (RetryCount = 0; RetryCount < 2; ++RetryCount)
238 {
240 if (!OutputBuffer)
241 {
242 ERR("Failed to allocate memory of size %lu\n", OutputSize);
243 return NULL;
244 }
245
246 /* Evaluate the _GTF method */
247 Status = AtaAcpiEvaluateObject(DeviceObject,
249 sizeof(InputBuffer),
251 OutputSize);
252
253 /* Increase the allocation size if it's too small */
255 {
256 OutputSize = OutputBuffer->Length;
257
259 continue;
260 }
261
262 break;
263 }
264
265 if (!NT_SUCCESS(Status))
266 goto Cleanup;
267
268 if (OutputBuffer->Argument[0].Type != ACPI_METHOD_ARGUMENT_BUFFER)
269 {
270 ERR("Unexpected method type %u\n", OutputBuffer->Argument[0].Type);
271 goto Cleanup;
272 }
273
274 if (OutputBuffer->Argument[0].DataLength % sizeof(ATA_ACPI_TASK_FILE))
275 {
276 ERR("Incorrect command stream length %u\n", OutputBuffer->Argument[0].DataLength);
277 goto Cleanup;
278 }
279
280 if (OutputBuffer->Argument[0].DataLength == 0)
281 {
282 WARN("Empty command list\n");
283 goto Cleanup;
284 }
285
286 return OutputBuffer;
287
288Cleanup:
290
291 return NULL;
292}
293
294CODE_SEG("PAGE")
295VOID
299{
301 PACPI_METHOD_ARGUMENT Argument;
303 ULONG InputSize;
304
305 PAGED_CODE();
307
308 InputSize = FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) +
309 ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*IdBlock));
310
312 if (!InputBuffer)
313 {
314 ERR("Failed to allocate memory\n");
315 return;
316 }
317 InputBuffer->MethodNameAsUlong = 'DDS_'; // _SDD
319 InputBuffer->ArgumentCount = 1;
320 InputBuffer->Size = InputSize;
321
322 /* Argument 1: The ATA drive ID block */
323 Argument = InputBuffer->Argument;
324 ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, IdBlock, sizeof(*IdBlock));
325
326 /* Evaluate the _SDD method */
327 Status = AtaAcpiEvaluateObject(DeviceObject, InputBuffer, InputSize, NULL, 0);
328 if (!NT_SUCCESS(Status))
329 {
331 TRACE("Failed to set device data, status 0x%lx\n", Status);
332 else
333 WARN("Failed to set device data, status 0x%lx\n", Status);
334 }
335
337}
#define ExAllocatePoolUninitialized
#define PAGED_CODE()
#define CODE_SEG(...)
BOOLEAN AtaAcpiGetTimingMode(_In_ PDEVICE_OBJECT DeviceObject, _Out_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode)
Definition: acpi.c:98
NTSTATUS AtaAcpiSetTimingMode(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode, _In_opt_ PIDENTIFY_DEVICE_DATA IdBlock1, _In_opt_ PIDENTIFY_DEVICE_DATA IdBlock2)
Definition: acpi.c:147
VOID AtaAcpiSetDeviceData(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIDENTIFY_DEVICE_DATA IdBlock)
Definition: acpi.c:296
PVOID AtaAcpiGetTaskFile(_In_ PDEVICE_OBJECT DeviceObject)
Definition: acpi.c:212
#define ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE
Definition: acpiioct.h:15
ACPI_METHOD_ARGUMENT UNALIGNED * PACPI_METHOD_ARGUMENT
Definition: acpiioct.h:80
#define ACPI_METHOD_NEXT_ARGUMENT(Argument)
Definition: acpiioct.h:159
#define ACPI_METHOD_ARGUMENT_LENGTH(DataLength)
Definition: acpiioct.h:153
#define ACPI_EVAL_INPUT_BUFFER_SIGNATURE
Definition: acpiioct.h:12
#define ACPI_METHOD_ARGUMENT_BUFFER
Definition: acpiioct.h:32
#define IOCTL_ACPI_ASYNC_EVAL_METHOD
Definition: acpiioct.h:193
#define ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE
Definition: acpiioct.h:16
#define ACPI_METHOD_SET_ARGUMENT_BUFFER(Argument, BuffData, BuffLength)
Definition: acpiioct.h:174
ACPI_EVAL_OUTPUT_BUFFER UNALIGNED * PACPI_EVAL_OUTPUT_BUFFER
Definition: acpiioct.h:99
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
Definition: bufpool.h:45
_In_ PIRP Irp
Definition: csq.h:116
#define STATUS_NOT_SUPPORTED
Definition: d3dkmdt.h:48
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
static const WCHAR Cleanup[]
Definition: register.c:80
#define INFO
Definition: debug.h:89
#define _IRQL_requires_max_(irql)
Definition: driverspecs.h:230
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define NonPagedPool
Definition: env_spec_w32.h:307
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
Status
Definition: gdiplustypes.h:25
#define IoSetCompletionRoutine(_Irp, _CompletionRoutine, _Context, _InvokeOnSuccess, _InvokeOnError, _InvokeOnCancel)
Definition: irp.cpp:490
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
static PVOID ExAllocatePoolZero(ULONG PoolType, SIZE_T NumberOfBytes, ULONG Tag)
Definition: precomp.h:45
#define min(a, b)
Definition: monoChain.cc:55
#define KernelMode
Definition: asm.h:38
#define _In_reads_bytes_(s)
Definition: no_sal2.h:170
#define _Out_writes_bytes_opt_(s)
Definition: no_sal2.h:228
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
@ NotificationEvent
PDEVICE_OBJECT NTAPI IoGetAttachedDeviceReference(PDEVICE_OBJECT DeviceObject)
Definition: device.c:1407
PIRP NTAPI IoAllocateIrp(IN CCHAR StackSize, IN BOOLEAN ChargeQuota)
Definition: irp.c:615
#define IoCallDriver
Definition: irp.c:1225
#define STATUS_ACPI_INVALID_DATA
Definition: ntstatus.h:1662
IO_COMPLETION_ROUTINE PciIdeXPdoCompletionRoutine
Definition: pciidex.h:521
#define TAG_PCIIDEX
Definition: pciidex.h:32
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
#define IRP_MJ_DEVICE_CONTROL
Definition: rdpdr.c:52
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
static void Exit(void)
Definition: sock.c:1330
#define TRACE(s)
Definition: solgame.cpp:4
union _IO_STACK_LOCATION::@1696 Parameters
struct _IO_STACK_LOCATION::@1696::@1697 DeviceIoControl
#define STATUS_PENDING
Definition: telnetd.h:14
unsigned char UCHAR
Definition: typedefs.h:53
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2061
_In_ WDFREQUEST _In_ size_t OutputBufferLength
Definition: wdfio.h:320
_In_ WDFREQUEST _In_ size_t _In_ size_t InputBufferLength
Definition: wdfio.h:322
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR OutputBuffer
Definition: wdfiotarget.h:863
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR InputBuffer
Definition: wdfiotarget.h:953
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2695
#define IRP_INPUT_OPERATION
#define IRP_BUFFERED_IO
@ Executive
Definition: ketypes.h:467
#define ObDereferenceObject
Definition: obfuncs.h:203
#define PsGetCurrentProcess
Definition: psfuncs.h:17