xref: /reactos/win32ss/drivers/videoprt/resource.c (revision ea6e7740)
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.Status;
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         else 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         else
808         {
809             ASSERT(FALSE);
810             return ERROR_INVALID_PARAMETER;
811         }
812     }
813 
814     return NO_ERROR;
815 }
816 
817 /*
818  * @implemented
819  */
820 
821 VP_STATUS NTAPI
822 VideoPortVerifyAccessRanges(
823    IN PVOID HwDeviceExtension,
824    IN ULONG NumAccessRanges,
825    IN PVIDEO_ACCESS_RANGE AccessRanges)
826 {
827    PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
828    BOOLEAN ConflictDetected;
829    ULONG i;
830    PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
831    PCM_RESOURCE_LIST ResourceList;
832    ULONG ResourceListSize;
833    NTSTATUS Status;
834 
835    TRACE_(VIDEOPRT, "VideoPortVerifyAccessRanges\n");
836 
837    DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
838 
839    /* Create the resource list */
840    ResourceListSize = sizeof(CM_RESOURCE_LIST)
841       + (NumAccessRanges - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
842    ResourceList = ExAllocatePool(PagedPool, ResourceListSize);
843    if (!ResourceList)
844    {
845       WARN_(VIDEOPRT, "ExAllocatePool() failed\n");
846       return ERROR_NOT_ENOUGH_MEMORY;
847    }
848 
849    /* Fill resource list */
850    ResourceList->Count = 1;
851    ResourceList->List[0].InterfaceType = DeviceExtension->AdapterInterfaceType;
852    ResourceList->List[0].BusNumber = DeviceExtension->SystemIoBusNumber;
853    ResourceList->List[0].PartialResourceList.Version = 1;
854    ResourceList->List[0].PartialResourceList.Revision = 1;
855    ResourceList->List[0].PartialResourceList.Count = NumAccessRanges;
856    for (i = 0; i < NumAccessRanges; i++, AccessRanges++)
857    {
858       PartialDescriptor = &ResourceList->List[0].PartialResourceList.PartialDescriptors[i];
859       if (AccessRanges->RangeInIoSpace)
860       {
861          PartialDescriptor->Type = CmResourceTypePort;
862          PartialDescriptor->u.Port.Start = AccessRanges->RangeStart;
863          PartialDescriptor->u.Port.Length = AccessRanges->RangeLength;
864       }
865       else
866       {
867          PartialDescriptor->Type = CmResourceTypeMemory;
868          PartialDescriptor->u.Memory.Start = AccessRanges->RangeStart;
869          PartialDescriptor->u.Memory.Length = AccessRanges->RangeLength;
870       }
871       if (AccessRanges->RangeShareable)
872          PartialDescriptor->ShareDisposition = CmResourceShareShared;
873       else
874          PartialDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
875       PartialDescriptor->Flags = 0;
876       if (AccessRanges->RangePassive & VIDEO_RANGE_PASSIVE_DECODE)
877          PartialDescriptor->Flags |= CM_RESOURCE_PORT_PASSIVE_DECODE;
878       if (AccessRanges->RangePassive & VIDEO_RANGE_10_BIT_DECODE)
879          PartialDescriptor->Flags |= CM_RESOURCE_PORT_10_BIT_DECODE;
880    }
881 
882    /* Try to acquire all resource ranges */
883    Status = IoReportResourceForDetection(
884       DeviceExtension->DriverObject,
885       NULL, 0, /* Driver List */
886       DeviceExtension->PhysicalDeviceObject,
887       ResourceList, ResourceListSize,
888       &ConflictDetected);
889    ExFreePool(ResourceList);
890 
891    if (!NT_SUCCESS(Status) || ConflictDetected)
892       return ERROR_INVALID_PARAMETER;
893    else
894       return NO_ERROR;
895 }
896 
897 /*
898  * @unimplemented
899  */
900 
901 VP_STATUS NTAPI
902 VideoPortGetDeviceData(
903    IN PVOID HwDeviceExtension,
904    IN VIDEO_DEVICE_DATA_TYPE DeviceDataType,
905    IN PMINIPORT_QUERY_DEVICE_ROUTINE CallbackRoutine,
906    IN PVOID Context)
907 {
908    TRACE_(VIDEOPRT, "VideoPortGetDeviceData\n");
909    UNIMPLEMENTED;
910    return ERROR_INVALID_FUNCTION;
911 }
912 
913 /*
914  * @implemented
915  */
916 
917 PVOID NTAPI
918 VideoPortAllocatePool(
919    IN PVOID HwDeviceExtension,
920    IN VP_POOL_TYPE PoolType,
921    IN SIZE_T NumberOfBytes,
922    IN ULONG Tag)
923 {
924    TRACE_(VIDEOPRT, "VideoPortAllocatePool\n");
925    return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
926 }
927 
928 /*
929  * @implemented
930  */
931 
932 VOID NTAPI
933 VideoPortFreePool(
934    IN PVOID HwDeviceExtension,
935    IN PVOID Ptr)
936 {
937    ExFreePool(Ptr);
938 }
939 
940 /*
941  * @implemented
942  */
943 
944 VP_STATUS NTAPI
945 VideoPortAllocateBuffer(
946    IN PVOID HwDeviceExtension,
947    IN ULONG Size,
948    OUT PVOID *Buffer)
949 {
950    TRACE_(VIDEOPRT, "VideoPortAllocateBuffer\n");
951    *Buffer = ExAllocatePoolWithTag ( PagedPool, Size, TAG_VIDEO_PORT_BUFFER ) ;
952    return *Buffer == NULL ? ERROR_NOT_ENOUGH_MEMORY : NO_ERROR;
953 }
954 
955 /*
956  * @implemented
957  */
958 
959 VOID NTAPI
960 VideoPortReleaseBuffer(
961    IN PVOID HwDeviceExtension,
962    IN PVOID Ptr)
963 {
964    TRACE_(VIDEOPRT, "VideoPortReleaseBuffer\n");
965    ExFreePool(Ptr);
966 }
967 
968 /*
969  * @implemented
970  */
971 
972 PVOID NTAPI
973 VideoPortLockBuffer(
974    IN PVOID HwDeviceExtension,
975    IN PVOID BaseAddress,
976    IN ULONG Length,
977    IN VP_LOCK_OPERATION Operation)
978 {
979     PMDL Mdl;
980 
981     Mdl = IoAllocateMdl(BaseAddress, Length, FALSE, FALSE, NULL);
982     if (!Mdl)
983     {
984         return NULL;
985     }
986     /* FIXME use seh */
987     MmProbeAndLockPages(Mdl, KernelMode,Operation);
988     return Mdl;
989 }
990 
991 /*
992  * @implemented
993  */
994 
995 BOOLEAN
996 NTAPI
997 VideoPortLockPages(
998     IN PVOID HwDeviceExtension,
999     IN OUT PVIDEO_REQUEST_PACKET pVrp,
1000     IN PEVENT pUEvent,
1001     IN PEVENT pDisplayEvent,
1002     IN DMA_FLAGS DmaFlags)
1003 {
1004     PVOID Buffer;
1005 
1006     /* clear output buffer */
1007     pVrp->OutputBuffer = NULL;
1008 
1009     if (DmaFlags != VideoPortDmaInitOnly)
1010     {
1011         /* VideoPortKeepPagesLocked / VideoPortUnlockAfterDma is no-op */
1012         return FALSE;
1013     }
1014 
1015     /* lock the buffer */
1016     Buffer = VideoPortLockBuffer(HwDeviceExtension, pVrp->InputBuffer, pVrp->InputBufferLength, IoModifyAccess);
1017 
1018     if (Buffer)
1019     {
1020         /* store result buffer & length */
1021         pVrp->OutputBuffer = Buffer;
1022         pVrp->OutputBufferLength = pVrp->InputBufferLength;
1023 
1024         /* operation succeeded */
1025         return TRUE;
1026     }
1027 
1028     /* operation failed */
1029     return FALSE;
1030 }
1031 
1032 
1033 /*
1034  * @implemented
1035  */
1036 
1037 VOID NTAPI
1038 VideoPortUnlockBuffer(
1039    IN PVOID HwDeviceExtension,
1040    IN PVOID Mdl)
1041 {
1042     if (Mdl)
1043     {
1044         MmUnlockPages((PMDL)Mdl);
1045         IoFreeMdl(Mdl);
1046     }
1047 }
1048 
1049 /*
1050  * @unimplemented
1051  */
1052 
1053 VP_STATUS NTAPI
1054 VideoPortSetTrappedEmulatorPorts(
1055    IN PVOID HwDeviceExtension,
1056    IN ULONG NumAccessRanges,
1057    IN PVIDEO_ACCESS_RANGE AccessRange)
1058 {
1059     UNIMPLEMENTED;
1060     /* Should store the ranges in the device extension for use by ntvdm. */
1061     return NO_ERROR;
1062 }
1063 
1064 /*
1065  * @implemented
1066  */
1067 
1068 ULONG NTAPI
1069 VideoPortGetBusData(
1070    IN PVOID HwDeviceExtension,
1071    IN BUS_DATA_TYPE BusDataType,
1072    IN ULONG SlotNumber,
1073    OUT PVOID Buffer,
1074    IN ULONG Offset,
1075    IN ULONG Length)
1076 {
1077    PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1078 
1079    TRACE_(VIDEOPRT, "VideoPortGetBusData\n");
1080 
1081    DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1082 
1083    if (BusDataType != Cmos)
1084    {
1085       /* Legacy vs. PnP behaviour */
1086       if (DeviceExtension->PhysicalDeviceObject != NULL)
1087          SlotNumber = DeviceExtension->SystemIoSlotNumber;
1088    }
1089 
1090    return HalGetBusDataByOffset(
1091       BusDataType,
1092       DeviceExtension->SystemIoBusNumber,
1093       SlotNumber,
1094       Buffer,
1095       Offset,
1096       Length);
1097 }
1098 
1099 /*
1100  * @implemented
1101  */
1102 
1103 ULONG NTAPI
1104 VideoPortSetBusData(
1105    IN PVOID HwDeviceExtension,
1106    IN BUS_DATA_TYPE BusDataType,
1107    IN ULONG SlotNumber,
1108    IN PVOID Buffer,
1109    IN ULONG Offset,
1110    IN ULONG Length)
1111 {
1112    PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension;
1113 
1114    TRACE_(VIDEOPRT, "VideoPortSetBusData\n");
1115 
1116    DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension);
1117 
1118    if (BusDataType != Cmos)
1119    {
1120       /* Legacy vs. PnP behaviour */
1121       if (DeviceExtension->PhysicalDeviceObject != NULL)
1122          SlotNumber = DeviceExtension->SystemIoSlotNumber;
1123    }
1124 
1125    return HalSetBusDataByOffset(
1126       BusDataType,
1127       DeviceExtension->SystemIoBusNumber,
1128       SlotNumber,
1129       Buffer,
1130       Offset,
1131       Length);
1132 }
1133