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