xref: /reactos/drivers/storage/ide/pciidex/fdo.c (revision 40462c92)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         PCI IDE bus driver extension
4  * FILE:            drivers/storage/pciidex/fdo.c
5  * PURPOSE:         IRP_MJ_PNP operations for FDOs
6  * PROGRAMMERS:     Herv� Poussineau (hpoussin@reactos.org)
7  */
8 
9 #include "pciidex.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 #include <initguid.h>
15 #include <wdmguid.h>
16 
17 static NTSTATUS
18 GetBusInterface(
19 	IN PFDO_DEVICE_EXTENSION DeviceExtension)
20 {
21 	PBUS_INTERFACE_STANDARD BusInterface = NULL;
22 	KEVENT Event;
23 	IO_STATUS_BLOCK IoStatus;
24 	PIRP Irp;
25 	PIO_STACK_LOCATION Stack;
26 	NTSTATUS Status = STATUS_UNSUCCESSFUL;
27 
28 	if (DeviceExtension->BusInterface)
29 	{
30 		DPRINT("We already have the bus interface\n");
31 		goto cleanup;
32 	}
33 
34 	BusInterface = ExAllocatePool(PagedPool, sizeof(BUS_INTERFACE_STANDARD));
35 	if (!BusInterface)
36 	{
37 		DPRINT("ExAllocatePool() failed\n");
38 		Status = STATUS_INSUFFICIENT_RESOURCES;
39 		goto cleanup;
40 	}
41 
42 	KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
43 	Irp = IoBuildSynchronousFsdRequest(
44 		IRP_MJ_PNP,
45 		DeviceExtension->LowerDevice,
46 		NULL,
47 		0,
48 		NULL,
49 		&Event,
50 		&IoStatus);
51 	if (!Irp)
52 	{
53 		DPRINT("IoBuildSynchronousFsdRequest() failed\n");
54 		Status = STATUS_INSUFFICIENT_RESOURCES;
55 		goto cleanup;
56 	}
57 
58 	Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
59 	Irp->IoStatus.Information = 0;
60 
61 	Stack = IoGetNextIrpStackLocation(Irp);
62 	Stack->MajorFunction = IRP_MJ_PNP;
63 	Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
64 	Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
65 	Stack->Parameters.QueryInterface.Version = 1;
66 	Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
67 	Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
68 	Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
69 
70 	Status = IoCallDriver(DeviceExtension->LowerDevice, Irp);
71 	if (Status == STATUS_PENDING)
72 	{
73 		KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
74 		Status = IoStatus.Status;
75 	}
76 	if (!NT_SUCCESS(Status))
77 		goto cleanup;
78 
79 	DeviceExtension->BusInterface = BusInterface;
80 	BusInterface = NULL;
81 	Status = STATUS_SUCCESS;
82 
83 cleanup:
84 	if (BusInterface) ExFreePool(BusInterface);
85 	return Status;
86 }
87 
88 static NTSTATUS
89 ReleaseBusInterface(
90 	IN PFDO_DEVICE_EXTENSION DeviceExtension)
91 {
92 	NTSTATUS Status = STATUS_UNSUCCESSFUL;
93 
94 	if (DeviceExtension->BusInterface)
95 	{
96 		(*DeviceExtension->BusInterface->InterfaceDereference)(
97 			DeviceExtension->BusInterface->Context);
98 		DeviceExtension->BusInterface = NULL;
99 		Status = STATUS_SUCCESS;
100 	}
101 
102 	return Status;
103 }
104 
105 NTSTATUS NTAPI
106 PciIdeXAddDevice(
107 	IN PDRIVER_OBJECT DriverObject,
108 	IN PDEVICE_OBJECT Pdo)
109 {
110 	PPCIIDEX_DRIVER_EXTENSION DriverExtension;
111 	PFDO_DEVICE_EXTENSION DeviceExtension;
112 	PDEVICE_OBJECT Fdo;
113 	ULONG BytesRead;
114 	PCI_COMMON_CONFIG PciConfig;
115 	NTSTATUS Status;
116 
117 	DPRINT("PciIdeXAddDevice(%p %p)\n", DriverObject, Pdo);
118 
119 	DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
120 	ASSERT(DriverExtension);
121 
122 	Status = IoCreateDevice(
123 		DriverObject,
124 		sizeof(FDO_DEVICE_EXTENSION) + DriverExtension->MiniControllerExtensionSize,
125 		NULL,
126 		FILE_DEVICE_BUS_EXTENDER,
127 		FILE_DEVICE_SECURE_OPEN,
128 		TRUE,
129 		&Fdo);
130 	if (!NT_SUCCESS(Status))
131 	{
132 		DPRINT("IoCreateDevice() failed with status 0x%08lx\n", Status);
133 		return Status;
134 	}
135 
136 	DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
137 	RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
138 
139 	DeviceExtension->Common.IsFDO = TRUE;
140 
141 	Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
142 	if (!NT_SUCCESS(Status))
143 	{
144 		DPRINT("IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
145 		return Status;
146 	}
147 
148 	Status = GetBusInterface(DeviceExtension);
149 	if (!NT_SUCCESS(Status))
150 	{
151 		DPRINT("GetBusInterface() failed with status 0x%08lx\n", Status);
152 		IoDetachDevice(DeviceExtension->LowerDevice);
153 		return Status;
154 	}
155 
156 	BytesRead = (*DeviceExtension->BusInterface->GetBusData)(
157 		DeviceExtension->BusInterface->Context,
158 		PCI_WHICHSPACE_CONFIG,
159 		&PciConfig,
160 		0,
161 		PCI_COMMON_HDR_LENGTH);
162 	if (BytesRead != PCI_COMMON_HDR_LENGTH)
163 	{
164 		DPRINT("BusInterface->GetBusData() failed()\n");
165 		ReleaseBusInterface(DeviceExtension);
166 		IoDetachDevice(DeviceExtension->LowerDevice);
167 		return STATUS_IO_DEVICE_ERROR;
168 	}
169 
170 	DeviceExtension->VendorId = PciConfig.VendorID;
171 	DeviceExtension->DeviceId = PciConfig.DeviceID;
172 
173 	Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
174 
175 	return STATUS_SUCCESS;
176 }
177 
178 static NTSTATUS NTAPI
179 PciIdeXUdmaModesSupported(
180 	IN IDENTIFY_DATA IdentifyData,
181 	OUT PULONG BestXferMode,
182 	OUT PULONG CurrentXferMode)
183 {
184 	ULONG Best = PIO_MODE0;
185 	ULONG Current = PIO_MODE0;
186 
187 	DPRINT("PciIdeXUdmaModesSupported(%lu, %p %p)\n",
188 		IdentifyData, BestXferMode, CurrentXferMode);
189 
190 	/* FIXME: if current mode is a PIO mode, how to get it?
191 	 * At the moment, PIO_MODE0 is always returned...
192 	 */
193 
194 	if (IdentifyData.TranslationFieldsValid & 0x2)
195 	{
196 		/* PIO modes and some DMA modes are supported */
197 		if (IdentifyData.AdvancedPIOModes & 0x10)
198 			Best = PIO_MODE4;
199 		else if (IdentifyData.AdvancedPIOModes & 0x8)
200 			Best = PIO_MODE3;
201 		else if (IdentifyData.AdvancedPIOModes & 0x4)
202 			Best = PIO_MODE2;
203 		else if (IdentifyData.AdvancedPIOModes & 0x2)
204 			Best = PIO_MODE1;
205 		else if (IdentifyData.AdvancedPIOModes & 0x1)
206 			Best = PIO_MODE0;
207 
208 		if (IdentifyData.SingleWordDMASupport & 0x4)
209 			Best = SWDMA_MODE2;
210 		else if (IdentifyData.SingleWordDMASupport & 0x2)
211 			Best = SWDMA_MODE1;
212 		else if (IdentifyData.SingleWordDMASupport & 0x1)
213 			Best = SWDMA_MODE0;
214 
215 		if (IdentifyData.SingleWordDMAActive & 0x4)
216 			Current = SWDMA_MODE2;
217 		else if (IdentifyData.SingleWordDMAActive & 0x2)
218 			Current = SWDMA_MODE1;
219 		else if (IdentifyData.SingleWordDMAActive & 0x1)
220 			Current = SWDMA_MODE0;
221 
222 		if (IdentifyData.MultiWordDMASupport & 0x4)
223 			Best = MWDMA_MODE2;
224 		else if (IdentifyData.MultiWordDMASupport & 0x2)
225 			Best = MWDMA_MODE1;
226 		else if (IdentifyData.MultiWordDMASupport & 0x1)
227 			Best = MWDMA_MODE0;
228 
229 		if (IdentifyData.MultiWordDMAActive & 0x4)
230 			Current = MWDMA_MODE2;
231 		else if (IdentifyData.MultiWordDMAActive & 0x2)
232 			Current = MWDMA_MODE1;
233 		else if (IdentifyData.MultiWordDMAActive & 0x1)
234 			Current = MWDMA_MODE0;
235 	}
236 
237 	if (IdentifyData.TranslationFieldsValid & 0x4)
238 	{
239 		/* UDMA modes are supported */
240 		if (IdentifyData.UltraDMAActive & 0x10)
241 			Current = UDMA_MODE4;
242 		else if (IdentifyData.UltraDMAActive & 0x8)
243 			Current = UDMA_MODE3;
244 		else if (IdentifyData.UltraDMAActive & 0x4)
245 			Current = UDMA_MODE2;
246 		else if (IdentifyData.UltraDMAActive & 0x2)
247 			Current = UDMA_MODE1;
248 		else if (IdentifyData.UltraDMAActive & 0x1)
249 			Current = UDMA_MODE0;
250 
251 		if (IdentifyData.UltraDMASupport & 0x10)
252 			Best = UDMA_MODE4;
253 		else if (IdentifyData.UltraDMASupport & 0x8)
254 			Best = UDMA_MODE3;
255 		else if (IdentifyData.UltraDMASupport & 0x4)
256 			Best = UDMA_MODE2;
257 		else if (IdentifyData.UltraDMASupport & 0x2)
258 			Best = UDMA_MODE1;
259 		else if (IdentifyData.UltraDMASupport & 0x1)
260 			Best = UDMA_MODE0;
261 	}
262 
263 	*BestXferMode = Best;
264 	*CurrentXferMode = Current;
265 	return TRUE;
266 }
267 
268 static NTSTATUS
269 PciIdeXFdoStartDevice(
270 	IN PDEVICE_OBJECT DeviceObject,
271 	IN PIRP Irp)
272 {
273 	PPCIIDEX_DRIVER_EXTENSION DriverExtension;
274 	PFDO_DEVICE_EXTENSION DeviceExtension;
275 	PCM_RESOURCE_LIST ResourceList;
276 	NTSTATUS Status;
277 
278 	DPRINT("PciIdeXStartDevice(%p %p)\n", DeviceObject, Irp);
279 
280 	DriverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, DeviceObject->DriverObject);
281 	ASSERT(DriverExtension);
282 	DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
283 	ASSERT(DeviceExtension);
284 	ASSERT(DeviceExtension->Common.IsFDO);
285 
286 	DeviceExtension->Properties.Size = sizeof(IDE_CONTROLLER_PROPERTIES);
287 	DeviceExtension->Properties.ExtensionSize = DriverExtension->MiniControllerExtensionSize;
288 	Status = DriverExtension->HwGetControllerProperties(
289 		DeviceExtension->MiniControllerExtension,
290 		&DeviceExtension->Properties);
291 	if (!NT_SUCCESS(Status))
292 		return Status;
293 
294 	DriverExtension->HwUdmaModesSupported = DeviceExtension->Properties.PciIdeUdmaModesSupported;
295 	if (!DriverExtension->HwUdmaModesSupported)
296 		/* This method is optional, so provide our own one */
297 		DriverExtension->HwUdmaModesSupported = PciIdeXUdmaModesSupported;
298 
299 	/* Get bus master port base, if any */
300 	ResourceList = IoGetCurrentIrpStackLocation(Irp)->Parameters.StartDevice.AllocatedResources;
301 	if (ResourceList
302 		&& ResourceList->Count == 1
303 		&& ResourceList->List[0].PartialResourceList.Count == 1
304 		&& ResourceList->List[0].PartialResourceList.Version == 1
305 		&& ResourceList->List[0].PartialResourceList.Revision == 1
306 		&& ResourceList->List[0].PartialResourceList.PartialDescriptors[0].Type == CmResourceTypePort
307 		&& ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length == 16)
308 	{
309 		DeviceExtension->BusMasterPortBase = ResourceList->List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start;
310 	}
311 	return STATUS_SUCCESS;
312 }
313 
314 static NTSTATUS
315 PciIdeXFdoQueryBusRelations(
316 	IN PDEVICE_OBJECT DeviceObject,
317 	OUT PDEVICE_RELATIONS* pDeviceRelations)
318 {
319 	PFDO_DEVICE_EXTENSION DeviceExtension;
320 	PDEVICE_RELATIONS DeviceRelations = NULL;
321 	PDEVICE_OBJECT Pdo;
322 	PPDO_DEVICE_EXTENSION PdoDeviceExtension;
323 	ULONG i, j;
324 	ULONG PDOs = 0;
325 	IDE_CHANNEL_STATE ChannelState;
326 	NTSTATUS Status;
327 
328 	DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
329 	ASSERT(DeviceExtension);
330 	ASSERT(DeviceExtension->Common.IsFDO);
331 
332 	for (i = 0; i < MAX_IDE_CHANNEL; i++)
333 	{
334 		if (DeviceExtension->Pdo[i])
335 		{
336 			PDOs++;
337 			continue;
338 		}
339 		ChannelState = DeviceExtension->Properties.PciIdeChannelEnabled(
340 			DeviceExtension->MiniControllerExtension, i);
341 		if (ChannelState == ChannelDisabled)
342 		{
343 			DPRINT("Channel %lu is disabled\n", i);
344 			continue;
345 		}
346 
347 		/* Need to create a PDO */
348 		Status = IoCreateDevice(
349 			DeviceObject->DriverObject,
350 			sizeof(PDO_DEVICE_EXTENSION),
351 			NULL,
352 			FILE_DEVICE_CONTROLLER,
353 			FILE_AUTOGENERATED_DEVICE_NAME,
354 			FALSE,
355 			&Pdo);
356 		if (!NT_SUCCESS(Status))
357 			/* FIXME: handle error */
358 			continue;
359 
360 		PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)Pdo->DeviceExtension;
361 		RtlZeroMemory(PdoDeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
362 		PdoDeviceExtension->Common.IsFDO = FALSE;
363 		PdoDeviceExtension->Channel = i;
364 		PdoDeviceExtension->ControllerFdo = DeviceObject;
365 		Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
366 		Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
367 
368 		DeviceExtension->Pdo[i] = Pdo;
369 		PDOs++;
370 	}
371 
372 	if (PDOs == 0)
373 	{
374 		DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
375 			PagedPool,
376 			sizeof(DEVICE_RELATIONS));
377 	}
378 	else
379 	{
380 		DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
381 			PagedPool,
382 			sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * (PDOs - 1));
383 	}
384 	if (!DeviceRelations)
385 		return STATUS_INSUFFICIENT_RESOURCES;
386 
387 	DeviceRelations->Count = PDOs;
388 	for (i = 0, j = 0; i < MAX_IDE_CHANNEL; i++)
389 	{
390 		if (DeviceExtension->Pdo[i])
391 		{
392 			ObReferenceObject(DeviceExtension->Pdo[i]);
393 			DeviceRelations->Objects[j++] = DeviceExtension->Pdo[i];
394 		}
395 	}
396 
397 	*pDeviceRelations = DeviceRelations;
398 	return STATUS_SUCCESS;
399 }
400 
401 NTSTATUS NTAPI
402 PciIdeXFdoPnpDispatch(
403 	IN PDEVICE_OBJECT DeviceObject,
404 	IN PIRP Irp)
405 {
406 	ULONG MinorFunction;
407 	PIO_STACK_LOCATION Stack;
408 	ULONG_PTR Information = Irp->IoStatus.Information;
409 	NTSTATUS Status;
410 
411 	Stack = IoGetCurrentIrpStackLocation(Irp);
412 	MinorFunction = Stack->MinorFunction;
413 
414 	switch (MinorFunction)
415 	{
416 		case IRP_MN_START_DEVICE: /* 0x00 */
417 		{
418 			DPRINT("IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
419 			/* Call lower driver */
420 			Status = ForwardIrpAndWait(DeviceObject, Irp);
421 			if (NT_SUCCESS(Status))
422 				Status = PciIdeXFdoStartDevice(DeviceObject, Irp);
423 			break;
424 		}
425                 case IRP_MN_QUERY_REMOVE_DEVICE: /* 0x01 */
426                 {
427                         DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_REMOVE_DEVICE\n");
428                         Status = STATUS_UNSUCCESSFUL;
429                         break;
430                 }
431 		case IRP_MN_QUERY_DEVICE_RELATIONS: /* 0x07 */
432 		{
433 			switch (Stack->Parameters.QueryDeviceRelations.Type)
434 			{
435 				case BusRelations:
436 				{
437 					PDEVICE_RELATIONS DeviceRelations = NULL;
438 					DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
439 					Status = PciIdeXFdoQueryBusRelations(DeviceObject, &DeviceRelations);
440 					Information = (ULONG_PTR)DeviceRelations;
441 					break;
442 				}
443 				default:
444 				{
445 					DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
446 						Stack->Parameters.QueryDeviceRelations.Type);
447 					Status = STATUS_NOT_IMPLEMENTED;
448 					break;
449 				}
450 			}
451 			break;
452 		}
453                 case IRP_MN_QUERY_PNP_DEVICE_STATE: /* 0x14 */
454                 {
455                         DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_PNP_DEVICE_STATE\n");
456                         Information |= PNP_DEVICE_NOT_DISABLEABLE;
457                         Status = STATUS_SUCCESS;
458                         break;
459                 }
460 		case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: /* 0x0d */
461 		{
462 			DPRINT("IRP_MJ_PNP / IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
463 			return ForwardIrpAndForget(DeviceObject, Irp);
464 		}
465 		case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
466 		{
467 			DPRINT("IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
468 			return ForwardIrpAndForget(DeviceObject, Irp);
469 		}
470 		default:
471 		{
472 			DPRINT1("IRP_MJ_PNP / Unknown minor function 0x%lx\n", MinorFunction);
473 			return ForwardIrpAndForget(DeviceObject, Irp);
474 		}
475 	}
476 
477 	Irp->IoStatus.Information = Information;
478 	Irp->IoStatus.Status = Status;
479 	IoCompleteRequest(Irp, IO_NO_INCREMENT);
480 	return Status;
481 }
482