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