Skip to content

Commit 01aeb61

Browse files
committed
[PCIIDEX] Add DMA support
CORE-17256
1 parent f7ef7ff commit 01aeb61

29 files changed

Lines changed: 13154 additions & 664 deletions

drivers/storage/ide/pciidex/CMakeLists.txt

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,36 @@
22
spec2def(pciidex.sys pciidex.spec ADD_IMPORTLIB)
33

44
list(APPEND SOURCE
5+
chipset/ahci_generic.c
6+
chipset/ahci_hw.c
7+
chipset/ahci_io.c
8+
chipset/amd.c
9+
chipset/ati.c
10+
chipset/cmd.c
11+
chipset/intel.c
12+
chipset/pata_generic.c
13+
chipset/pata_hw.c
14+
chipset/pata_io.c
15+
chipset/pctech.c
16+
chipset/serverworks.c
17+
chipset/toshiba.c
18+
chipset/via.c
19+
acpi.c
20+
ahci.h
21+
debug.h
522
fdo.c
623
miniport.c
724
pciidex.c
25+
pciidex.h
826
pdo.c
9-
power.c
10-
pciidex.h)
27+
power.c)
1128

1229
add_library(pciidex MODULE
1330
${SOURCE}
1431
pciidex.rc
1532
${CMAKE_CURRENT_BINARY_DIR}/pciidex.def)
1633

17-
add_pch(pciidex pciidex.h SOURCE)
34+
# add_pch(pciidex pciidex.h SOURCE) TODO
1835
set_module_type(pciidex kernelmodedriver)
1936
add_importlibs(pciidex ntoskrnl hal)
2037
add_cd_file(TARGET pciidex DESTINATION reactos/system32/drivers NO_CAB FOR all)

