1 /*
2 * PROJECT: PCI IDE bus driver extension
3 * LICENSE: See COPYING in the top level directory
4 * PURPOSE: Main file
5 * COPYRIGHT: Copyright 2005 Hervé Poussineau <hpoussin@reactos.org>
6 */
7
8 #include "pciidex.h"
9
10 #define NDEBUG
11 #include <debug.h>
12
13 ULONG PciIdeControllerNumber = 0;
14
15 CODE_SEG("PAGE")
16 NTSTATUS
17 NTAPI
PciIdeXDispatchWmi(_In_ PDEVICE_OBJECT DeviceObject,_Inout_ PIRP Irp)18 PciIdeXDispatchWmi(
19 _In_ PDEVICE_OBJECT DeviceObject,
20 _Inout_ PIRP Irp)
21 {
22 NTSTATUS Status;
23
24 PAGED_CODE();
25
26 if (IS_FDO(DeviceObject->DeviceExtension))
27 {
28 PFDO_DEVICE_EXTENSION FdoExtension = DeviceObject->DeviceExtension;
29
30 IoSkipCurrentIrpStackLocation(Irp);
31 Status = IoCallDriver(FdoExtension->Ldo, Irp);
32 }
33 else
34 {
35 Status = Irp->IoStatus.Status;
36 IoCompleteRequest(Irp, IO_NO_INCREMENT);
37 }
38
39 return Status;
40 }
41
42 CODE_SEG("PAGE")
43 VOID
44 NTAPI
PciIdeXUnload(_In_ PDRIVER_OBJECT DriverObject)45 PciIdeXUnload(
46 _In_ PDRIVER_OBJECT DriverObject)
47 {
48 UNREFERENCED_PARAMETER(DriverObject);
49
50 PAGED_CODE();
51
52 NOTHING;
53 }
54
55 static
56 CODE_SEG("PAGE")
57 NTSTATUS
PciIdeXQueryInterface(_In_ PFDO_DEVICE_EXTENSION FdoExtension,_In_ const GUID * Guid,_Out_ PVOID Interface,_In_ ULONG Size)58 PciIdeXQueryInterface(
59 _In_ PFDO_DEVICE_EXTENSION FdoExtension,
60 _In_ const GUID* Guid,
61 _Out_ PVOID Interface,
62 _In_ ULONG Size)
63 {
64 KEVENT Event;
65 IO_STATUS_BLOCK IoStatus;
66 PIRP Irp;
67 PIO_STACK_LOCATION Stack;
68 NTSTATUS Status;
69
70 PAGED_CODE();
71
72 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
73
74 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
75 FdoExtension->Ldo,
76 NULL,
77 0,
78 NULL,
79 &Event,
80 &IoStatus);
81 if (!Irp)
82 return STATUS_INSUFFICIENT_RESOURCES;
83
84 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
85 Irp->IoStatus.Information = 0;
86
87 Stack = IoGetNextIrpStackLocation(Irp);
88 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
89 Stack->Parameters.QueryInterface.InterfaceType = Guid;
90 Stack->Parameters.QueryInterface.Version = 1;
91 Stack->Parameters.QueryInterface.Size = Size;
92 Stack->Parameters.QueryInterface.Interface = Interface;
93 Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
94
95 Status = IoCallDriver(FdoExtension->Ldo, Irp);
96 if (Status == STATUS_PENDING)
97 {
98 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
99 Status = IoStatus.Status;
100 }
101
102 return Status;
103 }
104
105 static
106 CODE_SEG("PAGE")
107 NTSTATUS
PciIdeXGetConfigurationInfo(_In_ PFDO_DEVICE_EXTENSION FdoExtension)108 PciIdeXGetConfigurationInfo(
109 _In_ PFDO_DEVICE_EXTENSION FdoExtension)
110 {
111 UCHAR Buffer[RTL_SIZEOF_THROUGH_FIELD(PCI_COMMON_HEADER, BaseClass)];
112 PPCI_COMMON_HEADER PciConfig = (PPCI_COMMON_HEADER)Buffer;
113 ULONG BytesRead;
114
115 PAGED_CODE();
116
117 BytesRead = (*FdoExtension->BusInterface.GetBusData)(FdoExtension->BusInterface.Context,
118 PCI_WHICHSPACE_CONFIG,
119 Buffer,
120 0,
121 sizeof(Buffer));
122 if (BytesRead != sizeof(Buffer))
123 return STATUS_IO_DEVICE_ERROR;
124
125 FdoExtension->VendorId = PciConfig->VendorID;
126 FdoExtension->DeviceId = PciConfig->DeviceID;
127
128 if (PciConfig->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR)
129 {
130 if (PciConfig->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR)
131 {
132 /* Both IDE channels in native mode */
133 FdoExtension->InNativeMode =
134 (PciConfig->ProgIf & PCIIDE_PROGIF_PRIMARY_CHANNEL_NATIVE_MODE) &&
135 (PciConfig->ProgIf & PCIIDE_PROGIF_SECONDARY_CHANNEL_NATIVE_MODE);
136 }
137 else if (PciConfig->SubClass == PCI_SUBCLASS_MSC_RAID_CTLR)
138 {
139 FdoExtension->InNativeMode = TRUE;
140 }
141 }
142
143 DPRINT("Controller %04x:%04x, Interface byte 0x%02x, Native mode %d\n",
144 FdoExtension->VendorId,
145 FdoExtension->DeviceId,
146 PciConfig->ProgIf,
147 FdoExtension->InNativeMode);
148
149 return STATUS_SUCCESS;
150 }
151
152 CODE_SEG("PAGE")
153 NTSTATUS
154 NTAPI
PciIdeXAddDevice(_In_ PDRIVER_OBJECT DriverObject,_In_ PDEVICE_OBJECT PhysicalDeviceObject)155 PciIdeXAddDevice(
156 _In_ PDRIVER_OBJECT DriverObject,
157 _In_ PDEVICE_OBJECT PhysicalDeviceObject)
158 {
159 PPCIIDEX_DRIVER_EXTENSION DriverExtension;
160 PFDO_DEVICE_EXTENSION FdoExtension;
161 ULONG DeviceExtensionSize;
162 PDEVICE_OBJECT Fdo;
163 UNICODE_STRING DeviceName;
164 WCHAR DeviceNameBuffer[sizeof("\\Device\\Ide\\PciIde999")];
165 NTSTATUS Status;
166
167 PAGED_CODE();
168
169 Status = RtlStringCbPrintfW(DeviceNameBuffer,
170 sizeof(DeviceNameBuffer),
171 L"\\Device\\Ide\\PciIde%u",
172 PciIdeControllerNumber);
173 ASSERT(NT_SUCCESS(Status));
174 RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
175
176 DPRINT("%s(%p, %p) '%wZ'\n", __FUNCTION__, DriverObject, PhysicalDeviceObject, &DeviceName);
177
178 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
179 ASSERT(DriverExtension);
180
181 Status = RtlULongAdd(DriverExtension->MiniControllerExtensionSize,
182 sizeof(FDO_DEVICE_EXTENSION),
183 &DeviceExtensionSize);
184 if (!NT_SUCCESS(Status))
185 {
186 DPRINT1("Invalid miniport extension size %lx\n",
187 DriverExtension->MiniControllerExtensionSize);
188 return Status;
189 }
190
191 Status = IoCreateDevice(DriverObject,
192 DeviceExtensionSize,
193 &DeviceName,
194 FILE_DEVICE_BUS_EXTENDER,
195 FILE_DEVICE_SECURE_OPEN,
196 FALSE,
197 &Fdo);
198 if (!NT_SUCCESS(Status))
199 {
200 DPRINT1("Failed to create FDO 0x%lx\n", Status);
201 return Status;
202 }
203
204 FdoExtension = Fdo->DeviceExtension;
205
206 RtlZeroMemory(FdoExtension, sizeof(FDO_DEVICE_EXTENSION));
207 FdoExtension->Common.IsFDO = TRUE;
208 FdoExtension->Common.Self = Fdo;
209 FdoExtension->DriverObject = DriverObject;
210 FdoExtension->ControllerNumber = PciIdeControllerNumber++;
211
212 KeInitializeSpinLock(&FdoExtension->BusDataLock);
213 ExInitializeFastMutex(&FdoExtension->DeviceSyncMutex);
214
215 Status = IoAttachDeviceToDeviceStackSafe(Fdo, PhysicalDeviceObject, &FdoExtension->Ldo);
216 if (!NT_SUCCESS(Status))
217 {
218 DPRINT("Failed to attach FDO 0x%lx\n", Status);
219 goto Failure;
220 }
221
222 /* DMA buffers alignment */
223 Fdo->AlignmentRequirement = max(FdoExtension->Ldo->AlignmentRequirement, FILE_WORD_ALIGNMENT);
224
225 Status = PciIdeXQueryInterface(FdoExtension,
226 &GUID_BUS_INTERFACE_STANDARD,
227 &FdoExtension->BusInterface,
228 sizeof(BUS_INTERFACE_STANDARD));
229 if (!NT_SUCCESS(Status))
230 {
231 DPRINT1("No bus interface 0x%lx\n", Status);
232 goto Failure;
233 }
234
235 Status = PciIdeXGetConfigurationInfo(FdoExtension);
236 if (!NT_SUCCESS(Status))
237 {
238 DPRINT1("Unable to retrieve the configuration info %lx\n", Status);
239 goto Failure;
240 }
241
242 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
243
244 return STATUS_SUCCESS;
245
246 Failure:
247 if (FdoExtension->Ldo)
248 IoDetachDevice(FdoExtension->Ldo);
249
250 IoDeleteDevice(Fdo);
251
252 return Status;
253 }
254
255 static
256 CODE_SEG("PAGE")
257 VOID
PciIdeXCreateIdeDirectory(VOID)258 PciIdeXCreateIdeDirectory(VOID)
259 {
260 HANDLE Handle;
261 NTSTATUS Status;
262 OBJECT_ATTRIBUTES ObjectAttributes;
263 UNICODE_STRING DirectoryName = RTL_CONSTANT_STRING(L"\\Device\\Ide");
264
265 PAGED_CODE();
266
267 InitializeObjectAttributes(&ObjectAttributes,
268 &DirectoryName,
269 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_KERNEL_HANDLE,
270 NULL,
271 NULL);
272
273 Status = ZwCreateDirectoryObject(&Handle, DIRECTORY_ALL_ACCESS, &ObjectAttributes);
274 if (NT_SUCCESS(Status))
275 {
276 /* We don't need a handle for a permanent object */
277 ZwClose(Handle);
278 }
279 /*
280 * Ignore directory creation failures (don't report them as a driver initialization error)
281 * as the directory may have already been created by another driver.
282 * We will handle fatal errors later via IoCreateDevice() call.
283 */
284 }
285
286 CODE_SEG("PAGE")
287 NTSTATUS
288 NTAPI
PciIdeXInitialize(_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath,_In_ PCONTROLLER_PROPERTIES HwGetControllerProperties,_In_ ULONG ExtensionSize)289 PciIdeXInitialize(
290 _In_ PDRIVER_OBJECT DriverObject,
291 _In_ PUNICODE_STRING RegistryPath,
292 _In_ PCONTROLLER_PROPERTIES HwGetControllerProperties,
293 _In_ ULONG ExtensionSize)
294 {
295 PPCIIDEX_DRIVER_EXTENSION DriverExtension;
296 NTSTATUS Status;
297
298 PAGED_CODE();
299
300 DPRINT("PciIdeXInitialize(%p '%wZ' %p 0x%lx)\n",
301 DriverObject, RegistryPath, HwGetControllerProperties, ExtensionSize);
302
303 Status = IoAllocateDriverObjectExtension(DriverObject,
304 DriverObject,
305 sizeof(PCIIDEX_DRIVER_EXTENSION),
306 (PVOID*)&DriverExtension);
307 if (!NT_SUCCESS(Status))
308 return Status;
309
310 RtlZeroMemory(DriverExtension, sizeof(PCIIDEX_DRIVER_EXTENSION));
311 DriverExtension->MiniControllerExtensionSize = ExtensionSize;
312 DriverExtension->HwGetControllerProperties = HwGetControllerProperties;
313
314 DriverObject->MajorFunction[IRP_MJ_PNP] = PciIdeXDispatchPnp;
315 DriverObject->MajorFunction[IRP_MJ_POWER] = PciIdeXDispatchPower;
316 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciIdeXDispatchWmi;
317 DriverObject->DriverExtension->AddDevice = PciIdeXAddDevice;
318 DriverObject->DriverUnload = PciIdeXUnload;
319
320 /* Create a directory to hold the driver's device objects */
321 PciIdeXCreateIdeDirectory();
322
323 return STATUS_SUCCESS;
324 }
325
326 CODE_SEG("PAGE") /* This function is too small to be placed into INIT section */
327 NTSTATUS
328 NTAPI
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath)329 DriverEntry(
330 _In_ PDRIVER_OBJECT DriverObject,
331 _In_ PUNICODE_STRING RegistryPath)
332 {
333 UNREFERENCED_PARAMETER(DriverObject);
334 UNREFERENCED_PARAMETER(RegistryPath);
335
336 PAGED_CODE();
337
338 return STATUS_SUCCESS;
339 }
340