[WIN32SS]
[reactos.git] / reactos / win32ss / drivers / videoprt / resource.c
1 /*
2 * VideoPort driver
3 *
4 * Copyright (C) 2002 - 2005 ReactOS Team
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include "videoprt.h"
23
24 /* PRIVATE FUNCTIONS **********************************************************/
25
26 NTSTATUS NTAPI
27 IntVideoPortGetLegacyResources(
28 IN PVIDEO_PORT_DRIVER_EXTENSION DriverExtension,
29 IN PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension,
30 OUT PVIDEO_ACCESS_RANGE *AccessRanges,
31 OUT PULONG AccessRangeCount)
32 {
33 PCI_COMMON_CONFIG PciConfig;
34 ULONG ReadLength;
35
36 if (!DriverExtension->InitializationData.HwGetLegacyResources &&
37 !DriverExtension->InitializationData.HwLegacyResourceCount)
38 {
39 /* No legacy resources to report */
40 *AccessRangeCount = 0;
41 return STATUS_SUCCESS;
42 }
43
44 if (DriverExtension->InitializationData.HwGetLegacyResources)
45 {
46 ReadLength = HalGetBusData(PCIConfiguration,
47 DeviceExtension->SystemIoBusNumber,
48 DeviceExtension->SystemIoSlotNumber,
49 &PciConfig,
50 sizeof(PciConfig));
51 if (ReadLength != sizeof(PciConfig))
52 {
53 /* This device doesn't exist */
54 return STATUS_NO_SUCH_DEVICE;
55 }
56
57 DriverExtension->InitializationData.HwGetLegacyResources(PciConfig.VendorID,
58 PciConfig.DeviceID,
59 AccessRanges,
60 AccessRangeCount);
61 }
62 else
63 {
64 *AccessRanges = DriverExtension->InitializationData.HwLegacyResourceList;
65 *AccessRangeCount = DriverExtension->InitializationData.HwLegacyResourceCount;
66 }
67
68 INFO_(VIDEOPRT, "Got %d legacy access ranges\n", *AccessRangeCount);
69
70 return STATUS_SUCCESS;
71 }
72
73 NTSTATUS NTAPI
74 IntVideoPortFilterResourceRequirements(
75 IN PDEVICE_OBJECT DeviceObject,
76 IN PIRP Irp)
77 {
78 PDRIVER_OBJECT DriverObject;
79 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
80 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
81 PVIDEO_ACCESS_RANGE AccessRanges;
82 ULONG AccessRangeCount, ListSize, i;
83 PIO_RESOURCE_REQUIREMENTS_LIST ResList, OldResList = (PVOID)Irp->IoStatus.Information;
84 PIO_RESOURCE_DESCRIPTOR CurrentDescriptor;
85 NTSTATUS Status;
86
87 DriverObject = DeviceObject->DriverObject;
88 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
89 DeviceExtension = (PVIDEO_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
90
91 Status = IntVideoPortGetLegacyResources(DriverExtension, DeviceExtension, &AccessRanges, &AccessRangeCount);
92 if (!NT_SUCCESS(Status))
93 return Status;
94 if (!AccessRangeCount)
95 {
96 /* No legacy resources to report */
97 return Irp->IoStatus.Information;
98 }
99
100 /* OK, we've got the access ranges now. Let's set up the resource requirements list */
101
102 if (OldResList)
103 {
104 /* Already one there so let's add to it */
105 ListSize = OldResList->ListSize + sizeof(IO_RESOURCE_DESCRIPTOR) * AccessRangeCount;
106 ResList = ExAllocatePool(NonPagedPool,
107 ListSize);
108 if (!ResList) return STATUS_NO_MEMORY;
109
110 RtlCopyMemory(ResList, OldResList, OldResList->ListSize);
111
112 ASSERT(ResList->AlternativeLists == 1);
113
114 ResList->ListSize = ListSize;
115 ResList->List[0].Count += AccessRangeCount;
116
117 CurrentDescriptor = (PIO_RESOURCE_DESCRIPTOR)((PUCHAR)ResList + OldResList->ListSize);
118
119 ExFreePool(OldResList);
120 Irp->IoStatus.Information = 0;
121 }
122 else
123 {
124 /* We need to make a new one */
125 ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + sizeof(IO_RESOURCE_DESCRIPTOR) * (AccessRangeCount - 1);
126 ResList = ExAllocatePool(NonPagedPool,
127 ListSize);
128 if (!ResList) return STATUS_NO_MEMORY;
129
130 RtlZeroMemory(ResList, ListSize);
131
132 /* We need to initialize some fields */
133 ResList->ListSize = ListSize;
134 ResList->InterfaceType = DeviceExtension->AdapterInterfaceType;
135 ResList->BusNumber = DeviceExtension->SystemIoBusNumber;
136 ResList->SlotNumber = DeviceExtension->SystemIoSlotNumber;
137 ResList->AlternativeLists = 1;
138 ResList->List[0].Version = 1;
139 ResList->List[0].Revision = 1;
140 ResList->List[0].Count = AccessRangeCount;
141
142 CurrentDescriptor = ResList->List[0].Descriptors;
143 }
144
145 for (i = 0; i < AccessRangeCount; i++)
146 {
147 /* This is a required resource */
148 CurrentDescriptor->Option = 0;
149
150 if (AccessRanges[i].RangeInIoSpace)
151 CurrentDescriptor->Type = CmResourceTypePort;
152 else
153 CurrentDescriptor->Type = CmResourceTypeMemory;
154
155 CurrentDescriptor->ShareDisposition =
156 (AccessRanges[i].RangeShareable ? CmResourceShareShared : CmResourceShareDeviceExclusive);
157
158 CurrentDescriptor->Flags = 0;
159
160 if (CurrentDescriptor->Type == CmResourceTypePort)
161 {
162 CurrentDescriptor->u.Port.Length = AccessRanges[i].RangeLength;
163 CurrentDescriptor->u.Port.MinimumAddress =
164 CurrentDescriptor->u.Port.MaximumAddress = AccessRanges[i].RangeStart;
165 CurrentDescriptor->u.Port.Alignment = 1;
166 if (AccessRanges[i].RangePassive & VIDEO_RANGE_PASSIVE_DECODE)
167 CurrentDescriptor->Flags |= CM_RESOURCE_PORT_PASSIVE_DECODE;
168 if (AccessRanges[i].RangePassive & VIDEO_RANGE_10_BIT_DECODE)
169 CurrentDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
170 }
171 else
172 {
173 CurrentDescriptor->u.Memory.Length = AccessRanges[i].RangeLength;
174 CurrentDescriptor->u.Memory.MinimumAddress =
175 CurrentDescriptor->u.Memory.MaximumAddress = AccessRanges[i].RangeStart;
176 CurrentDescriptor->u.Memory.Alignment = 1;
177 CurrentDescriptor->Flags |= CM_RESOURCE_MEMORY_READ_WRITE;
178 }
179
180 CurrentDescriptor++;
181 }
182
183 Irp->IoStatus.Information = (ULONG_PTR)ResList;
184
185 return STATUS_SUCCESS;
186 }
187
188 NTSTATUS NTAPI
189 IntVideoPortMapPhysicalMemory(
190 IN HANDLE Process,
191 IN PHYSICAL_ADDRESS PhysicalAddress,
192 IN ULONG SizeInBytes,
193 IN ULONG Protect,
194 IN OUT PVOID *VirtualAddress OPTIONAL)
195 {
196 OBJECT_ATTRIBUTES ObjAttribs;
197 UNICODE_STRING UnicodeString;
198 HANDLE hMemObj;
199 NTSTATUS Status;
200 SIZE_T Size;
201
202 /* Initialize object attribs */
203 RtlInitUnicodeString(&UnicodeString, L"\\Device\\PhysicalMemory");
204 InitializeObjectAttributes(&ObjAttribs,
205 &UnicodeString,
206 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
207 NULL, NULL);
208
209 /* Open physical memory section */
210 Status = ZwOpenSection(&hMemObj, SECTION_ALL_ACCESS, &ObjAttribs);
211 if (!NT_SUCCESS(Status))
212 {
213 WARN_(VIDEOPRT, "ZwOpenSection() failed! (0x%x)\n", Status);
214 return Status;
215 }
216
217 /* Map view of section */
218 Size = SizeInBytes;
219 Status = ZwMapViewOfSection(hMemObj,
220 Process,
221 VirtualAddress,
222 0,
223 Size,
224 (PLARGE_INTEGER)(&PhysicalAddress),
225 &Size,
226 ViewUnmap,
227 0,
228 Protect);
229 ZwClose(hMemObj);
230 if (!NT_SUCCESS(Status))
231 {
232 WARN_(VIDEOPRT, "ZwMapViewOfSection() failed! (0x%x)\n", Status);
233 }
234
235 return Status;
236 }
237
238
239 PVOID NTAPI
240 IntVideoPortMapMemory(
241 IN PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension,
242 IN PHYSICAL_ADDRESS IoAddress,
243 IN ULONG NumberOfUchars,
244 IN ULONG InIoSpace,
245 IN HANDLE ProcessHandle,
246 OUT VP_STATUS *Status)
247 {
248 PHYSICAL_ADDRESS TranslatedAddress;
249 PVIDEO_PORT_ADDRESS_MAPPING AddressMapping;
250 ULONG AddressSpace;
251 PVOID MappedAddress;
252 PLIST_ENTRY Entry;
253
254 INFO_(VIDEOPRT, "- IoAddress: %lx\n", IoAddress.u.LowPart);
255 INFO_(VIDEOPRT, "- NumberOfUchars: %lx\n", NumberOfUchars);
256 INFO_(VIDEOPRT, "- InIoSpace: %x\n", InIoSpace);
257
258 InIoSpace &= ~VIDEO_MEMORY_SPACE_DENSE;
259 if ((InIoSpace & VIDEO_MEMORY_SPACE_P6CACHE) != 0)
260 {
261 INFO_(VIDEOPRT, "VIDEO_MEMORY_SPACE_P6CACHE not supported, turning off\n");
262 InIoSpace &= ~VIDEO_MEMORY_SPACE_P6CACHE;
263 }
264
265 if (ProcessHandle != NULL && (InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE) == 0)
266 {
267 INFO_(VIDEOPRT, "ProcessHandle is not NULL (0x%x) but InIoSpace does not have "
268 "VIDEO_MEMORY_SPACE_USER_MODE set! Setting "
269 "VIDEO_MEMORY_SPACE_USER_MODE.\n",
270 ProcessHandle);
271 InIoSpace |= VIDEO_MEMORY_SPACE_USER_MODE;
272 }
273 else if (ProcessHandle == NULL && (InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE) != 0)
274 {
275 INFO_(VIDEOPRT, "ProcessHandle is NULL (0x%x) but InIoSpace does have "
276 "VIDEO_MEMORY_SPACE_USER_MODE set! Setting ProcessHandle "
277 "to NtCurrentProcess()\n",
278 ProcessHandle);
279 ProcessHandle = NtCurrentProcess();
280 }
281
282 if ((InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE) == 0 &&
283 !IsListEmpty(&DeviceExtension->AddressMappingListHead))
284 {
285 Entry = DeviceExtension->AddressMappingListHead.Flink;
286 while (Entry != &DeviceExtension->AddressMappingListHead)
287 {
288 AddressMapping = CONTAINING_RECORD(
289 Entry,
290 VIDEO_PORT_ADDRESS_MAPPING,
291 List);
292 if (IoAddress.QuadPart == AddressMapping->IoAddress.QuadPart &&
293 NumberOfUchars <= AddressMapping->NumberOfUchars)
294 {
295 {
296 AddressMapping->MappingCount++;
297 if (Status)
298 *Status = NO_ERROR;
299 return AddressMapping->MappedAddress;
300 }
301 }
302 Entry = Entry->Flink;
303 }
304 }
305
306 AddressSpace = (ULONG)InIoSpace;
307 AddressSpace &= ~VIDEO_MEMORY_SPACE_USER_MODE;
308 if (HalTranslateBusAddress(
309 DeviceExtension->AdapterInterfaceType,
310 DeviceExtension->SystemIoBusNumber,
311 IoAddress,
312 &AddressSpace,
313 &TranslatedAddress) == FALSE)
314 {
315 if (Status)
316 *Status = ERROR_NOT_ENOUGH_MEMORY;
317
318 return NULL;
319 }
320
321 /* I/O space */
322 if (AddressSpace != 0)
323 {
324 ASSERT(0 == TranslatedAddress.u.HighPart);
325 if (Status)
326 *Status = NO_ERROR;
327
328 return (PVOID)(ULONG_PTR)TranslatedAddress.u.LowPart;
329 }
330
331 /* user space */
332 if ((InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE) != 0)
333 {
334 NTSTATUS NtStatus;
335 MappedAddress = NULL;
336 NtStatus = IntVideoPortMapPhysicalMemory(ProcessHandle,
337 TranslatedAddress,
338 NumberOfUchars,
339 PAGE_READWRITE/* | PAGE_WRITECOMBINE*/,
340 &MappedAddress);
341 if (!NT_SUCCESS(NtStatus))
342 {
343 WARN_(VIDEOPRT, "IntVideoPortMapPhysicalMemory() failed! (0x%x)\n", NtStatus);
344 if (Status)
345 *Status = NO_ERROR;
346 return NULL;
347 }
348 INFO_(VIDEOPRT, "Mapped user address = 0x%08x\n", MappedAddress);
349 }
350 else /* kernel space */
351 {
352 MappedAddress = MmMapIoSpace(
353 TranslatedAddress,
354 NumberOfUchars,
355 MmNonCached);
356 }
357
358 if (MappedAddress != NULL)
359 {
360 if (Status)
361 {
362 *Status = NO_ERROR;
363 }
364 if ((InIoSpace & VIDEO_MEMORY_SPACE_USER_MODE) == 0)
365 {
366 AddressMapping = ExAllocatePoolWithTag(
367 PagedPool,
368 sizeof(VIDEO_PORT_ADDRESS_MAPPING),
369 TAG_VIDEO_PORT);
370
371 if (AddressMapping == NULL)
372 return MappedAddress;
373
374 RtlZeroMemory(AddressMapping, sizeof(VIDEO_PORT_ADDRESS_MAPPING));
375 AddressMapping->NumberOfUchars = NumberOfUchars;
376 AddressMapping->IoAddress = IoAddress;
377 AddressMapping->SystemIoBusNumber = DeviceExtension->SystemIoBusNumber;
378 AddressMapping->MappedAddress = MappedAddress;
379 AddressMapping->MappingCount = 1;
380 InsertHeadList(
381 &DeviceExtension->AddressMappingListHead,
382 &AddressMapping->List);
383 }
384
385 return MappedAddress;
386 }
387
388 if (Status)
389 *Status = NO_ERROR;
390
391 return NULL;
392 }
393
394 VOID NTAPI
395 IntVideoPortUnmapMemory(
396 IN PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension,
397 IN PVOID MappedAddress)
398 {
399 PVIDEO_PORT_ADDRESS_MAPPING AddressMapping;
400 PLIST_ENTRY Entry;
401 NTSTATUS Status;
402
403 Entry = DeviceExtension->AddressMappingListHead.Flink;
404 while (Entry != &DeviceExtension->AddressMappingListHead)
405 {
406 AddressMapping = CONTAINING_RECORD(
407 Entry,
408 VIDEO_PORT_ADDRESS_MAPPING,
409 List);
410 if (AddressMapping->MappedAddress == MappedAddress)
411 {
412 ASSERT(AddressMapping->MappingCount > 0);
413 AddressMapping->MappingCount--;
414 if (AddressMapping->MappingCount == 0)
415 {
416 MmUnmapIoSpace(
417 AddressMapping->MappedAddress,
418 AddressMapping->NumberOfUchars);
419 RemoveEntryList(Entry);
420 ExFreePool(AddressMapping);
421 }
422 return;
423 }
424
425 Entry = Entry->Flink;
426 }
427
428 /* If there was no kernelmode mapping for the given address found we assume
429 * that the given address is a usermode mapping and try to unmap it.
430 *
431 * FIXME: Is it ok to use NtCurrentProcess?
432 */
433 Status = ZwUnmapViewOfSection(NtCurrentProcess(), MappedAddress);
434 if (!NT_SUCCESS(Status))
435 {
436 WARN_(VIDEOPRT, "Warning: Mapping for address 0x%p not found!\n", MappedAddress);
437 }
438 }
439
440 /* PUBLIC FUNCTIONS ***********************************************************/
441
442 /*
443 * @implemented
444 */
445
446 PVOID NTAPI
447 VideoPortGetDeviceBase(
448 IN PVOID HwDeviceExtension,
449 IN PHYSICAL_ADDRESS IoAddress,
450 IN ULONG NumberOfUchars,
451 IN UCHAR InIoSpace)
452 {
453 TRACE_(VIDEOPRT, "VideoPortGetDeviceBase\n");
454 return IntVideoPortMapMemory(
455 VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension),
456 IoAddress,
457 NumberOfUchars,
458 InIoSpace,
459 NULL,
460 NULL);
461 }
462
463 /*
464 * @implemented
465 */
466
467 VOID NTAPI
468 VideoPortFreeDeviceBase(
469 IN PVOID HwDeviceExtension,
470 IN PVOID MappedAddress)
471 {
472 TRACE_(VIDEOPRT, "VideoPortFreeDeviceBase\n");
473 IntVideoPortUnmapMemory(
474 VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension),
475 MappedAddress);
476 }
477
478 /*
479 * @unimplemented
480 */
481
482 VP_STATUS NTAPI
483 VideoPortMapBankedMemory(
484 IN PVOID HwDeviceExtension,
485 IN PHYSICAL_ADDRESS PhysicalAddress,
486 IN PULONG Length,
487 IN PULONG InIoSpace,
488 OUT PVOID *VirtualAddress,
489 IN ULONG BankLength,
490 IN UCHAR ReadWriteBank,
491 IN PBANKED_SECTION_ROUTINE BankRoutine,
492 IN PVOID Context)
493 {
494 TRACE_(VIDEOPRT, "VideoPortMapBankedMemory\n");
495 UNIMPLEMENTED;
496 return ERROR_INVALID_FUNCTION;
497 }
498
499
500 /*
501 * @implemented
502 */
503
504 VP_STATUS NTAPI
505 VideoPortMapMemory(
506 IN PVOID HwDeviceExtension,
507 IN PHYSICAL_ADDRESS PhysicalAddress,
508 IN PULONG Length,
509 IN PULONG InIoSpace,
510 OUT PVOID *VirtualAddress)
511 {
512 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
513 NTSTATUS Status;
514
515 TRACE_(VIDEOPRT, "VideoPortMapMemory\n");
516 INFO_(VIDEOPRT, "- *VirtualAddress: 0x%x\n", *VirtualAddress);
517
518 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
519 *VirtualAddress = IntVideoPortMapMemory(
520 DeviceExtension,
521 PhysicalAddress,
522 *Length,
523 *InIoSpace,
524 (HANDLE)*VirtualAddress,
525 &Status);
526
527 return Status;
528 }
529
530 /*
531 * @implemented
532 */
533
534 VP_STATUS NTAPI
535 VideoPortUnmapMemory(
536 IN PVOID HwDeviceExtension,
537 IN PVOID VirtualAddress,
538 IN HANDLE ProcessHandle)
539 {
540 TRACE_(VIDEOPRT, "VideoPortFreeDeviceBase\n");
541
542 IntVideoPortUnmapMemory(
543 VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension),
544 VirtualAddress);
545
546 return NO_ERROR;
547 }
548
549 /*
550 * @implemented
551 */
552
553 VP_STATUS NTAPI
554 VideoPortGetAccessRanges(
555 IN PVOID HwDeviceExtension,
556 IN ULONG NumRequestedResources,
557 IN PIO_RESOURCE_DESCRIPTOR RequestedResources OPTIONAL,
558 IN ULONG NumAccessRanges,
559 IN PVIDEO_ACCESS_RANGE AccessRanges,
560 IN PVOID VendorId,
561 IN PVOID DeviceId,
562 OUT PULONG Slot)
563 {
564 PCI_SLOT_NUMBER PciSlotNumber;
565 ULONG DeviceNumber;
566 ULONG FunctionNumber;
567 PCI_COMMON_CONFIG Config;
568 PCM_RESOURCE_LIST AllocatedResources;
569 NTSTATUS Status;
570 UINT AssignedCount = 0;
571 CM_FULL_RESOURCE_DESCRIPTOR *FullList;
572 CM_PARTIAL_RESOURCE_DESCRIPTOR *Descriptor;
573 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
574 PVIDEO_PORT_DRIVER_EXTENSION DriverExtension;
575 USHORT VendorIdToFind;
576 USHORT DeviceIdToFind;
577 ULONG ReturnedLength;
578 PVIDEO_ACCESS_RANGE LegacyAccessRanges;
579 ULONG LegacyAccessRangeCount;
580 PDRIVER_OBJECT DriverObject;
581 ULONG ListSize;
582 PIO_RESOURCE_REQUIREMENTS_LIST ResReqList;
583 BOOLEAN DeviceAndVendorFound = FALSE;
584
585 TRACE_(VIDEOPRT, "VideoPortGetAccessRanges(%d, %p, %d, %p)\n", NumRequestedResources, RequestedResources, NumAccessRanges, AccessRanges);
586
587 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
588 DriverObject = DeviceExtension->DriverObject;
589 DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
590
591 if (NumRequestedResources == 0)
592 {
593 AllocatedResources = DeviceExtension->AllocatedResources;
594 if (AllocatedResources == NULL &&
595 DeviceExtension->AdapterInterfaceType == PCIBus)
596 {
597 if (DeviceExtension->PhysicalDeviceObject != NULL)
598 {
599 PciSlotNumber.u.AsULONG = DeviceExtension->SystemIoSlotNumber;
600
601 ReturnedLength = HalGetBusData(PCIConfiguration,
602 DeviceExtension->SystemIoBusNumber,
603 PciSlotNumber.u.AsULONG,
604 &Config,
605 sizeof(PCI_COMMON_CONFIG));
606
607 if (ReturnedLength != sizeof(PCI_COMMON_CONFIG))
608 {
609 return ERROR_NOT_ENOUGH_MEMORY;
610 }
611 }
612 else
613 {
614 VendorIdToFind = VendorId != NULL ? *(PUSHORT)VendorId : 0;
615 DeviceIdToFind = DeviceId != NULL ? *(PUSHORT)DeviceId : 0;
616
617 if (VendorIdToFind == 0 && DeviceIdToFind == 0)
618 {
619 /* We're screwed */
620 return ERROR_DEV_NOT_EXIST;
621 }
622
623 INFO_(VIDEOPRT, "Looking for VendorId 0x%04x DeviceId 0x%04x\n",
624 VendorIdToFind, DeviceIdToFind);
625
626 /*
627 * Search for the device id and vendor id on this bus.
628 */
629 for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++)
630 {
631 PciSlotNumber.u.bits.DeviceNumber = DeviceNumber;
632 for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++)
633 {
634 INFO_(VIDEOPRT, "- Function number: %d\n", FunctionNumber);
635 PciSlotNumber.u.bits.FunctionNumber = FunctionNumber;
636 ReturnedLength = HalGetBusData(PCIConfiguration,
637 DeviceExtension->SystemIoBusNumber,
638 PciSlotNumber.u.AsULONG,
639 &Config,
640 sizeof(PCI_COMMON_CONFIG));
641 INFO_(VIDEOPRT, "- Length of data: %x\n", ReturnedLength);
642 if (ReturnedLength == sizeof(PCI_COMMON_CONFIG))
643 {
644 INFO_(VIDEOPRT, "- Slot 0x%02x (Device %d Function %d) VendorId 0x%04x "
645 "DeviceId 0x%04x\n",
646 PciSlotNumber.u.AsULONG,
647 PciSlotNumber.u.bits.DeviceNumber,
648 PciSlotNumber.u.bits.FunctionNumber,
649 Config.VendorID,
650 Config.DeviceID);
651
652 if ((VendorIdToFind == 0 || Config.VendorID == VendorIdToFind) &&
653 (DeviceIdToFind == 0 || Config.DeviceID == DeviceIdToFind))
654 {
655 DeviceAndVendorFound = TRUE;
656 break;
657 }
658 }
659 }
660 if (DeviceAndVendorFound) break;
661 }
662 if (FunctionNumber == PCI_MAX_FUNCTION)
663 {
664 WARN_(VIDEOPRT, "Didn't find device.\n");
665 return ERROR_DEV_NOT_EXIST;
666 }
667 }
668
669 Status = HalAssignSlotResources(&DeviceExtension->RegistryPath,
670 NULL,
671 DeviceExtension->DriverObject,
672 DeviceExtension->DriverObject->DeviceObject,
673 DeviceExtension->AdapterInterfaceType,
674 DeviceExtension->SystemIoBusNumber,
675 PciSlotNumber.u.AsULONG,
676 &AllocatedResources);
677
678 if (!NT_SUCCESS(Status))
679 {
680 WARN_(VIDEOPRT, "HalAssignSlotResources failed with status %x.\n",Status);
681 return Status;
682 }
683 DeviceExtension->AllocatedResources = AllocatedResources;
684 DeviceExtension->SystemIoSlotNumber = PciSlotNumber.u.AsULONG;
685
686 /* Add legacy resources to the resources from HAL */
687 Status = IntVideoPortGetLegacyResources(DriverExtension, DeviceExtension,
688 &LegacyAccessRanges, &LegacyAccessRangeCount);
689 if (!NT_SUCCESS(Status))
690 return ERROR_DEV_NOT_EXIST;
691
692 if (NumAccessRanges < LegacyAccessRangeCount)
693 {
694 ERR_(VIDEOPRT, "Too many legacy access ranges found\n");
695 return ERROR_NOT_ENOUGH_MEMORY;
696 }
697
698 RtlCopyMemory(AccessRanges, LegacyAccessRanges, LegacyAccessRangeCount * sizeof(VIDEO_ACCESS_RANGE));
699 AssignedCount = LegacyAccessRangeCount;
700 }
701 }
702 else
703 {
704 ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + (NumRequestedResources - 1) * sizeof(IO_RESOURCE_DESCRIPTOR);
705 ResReqList = ExAllocatePool(NonPagedPool, ListSize);
706 if (!ResReqList) return ERROR_NOT_ENOUGH_MEMORY;
707
708 ResReqList->ListSize = ListSize;
709 ResReqList->InterfaceType = DeviceExtension->AdapterInterfaceType;
710 ResReqList->BusNumber = DeviceExtension->SystemIoBusNumber;
711 ResReqList->SlotNumber = DeviceExtension->SystemIoSlotNumber;
712 ResReqList->AlternativeLists = 1;
713 ResReqList->List[0].Version = 1;
714 ResReqList->List[0].Revision = 1;
715 ResReqList->List[0].Count = NumRequestedResources;
716
717 /* Copy in the caller's resource list */
718 RtlCopyMemory(ResReqList->List[0].Descriptors,
719 RequestedResources,
720 NumRequestedResources * sizeof(IO_RESOURCE_DESCRIPTOR));
721
722 Status = IoAssignResources(&DeviceExtension->RegistryPath,
723 NULL,
724 DeviceExtension->DriverObject,
725 DeviceExtension->PhysicalDeviceObject ?
726 DeviceExtension->PhysicalDeviceObject :
727 DeviceExtension->DriverObject->DeviceObject,
728 ResReqList,
729 &AllocatedResources);
730
731 if (!NT_SUCCESS(Status))
732 return Status;
733
734 if (!DeviceExtension->AllocatedResources)
735 DeviceExtension->AllocatedResources = AllocatedResources;
736 }
737
738 if (AllocatedResources == NULL)
739 return ERROR_NOT_ENOUGH_MEMORY;
740
741 /* Return the slot number if the caller wants it */
742 if (Slot != NULL) *Slot = DeviceExtension->SystemIoBusNumber;
743
744 for (FullList = AllocatedResources->List;
745 FullList < AllocatedResources->List + AllocatedResources->Count;
746 FullList++)
747 {
748 INFO_(VIDEOPRT, "InterfaceType %u BusNumber List %u Device BusNumber %u Version %u Revision %u\n",
749 FullList->InterfaceType, FullList->BusNumber, DeviceExtension->SystemIoBusNumber, FullList->PartialResourceList.Version, FullList->PartialResourceList.Revision);
750
751 ASSERT(FullList->InterfaceType == PCIBus);
752 ASSERT(FullList->BusNumber == DeviceExtension->SystemIoBusNumber);
753 ASSERT(1 == FullList->PartialResourceList.Version);
754 ASSERT(1 == FullList->PartialResourceList.Revision);
755 for (Descriptor = FullList->PartialResourceList.PartialDescriptors;
756 Descriptor < FullList->PartialResourceList.PartialDescriptors + FullList->PartialResourceList.Count;
757 Descriptor++)
758 {
759 if ((Descriptor->Type == CmResourceTypeMemory ||
760 Descriptor->Type == CmResourceTypePort) &&
761 AssignedCount >= NumAccessRanges)
762 {
763 ERR_(VIDEOPRT, "Too many access ranges found\n");
764 return ERROR_NOT_ENOUGH_MEMORY;
765 }
766 if (Descriptor->Type == CmResourceTypeMemory)
767 {
768 INFO_(VIDEOPRT, "Memory range starting at 0x%08x length 0x%08x\n",
769 Descriptor->u.Memory.Start.u.LowPart, Descriptor->u.Memory.Length);
770 AccessRanges[AssignedCount].RangeStart = Descriptor->u.Memory.Start;
771 AccessRanges[AssignedCount].RangeLength = Descriptor->u.Memory.Length;
772 AccessRanges[AssignedCount].RangeInIoSpace = 0;
773 AccessRanges[AssignedCount].RangeVisible = 0; /* FIXME: Just guessing */
774 AccessRanges[AssignedCount].RangeShareable =
775 (Descriptor->ShareDisposition == CmResourceShareShared);
776 AccessRanges[AssignedCount].RangePassive = 0;
777 AssignedCount++;
778 }
779 else if (Descriptor->Type == CmResourceTypePort)
780 {
781 INFO_(VIDEOPRT, "Port range starting at 0x%04x length %d\n",
782 Descriptor->u.Port.Start.u.LowPart, Descriptor->u.Port.Length);
783 AccessRanges[AssignedCount].RangeStart = Descriptor->u.Port.Start;
784 AccessRanges[AssignedCount].RangeLength = Descriptor->u.Port.Length;
785 AccessRanges[AssignedCount].RangeInIoSpace = 1;
786 AccessRanges[AssignedCount].RangeVisible = 0; /* FIXME: Just guessing */
787 AccessRanges[AssignedCount].RangeShareable =
788 (Descriptor->ShareDisposition == CmResourceShareShared);
789 AccessRanges[AssignedCount].RangePassive = 0;
790 if (Descriptor->Flags & CM_RESOURCE_PORT_10_BIT_DECODE)
791 AccessRanges[AssignedCount].RangePassive |= VIDEO_RANGE_10_BIT_DECODE;
792 if (Descriptor->Flags & CM_RESOURCE_PORT_PASSIVE_DECODE)
793 AccessRanges[AssignedCount].RangePassive |= VIDEO_RANGE_PASSIVE_DECODE;
794 AssignedCount++;
795 }
796 else if (Descriptor->Type == CmResourceTypeInterrupt)
797 {
798 DeviceExtension->InterruptLevel = Descriptor->u.Interrupt.Level;
799 DeviceExtension->InterruptVector = Descriptor->u.Interrupt.Vector;
800 if (Descriptor->ShareDisposition == CmResourceShareShared)
801 DeviceExtension->InterruptShared = TRUE;
802 else
803 DeviceExtension->InterruptShared = FALSE;
804 }
805 }
806 }
807
808 return NO_ERROR;
809 }
810
811 /*
812 * @implemented
813 */
814
815 VP_STATUS NTAPI
816 VideoPortVerifyAccessRanges(
817 IN PVOID HwDeviceExtension,
818 IN ULONG NumAccessRanges,
819 IN PVIDEO_ACCESS_RANGE AccessRanges)
820 {
821 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
822 BOOLEAN ConflictDetected;
823 ULONG i;
824 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
825 PCM_RESOURCE_LIST ResourceList;
826 ULONG ResourceListSize;
827 NTSTATUS Status;
828
829 TRACE_(VIDEOPRT, "VideoPortVerifyAccessRanges\n");
830
831 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
832
833 /* Create the resource list */
834 ResourceListSize = sizeof(CM_RESOURCE_LIST)
835 + (NumAccessRanges - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
836 ResourceList = ExAllocatePool(PagedPool, ResourceListSize);
837 if (!ResourceList)
838 {
839 WARN_(VIDEOPRT, "ExAllocatePool() failed\n");
840 return ERROR_INVALID_PARAMETER;
841 }
842
843 /* Fill resource list */
844 ResourceList->Count = 1;
845 ResourceList->List[0].InterfaceType = DeviceExtension->AdapterInterfaceType;
846 ResourceList->List[0].BusNumber = DeviceExtension->SystemIoBusNumber;
847 ResourceList->List[0].PartialResourceList.Version = 1;
848 ResourceList->List[0].PartialResourceList.Revision = 1;
849 ResourceList->List[0].PartialResourceList.Count = NumAccessRanges;
850 for (i = 0; i < NumAccessRanges; i++, AccessRanges++)
851 {
852 PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
853 if (AccessRanges->RangeInIoSpace)
854 {
855 PartialDescriptor->Type = CmResourceTypePort;
856 PartialDescriptor->u.Port.Start = AccessRanges->RangeStart;
857 PartialDescriptor->u.Port.Length = AccessRanges->RangeLength;
858 }
859 else
860 {
861 PartialDescriptor->Type = CmResourceTypeMemory;
862 PartialDescriptor->u.Memory.Start = AccessRanges->RangeStart;
863 PartialDescriptor->u.Memory.Length = AccessRanges->RangeLength;
864 }
865 if (AccessRanges->RangeShareable)
866 PartialDescriptor->ShareDisposition = CmResourceShareShared;
867 else
868 PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
869 PartialDescriptor->Flags = 0;
870 if (AccessRanges->RangePassive & VIDEO_RANGE_PASSIVE_DECODE)
871 PartialDescriptor->Flags |= CM_RESOURCE_PORT_PASSIVE_DECODE;
872 if (AccessRanges->RangePassive & VIDEO_RANGE_10_BIT_DECODE)
873 PartialDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
874 }
875
876 /* Try to acquire all resource ranges */
877 Status = IoReportResourceForDetection(
878 DeviceExtension->DriverObject,
879 NULL, 0, /* Driver List */
880 DeviceExtension->PhysicalDeviceObject,
881 ResourceList, ResourceListSize,
882 &ConflictDetected);
883 ExFreePool(ResourceList);
884
885 if (!NT_SUCCESS(Status) || ConflictDetected)
886 return ERROR_INVALID_PARAMETER;
887 else
888 return NO_ERROR;
889 }
890
891 /*
892 * @unimplemented
893 */
894
895 VP_STATUS NTAPI
896 VideoPortGetDeviceData(
897 IN PVOID HwDeviceExtension,
898 IN VIDEO_DEVICE_DATA_TYPE DeviceDataType,
899 IN PMINIPORT_QUERY_DEVICE_ROUTINE CallbackRoutine,
900 IN PVOID Context)
901 {
902 TRACE_(VIDEOPRT, "VideoPortGetDeviceData\n");
903 UNIMPLEMENTED;
904 return ERROR_INVALID_FUNCTION;
905 }
906
907 /*
908 * @implemented
909 */
910
911 PVOID NTAPI
912 VideoPortAllocatePool(
913 IN PVOID HwDeviceExtension,
914 IN VP_POOL_TYPE PoolType,
915 IN SIZE_T NumberOfBytes,
916 IN ULONG Tag)
917 {
918 TRACE_(VIDEOPRT, "VideoPortAllocatePool\n");
919 return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
920 }
921
922 /*
923 * @implemented
924 */
925
926 VOID NTAPI
927 VideoPortFreePool(
928 IN PVOID HwDeviceExtension,
929 IN PVOID Ptr)
930 {
931 ExFreePool(Ptr);
932 }
933
934 /*
935 * @implemented
936 */
937
938 VP_STATUS NTAPI
939 VideoPortAllocateBuffer(
940 IN PVOID HwDeviceExtension,
941 IN ULONG Size,
942 OUT PVOID *Buffer)
943 {
944 TRACE_(VIDEOPRT, "VideoPortAllocateBuffer\n");
945 *Buffer = ExAllocatePoolWithTag ( PagedPool, Size, TAG_VIDEO_PORT_BUFFER ) ;
946 return *Buffer == NULL ? ERROR_NOT_ENOUGH_MEMORY : NO_ERROR;
947 }
948
949 /*
950 * @implemented
951 */
952
953 VOID NTAPI
954 VideoPortReleaseBuffer(
955 IN PVOID HwDeviceExtension,
956 IN PVOID Ptr)
957 {
958 TRACE_(VIDEOPRT, "VideoPortReleaseBuffer\n");
959 ExFreePool(Ptr);
960 }
961
962 /*
963 * @implemented
964 */
965
966 PVOID NTAPI
967 VideoPortLockBuffer(
968 IN PVOID HwDeviceExtension,
969 IN PVOID BaseAddress,
970 IN ULONG Length,
971 IN VP_LOCK_OPERATION Operation)
972 {
973 PMDL Mdl;
974
975 Mdl = IoAllocateMdl(BaseAddress, Length, FALSE, FALSE, NULL);
976 if (!Mdl)
977 {
978 return NULL;
979 }
980 /* FIXME use seh */
981 MmProbeAndLockPages(Mdl, KernelMode,Operation);
982 return Mdl;
983 }
984
985 /*
986 * @implemented
987 */
988
989 BOOLEAN
990 NTAPI
991 VideoPortLockPages(
992 IN PVOID HwDeviceExtension,
993 IN OUT PVIDEO_REQUEST_PACKET pVrp,
994 IN PEVENT pUEvent,
995 IN PEVENT pDisplayEvent,
996 IN DMA_FLAGS DmaFlags)
997 {
998 PVOID Buffer;
999
1000 /* clear output buffer */
1001 pVrp->OutputBuffer = NULL;
1002
1003 if (DmaFlags != VideoPortDmaInitOnly)
1004 {
1005 /* VideoPortKeepPagesLocked / VideoPortUnlockAfterDma is no-op */
1006 return FALSE;
1007 }
1008
1009 /* lock the buffer */
1010 Buffer = VideoPortLockBuffer(HwDeviceExtension, pVrp->InputBuffer, pVrp->InputBufferLength, IoModifyAccess);
1011
1012 if (Buffer)
1013 {
1014 /* store result buffer & length */
1015 pVrp->OutputBuffer = Buffer;
1016 pVrp->OutputBufferLength = pVrp->InputBufferLength;
1017
1018 /* operation succeeded */
1019 return TRUE;
1020 }
1021
1022 /* operation failed */
1023 return FALSE;
1024 }
1025
1026
1027 /*
1028 * @implemented
1029 */
1030
1031 VOID NTAPI
1032 VideoPortUnlockBuffer(
1033 IN PVOID HwDeviceExtension,
1034 IN PVOID Mdl)
1035 {
1036 if (Mdl)
1037 {
1038 MmUnlockPages((PMDL)Mdl);
1039 IoFreeMdl(Mdl);
1040 }
1041 }
1042
1043 /*
1044 * @unimplemented
1045 */
1046
1047 VP_STATUS NTAPI
1048 VideoPortSetTrappedEmulatorPorts(
1049 IN PVOID HwDeviceExtension,
1050 IN ULONG NumAccessRanges,
1051 IN PVIDEO_ACCESS_RANGE AccessRange)
1052 {
1053 UNIMPLEMENTED;
1054 /* Should store the ranges in the device extension for use by ntvdm. */
1055 return NO_ERROR;
1056 }
1057
1058 /*
1059 * @implemented
1060 */
1061
1062 ULONG NTAPI
1063 VideoPortGetBusData(
1064 IN PVOID HwDeviceExtension,
1065 IN BUS_DATA_TYPE BusDataType,
1066 IN ULONG SlotNumber,
1067 OUT PVOID Buffer,
1068 IN ULONG Offset,
1069 IN ULONG Length)
1070 {
1071 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1072
1073 TRACE_(VIDEOPRT, "VideoPortGetBusData\n");
1074
1075 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1076
1077 if (BusDataType != Cmos)
1078 {
1079 /* Legacy vs. PnP behaviour */
1080 if (DeviceExtension->PhysicalDeviceObject != NULL)
1081 SlotNumber = DeviceExtension->SystemIoSlotNumber;
1082 }
1083
1084 return HalGetBusDataByOffset(
1085 BusDataType,
1086 DeviceExtension->SystemIoBusNumber,
1087 SlotNumber,
1088 Buffer,
1089 Offset,
1090 Length);
1091 }
1092
1093 /*
1094 * @implemented
1095 */
1096
1097 ULONG NTAPI
1098 VideoPortSetBusData(
1099 IN PVOID HwDeviceExtension,
1100 IN BUS_DATA_TYPE BusDataType,
1101 IN ULONG SlotNumber,
1102 IN PVOID Buffer,
1103 IN ULONG Offset,
1104 IN ULONG Length)
1105 {
1106 PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1107
1108 TRACE_(VIDEOPRT, "VideoPortSetBusData\n");
1109
1110 DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1111
1112 if (BusDataType != Cmos)
1113 {
1114 /* Legacy vs. PnP behaviour */
1115 if (DeviceExtension->PhysicalDeviceObject != NULL)
1116 SlotNumber = DeviceExtension->SystemIoSlotNumber;
1117 }
1118
1119 return HalSetBusDataByOffset(
1120 BusDataType,
1121 DeviceExtension->SystemIoBusNumber,
1122 SlotNumber,
1123 Buffer,
1124 Offset,
1125 Length);
1126 }