1 /* 2 * PROJECT: ReactOS PCI Bus Driver 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/bus/pci/device.c 5 * PURPOSE: Device Management 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <pci.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* FUNCTIONS ******************************************************************/ 17 18 VOID 19 NTAPI 20 Device_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context) 21 { 22 PPCI_COMMON_HEADER PciData; 23 PIO_RESOURCE_DESCRIPTOR IoDescriptor; 24 PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor; 25 PPCI_FUNCTION_RESOURCES Resources; 26 PULONG BarArray; 27 ULONG Bar, BarMask, i; 28 29 /* Get variables from context */ 30 PciData = Context->Current; 31 Resources = Context->PdoExtension->Resources; 32 33 /* Loop all the PCI BARs */ 34 BarArray = PciData->u.type0.BaseAddresses; 35 for (i = 0; i <= PCI_TYPE0_ADDRESSES; i++) 36 { 37 /* Get the resource descriptor and limit descriptor for this BAR */ 38 CmDescriptor = &Resources->Current[i]; 39 IoDescriptor = &Resources->Limit[i]; 40 41 /* Build the resource descriptor based on the limit descriptor */ 42 CmDescriptor->Type = IoDescriptor->Type; 43 if (CmDescriptor->Type == CmResourceTypeNull) continue; 44 CmDescriptor->Flags = IoDescriptor->Flags; 45 CmDescriptor->ShareDisposition = IoDescriptor->ShareDisposition; 46 CmDescriptor->u.Generic.Start.HighPart = 0; 47 CmDescriptor->u.Generic.Length = IoDescriptor->u.Generic.Length; 48 49 /* Check if we're handling PCI BARs, or the ROM BAR */ 50 if (i < PCI_TYPE0_ADDRESSES) 51 { 52 /* Read the actual BAR value */ 53 Bar = BarArray[i]; 54 55 /* Check if this is an I/O BAR */ 56 if (Bar & PCI_ADDRESS_IO_SPACE) 57 { 58 /* Use the right mask to get the I/O port base address */ 59 ASSERT(CmDescriptor->Type == CmResourceTypePort); 60 BarMask = PCI_ADDRESS_IO_ADDRESS_MASK; 61 } 62 else 63 { 64 /* It's a RAM BAR, use the right mask to get the base address */ 65 ASSERT(CmDescriptor->Type == CmResourceTypeMemory); 66 BarMask = PCI_ADDRESS_MEMORY_ADDRESS_MASK; 67 68 /* Check if it's a 64-bit BAR */ 69 if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT) 70 { 71 /* The next BAR value is actually the high 32-bits */ 72 CmDescriptor->u.Memory.Start.HighPart = BarArray[i + 1]; 73 } 74 else if ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_20BIT) 75 { 76 /* Legacy BAR, don't read more than 20 bits of the address */ 77 BarMask = 0xFFFF0; 78 } 79 } 80 } 81 else 82 { 83 /* Actually a ROM BAR, so read the correct register */ 84 Bar = PciData->u.type0.ROMBaseAddress; 85 86 /* Apply the correct mask for ROM BARs */ 87 BarMask = PCI_ADDRESS_ROM_ADDRESS_MASK; 88 89 /* Make sure it's enabled */ 90 if (!(Bar & PCI_ROMADDRESS_ENABLED)) 91 { 92 /* If it isn't, then a descriptor won't be built for it */ 93 CmDescriptor->Type = CmResourceTypeNull; 94 continue; 95 } 96 } 97 98 /* Now we have the right mask, read the actual address from the BAR */ 99 Bar &= BarMask; 100 CmDescriptor->u.Memory.Start.LowPart = Bar; 101 102 /* And check for invalid BAR addresses */ 103 if (!(CmDescriptor->u.Memory.Start.HighPart | Bar)) 104 { 105 /* Skip these descriptors */ 106 CmDescriptor->Type = CmResourceTypeNull; 107 DPRINT1("Invalid BAR\n"); 108 } 109 } 110 111 /* Also save the sub-IDs that came directly from the PCI header */ 112 Context->PdoExtension->SubsystemVendorId = PciData->u.type0.SubVendorID; 113 Context->PdoExtension->SubsystemId = PciData->u.type0.SubSystemID; 114 } 115 116 VOID 117 NTAPI 118 Device_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context) 119 { 120 PPCI_COMMON_HEADER Current, PciData; 121 PPCI_PDO_EXTENSION PdoExtension; 122 PULONG BarArray; 123 PIO_RESOURCE_DESCRIPTOR Limit; 124 ULONG i; 125 126 /* Get pointers from the context */ 127 PdoExtension = Context->PdoExtension; 128 Current = Context->Current; 129 PciData = Context->PciData; 130 131 /* And get the array of bARs */ 132 BarArray = PciData->u.type0.BaseAddresses; 133 134 /* First, check for IDE controllers that are not in native mode */ 135 if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) && 136 (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR) && 137 (PdoExtension->ProgIf & 5) != 5) 138 { 139 /* They should not be using any non-legacy resources */ 140 BarArray[0] = 0; 141 BarArray[1] = 0; 142 BarArray[2] = 0; 143 BarArray[3] = 0; 144 } 145 else if ((PdoExtension->VendorId == 0x5333) && 146 ((PdoExtension->DeviceId == 0x88F0) || 147 (PdoExtension->DeviceId == 0x8880))) 148 { 149 /* 150 * The problem is caused by the S3 Vision 968/868 video controller which 151 * is used on the Diamond Stealth 64 Video 3000 series, Number Nine 9FX 152 * motion 771, and other popular video cards, all containing a memory bug. 153 * The 968/868 claims to require 32 MB of memory, but it actually decodes 154 * 64 MB of memory. 155 */ 156 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) 157 { 158 /* Find its 32MB RAM BAR */ 159 if (BarArray[i] == 0xFE000000) 160 { 161 /* Increase it to 64MB to make sure nobody touches the buffer */ 162 BarArray[i] = 0xFC000000; 163 DPRINT1("PCI - Adjusted broken S3 requirement from 32MB to 64MB\n"); 164 } 165 } 166 } 167 168 /* Check for Cirrus Logic GD5430/5440 cards */ 169 if ((PdoExtension->VendorId == 0x1013) && (PdoExtension->DeviceId == 0xA0)) 170 { 171 /* Check for the I/O port requirement */ 172 if (BarArray[1] == 0xFC01) 173 { 174 /* Check for completely bogus BAR */ 175 if (Current->u.type0.BaseAddresses[1] == 1) 176 { 177 /* Ignore it */ 178 BarArray[1] = 0; 179 DPRINT1("PCI - Ignored Cirrus GD54xx broken IO requirement (400 ports)\n"); 180 } 181 else 182 { 183 /* Otherwise, this BAR seems okay */ 184 DPRINT1("PCI - Cirrus GD54xx 400 port IO requirement has a valid setting (%08x)\n", 185 Current->u.type0.BaseAddresses[1]); 186 } 187 } 188 else if (BarArray[1]) 189 { 190 /* Strange, the I/O BAR was not found as expected (or at all) */ 191 DPRINT1("PCI - Warning Cirrus Adapter 101300a0 has unexpected resource requirement (%08x)\n", 192 BarArray[1]); 193 } 194 } 195 196 /* Finally, process all the limit descriptors */ 197 Limit = PdoExtension->Resources->Limit; 198 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) 199 { 200 /* And build them based on the BARs */ 201 if (PciCreateIoDescriptorFromBarLimit(&Limit[i], &BarArray[i], FALSE)) 202 { 203 /* This function returns TRUE if the BAR was 64-bit, handle this */ 204 ASSERT((i + 1) < PCI_TYPE0_ADDRESSES); 205 i++; 206 Limit[i].Type = CmResourceTypeNull; 207 } 208 } 209 210 /* Create the last descriptor based on the ROM address */ 211 PciCreateIoDescriptorFromBarLimit(&Limit[i], 212 &PciData->u.type0.ROMBaseAddress, 213 TRUE); 214 } 215 216 VOID 217 NTAPI 218 Device_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context) 219 { 220 PPCI_COMMON_HEADER PciData; 221 PPCI_PDO_EXTENSION PdoExtension; 222 PULONG BarArray; 223 ULONG i = 0; 224 225 /* Get pointers from context data */ 226 PdoExtension = Context->PdoExtension; 227 PciData = Context->PciData; 228 229 /* Get the array of BARs */ 230 BarArray = PciData->u.type0.BaseAddresses; 231 232 /* Check for IDE controllers that are not in native mode */ 233 if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) && 234 (PdoExtension->SubClass == PCI_SUBCLASS_MSC_IDE_CTLR) && 235 (PdoExtension->ProgIf & 5) != 5) 236 { 237 /* These controllers only use legacy resources */ 238 i = 4; 239 } 240 241 /* Set all the bits on, which will allow us to recover the limit data */ 242 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) BarArray[i] = 0xFFFFFFFF; 243 244 /* Do the same for the PCI ROM BAR */ 245 PciData->u.type0.ROMBaseAddress = PCI_ADDRESS_ROM_ADDRESS_MASK; 246 } 247 248 VOID 249 NTAPI 250 Device_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context) 251 { 252 UNREFERENCED_PARAMETER(Context); 253 /* Nothing to do for devices */ 254 return; 255 } 256 257 VOID 258 NTAPI 259 Device_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context, 260 IN PPCI_COMMON_HEADER PciData, 261 IN PIO_RESOURCE_DESCRIPTOR IoDescriptor) 262 { 263 UNREFERENCED_PARAMETER(Context); 264 UNREFERENCED_PARAMETER(PciData); 265 UNREFERENCED_PARAMETER(IoDescriptor); 266 /* Not yet implemented */ 267 UNIMPLEMENTED_DBGBREAK(); 268 } 269 270 VOID 271 NTAPI 272 Device_ResetDevice(IN PPCI_PDO_EXTENSION PdoExtension, 273 IN PPCI_COMMON_HEADER PciData) 274 { 275 UNREFERENCED_PARAMETER(PdoExtension); 276 UNREFERENCED_PARAMETER(PciData); 277 /* Not yet implemented */ 278 UNIMPLEMENTED_DBGBREAK(); 279 } 280 281 VOID 282 NTAPI 283 Device_ChangeResourceSettings(IN PPCI_PDO_EXTENSION PdoExtension, 284 IN PPCI_COMMON_HEADER PciData) 285 { 286 UNREFERENCED_PARAMETER(PdoExtension); 287 UNREFERENCED_PARAMETER(PciData); 288 /* Not yet implemented */ 289 UNIMPLEMENTED_DBGBREAK(); 290 } 291 292 /* EOF */ 293