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
Device_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context)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
Device_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)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
Device_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context)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
Device_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context)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
Device_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context,IN PPCI_COMMON_HEADER PciData,IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)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
Device_ResetDevice(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER PciData)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
Device_ChangeResourceSettings(IN PPCI_PDO_EXTENSION PdoExtension,IN PPCI_COMMON_HEADER PciData)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