drivers/storage/ide/pciidex/acpi.c

Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
/*
2+
* PROJECT: ReactOS ATA Bus Driver
3+
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4+
* PURPOSE: ACPI interface with SATA ports, IDE controllers and drives
5+
* COPYRIGHT: Copyright 2024-2025 Dmitry Borisov <di.sean@protonmail.com>
6+
*/
7+
8+
/* INCLUDES *******************************************************************/
9+
10+
#include "pciidex.h"
11+
12+
#include <acpiioct.h>
13+
14+
/* FUNCTIONS ******************************************************************/
15+
16+
_IRQL_requires_max_(DISPATCH_LEVEL)
17+
static
18+
NTSTATUS
19+
AtaAcpiEvaluateObject(
20+
_In_ PDEVICE_OBJECT DeviceObject,
21+
_In_ PVOID InputBuffer,
22+
_In_ ULONG InputBufferLength,
23+
_Out_opt_ PACPI_EVAL_OUTPUT_BUFFER OutputBuffer,
24+
_In_ ULONG OutputBufferLength)
25+
{
26+
PIRP Irp;
27+
PIO_STACK_LOCATION IoStack;
28+
KEVENT Event;
29+
NTSTATUS Status;
30+
PDEVICE_OBJECT TopDeviceObject;
31+
32+
/* Get the ACPI bus filter device for this DO */
33+
TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
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+
{
42+
Status = STATUS_INSUFFICIENT_RESOURCES;
43+
goto Exit;
44+
}
45+
Irp->AssociatedIrp.SystemBuffer = InputBuffer;
46+
Irp->UserBuffer = OutputBuffer;
47+
Irp->Flags |= IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
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+
*/
56+
IoStack = IoGetNextIrpStackLocation(Irp);
57+
IoStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
58+
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_ACPI_ASYNC_EVAL_METHOD;
59+
IoStack->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
60+
IoStack->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
61+
62+
KeInitializeEvent(&Event, NotificationEvent, FALSE);
63+
IoSetCompletionRoutine(Irp,
64+
PciIdeXPdoCompletionRoutine,
65+
&Event,
66+
TRUE,
67+
TRUE,
68+
TRUE);
69+
70+
Status = IoCallDriver(TopDeviceObject, Irp);
71+
if (Status == STATUS_PENDING)
72+
{
73+
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
74+
Status = Irp->IoStatus.Status;
75+
}
76+
77+
RtlCopyMemory(OutputBuffer, InputBuffer, min(Irp->IoStatus.Information, OutputBufferLength));
78+
79+
if (OutputBuffer && NT_SUCCESS(Status))
80+
{
81+
ASSERT(OutputBuffer->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
82+
83+
if ((OutputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) ||
84+
(OutputBuffer->Count == 0))
85+
{
86+
ERR("Invalid ACPI output buffer\n");
87+
88+
Status = STATUS_ACPI_INVALID_DATA;
89+
}
90+
}
91+
92+
Exit:
93+
ObDereferenceObject(TopDeviceObject);
94+
return Status;
95+
}
96+
97+
BOOLEAN
98+
AtaAcpiGetTimingMode(
99+
_In_ PDEVICE_OBJECT DeviceObject,
100+
_Out_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode)
101+
{
102+
UCHAR Buffer[FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
103+
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*TimingMode))];
104+
ACPI_EVAL_INPUT_BUFFER InputBuffer;
105+
NTSTATUS Status;
106+
PACPI_EVAL_OUTPUT_BUFFER OutputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)Buffer;
107+
108+
RtlZeroMemory(Buffer, sizeof(Buffer));
109+
110+
InputBuffer.MethodNameAsUlong = 'MTG_'; // _GTM
111+
InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
112+
113+
/* Evaluate the _GTM method */
114+
Status = AtaAcpiEvaluateObject(DeviceObject,
115+
&InputBuffer,
116+
sizeof(InputBuffer),
117+
OutputBuffer,
118+
sizeof(Buffer));
119+
120+
if (!NT_SUCCESS(Status))
121+
{
122+
ASSERT(Status != STATUS_BUFFER_OVERFLOW);
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+
146+
NTSTATUS
147+
AtaAcpiSetTimingMode(
148+
_In_ PDEVICE_OBJECT DeviceObject,
149+
_In_ PIDE_ACPI_TIMING_MODE_BLOCK TimingMode,
150+
_In_opt_ PIDENTIFY_DEVICE_DATA IdBlock1,
151+
_In_opt_ PIDENTIFY_DEVICE_DATA IdBlock2)
152+
{
153+
PACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer;
154+
PACPI_METHOD_ARGUMENT Argument;
155+
NTSTATUS Status;
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+
163+
InputBuffer = ExAllocatePoolUninitialized(NonPagedPool, InputSize, TAG_PCIIDEX);
164+
if (!InputBuffer)
165+
{
166+
ERR("Failed to allocate memory\n");
167+
return STATUS_INSUFFICIENT_RESOURCES;
168+
}
169+
InputBuffer->MethodNameAsUlong = 'MTS_'; // _STM
170+
InputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
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+
{
200+
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
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+
206+
ExFreePoolWithTag(InputBuffer, TAG_PCIIDEX);
207+
return Status;
208+
}
209+
210+
CODE_SEG("PAGE")
211+
PVOID
212+
AtaAcpiGetTaskFile(
213+
_In_ PDEVICE_OBJECT DeviceObject)
214+
{
215+
ACPI_EVAL_INPUT_BUFFER InputBuffer;
216+
PACPI_EVAL_OUTPUT_BUFFER OutputBuffer;
217+
ULONG RetryCount, OutputSize;
218+
NTSTATUS Status;
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+
*/
225+
ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
226+
227+
InputBuffer.MethodNameAsUlong = 'FTG_'; // _GTF
228+
InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
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) +
235+
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ATA_ACPI_TASK_FILE) * 10);
236+
237+
for (RetryCount = 0; RetryCount < 2; ++RetryCount)
238+
{
239+
OutputBuffer = ExAllocatePoolZero(NonPagedPool, OutputSize, TAG_PCIIDEX);
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,
248+
&InputBuffer,
249+
sizeof(InputBuffer),
250+
OutputBuffer,
251+
OutputSize);
252+
253+
/* Increase the allocation size if it's too small */
254+
if (Status == STATUS_BUFFER_OVERFLOW)
255+
{
256+
OutputSize = OutputBuffer->Length;
257+
258+
ExFreePoolWithTag(OutputBuffer, TAG_PCIIDEX);
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+
288+
Cleanup:
289+
ExFreePoolWithTag(OutputBuffer, TAG_PCIIDEX);
290+
291+
return NULL;
292+
}
293+
294+
CODE_SEG("PAGE")
295+
VOID
296+
AtaAcpiSetDeviceData(
297+
_In_ PDEVICE_OBJECT DeviceObject,
298+
_In_ PIDENTIFY_DEVICE_DATA IdBlock)
299+
{
300+
PACPI_EVAL_INPUT_BUFFER_COMPLEX InputBuffer;
301+
PACPI_METHOD_ARGUMENT Argument;
302+
NTSTATUS Status;
303+
ULONG InputSize;
304+
305+
PAGED_CODE();
306+
ASSERT(PsGetCurrentProcess() == PsInitialSystemProcess);
307+
308+
InputSize = FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) +
309+
ACPI_METHOD_ARGUMENT_LENGTH(sizeof(*IdBlock));
310+
311+
InputBuffer = ExAllocatePoolUninitialized(NonPagedPool, InputSize, TAG_PCIIDEX);
312+
if (!InputBuffer)
313+
{
314+
ERR("Failed to allocate memory\n");
315+
return;
316+
}
317+
InputBuffer->MethodNameAsUlong = 'DDS_'; // _SDD
318+
InputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
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+
{
330+
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
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+
336+
ExFreePoolWithTag(InputBuffer, TAG_PCIIDEX);
337+
}

0 commit comments

Comments
 (0)