ReactOS 0.4.17-dev-1190-g4c812f4
device.c
Go to the documentation of this file.
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
18VOID
21{
22 PPCI_COMMON_HEADER PciData;
23 PIO_RESOURCE_DESCRIPTOR IoDescriptor;
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 */
51 {
52 /* Read the actual BAR value */
53 Bar = BarArray[i];
54
55 /* Check if this is an I/O BAR */
57 {
58 /* Use the right mask to get the I/O port base address */
59 ASSERT(CmDescriptor->Type == CmResourceTypePort);
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 (CmDescriptor->Type == CmResourceTypeMemoryLarge));
68
69 /* Check if it's a 64-bit BAR, the last BAR has no register for a high half */
71 ((i + 1) < PCI_TYPE0_ADDRESSES))
72 {
73 /* The next BAR value is actually the high 32-bits */
74 CmDescriptor->u.Memory.Start.HighPart = BarArray[i + 1];
75 }
77 {
78 /* Legacy BAR, don't read more than 20 bits of the address */
79 BarMask = 0xFFFF0;
80 }
81 }
82 }
83 else
84 {
85 /* Actually a ROM BAR, so read the correct register */
86 Bar = PciData->u.type0.ROMBaseAddress;
87
88 /* Apply the correct mask for ROM BARs */
90
91 /* Make sure it's enabled */
93 {
94 /* If it isn't, then a descriptor won't be built for it */
95 CmDescriptor->Type = CmResourceTypeNull;
96 continue;
97 }
98 }
99
100 /* Now we have the right mask, read the actual address from the BAR */
101 Bar &= BarMask;
102 CmDescriptor->u.Memory.Start.LowPart = Bar;
103
104 /* And check for invalid BAR addresses */
105 if (!(CmDescriptor->u.Memory.Start.HighPart | Bar))
106 {
107 /* Skip these descriptors */
108 CmDescriptor->Type = CmResourceTypeNull;
109 DPRINT1("PCIX - Invalid BAR\n");
110 }
111 }
112
113 /* Also save the sub-IDs that came directly from the PCI header */
114 Context->PdoExtension->SubsystemVendorId = PciData->u.type0.SubVendorID;
115 Context->PdoExtension->SubsystemId = PciData->u.type0.SubSystemID;
116}
117
118VOID
119NTAPI
121{
122 PPCI_COMMON_HEADER Current, PciData;
124 PULONG BarArray;
126 ULONG i;
127
128 /* Get pointers from the context */
129 PdoExtension = Context->PdoExtension;
130 Current = Context->Current;
131 PciData = Context->PciData;
132
133 /* And get the array of bARs */
134 BarArray = PciData->u.type0.BaseAddresses;
135
136 /* First, check for IDE controllers that are not in native mode */
137 if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
139 (PdoExtension->ProgIf & 5) != 5)
140 {
141 /* They should not be using any non-legacy resources */
142 BarArray[0] = 0;
143 BarArray[1] = 0;
144 BarArray[2] = 0;
145 BarArray[3] = 0;
146 }
147 else if ((PdoExtension->VendorId == 0x5333) &&
148 ((PdoExtension->DeviceId == 0x88F0) ||
149 (PdoExtension->DeviceId == 0x8880)))
150 {
151 /*
152 * The problem is caused by the S3 Vision 968/868 video controller which
153 * is used on the Diamond Stealth 64 Video 3000 series, Number Nine 9FX
154 * motion 771, and other popular video cards, all containing a memory bug.
155 * The 968/868 claims to require 32 MB of memory, but it actually decodes
156 * 64 MB of memory.
157 */
158 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
159 {
160 /* Find its 32MB RAM BAR */
161 if (BarArray[i] == 0xFE000000)
162 {
163 /* Increase it to 64MB to make sure nobody touches the buffer */
164 BarArray[i] = 0xFC000000;
165 DPRINT1("PCIX - Adjusted broken S3 requirement from 32MB to 64MB\n");
166 }
167 }
168 }
169
170 /* Check for Cirrus Logic GD5430/5440 cards */
171 if ((PdoExtension->VendorId == 0x1013) && (PdoExtension->DeviceId == 0xA0))
172 {
173 /* Check for the I/O port requirement */
174 if (BarArray[1] == 0xFC01)
175 {
176 /* Check for completely bogus BAR */
177 if (Current->u.type0.BaseAddresses[1] == 1)
178 {
179 /* Ignore it */
180 BarArray[1] = 0;
181 DPRINT1("PCIX - Ignored Cirrus GD54xx broken IO requirement (400 ports)\n");
182 }
183 else
184 {
185 /* Otherwise, this BAR seems okay */
186 DPRINT1("PCIX - Cirrus GD54xx 400 port IO requirement has a valid setting (%08x)\n",
187 Current->u.type0.BaseAddresses[1]);
188 }
189 }
190 else if (BarArray[1])
191 {
192 /* Strange, the I/O BAR was not found as expected (or at all) */
193 DPRINT1("PCIX - Warning Cirrus Adapter 101300a0 has unexpected resource requirement (%08x)\n",
194 BarArray[1]);
195 }
196 }
197
198 /* Finally, process all the limit descriptors */
199 Limit = PdoExtension->Resources->Limit;
200 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
201 {
202 /* And build them based on the BARs, the last one has no BAR after it for a high half */
203 ULONG NextBar = ((i + 1) < PCI_TYPE0_ADDRESSES) ? BarArray[i + 1] : 0;
204
205 if (!PciCreateIoDescriptorFromBarLimit(&Limit[i], BarArray[i], NextBar, FALSE))
206 continue;
207
208 /* A 64-bit BAR in the last slot has nowhere to put its high half, so it stays below 4GB */
209 if ((i + 1) == PCI_TYPE0_ADDRESSES)
210 {
211 DPRINT1("PCIX - 64-bit BAR %lu has no upper register, decoding it as 32-bit\n", i);
212 continue;
213 }
214
215 /* The high half of a 64-bit BAR is not a BAR of its own */
216 i++;
217 Limit[i].Type = CmResourceTypeNull;
218 }
219
220 /* Create the last descriptor based on the ROM address */
221 PciCreateIoDescriptorFromBarLimit(&Limit[i], PciData->u.type0.ROMBaseAddress, 0, TRUE);
222
223 /* A ROM the firmware left disabled is not given a window */
224 if (!(Current->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED))
225 Limit[i].Type = CmResourceTypeNull;
226}
227
228VOID
229NTAPI
231{
232 PPCI_COMMON_HEADER PciData;
234 PULONG BarArray;
235 ULONG i = 0;
236
237 /* Get pointers from context data */
238 PdoExtension = Context->PdoExtension;
239 PciData = Context->PciData;
240
241 /* Get the array of BARs */
242 BarArray = PciData->u.type0.BaseAddresses;
243
244 /* Check for IDE controllers that are not in native mode */
245 if ((PdoExtension->BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
247 (PdoExtension->ProgIf & 5) != 5)
248 {
249 /* These controllers only use legacy resources */
250 i = 4;
251 }
252
253 /* Set all the bits on, which will allow us to recover the limit data */
254 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) BarArray[i] = 0xFFFFFFFF;
255
256 /* Do the same for the PCI ROM BAR */
257 PciData->u.type0.ROMBaseAddress = PCI_ADDRESS_ROM_ADDRESS_MASK;
258}
259
260VOID
261NTAPI
263{
265 /* Nothing to do for devices */
266 return;
267}
268
269VOID
270NTAPI
272 IN PPCI_COMMON_HEADER PciData,
273 IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)
274{
276 UNREFERENCED_PARAMETER(PciData);
277 UNREFERENCED_PARAMETER(IoDescriptor);
278
279 /* A device decodes nothing beyond its BARs, only bridges add ranges here */
280}
281
282VOID
283NTAPI
285 IN PPCI_COMMON_HEADER PciData)
286{
288 UNREFERENCED_PARAMETER(PciData);
289
290 /* Nothing to undo, the caller writes the whole header back */
291}
292
307NTAPI
311{
315 PULONG BarArray;
316 ULONG Bar, BarMask, i;
317 USHORT Decode;
318 BOOLEAN IsVga, HasUpperHalf;
319
320 Resources = PdoExtension->Resources;
321 if (!Resources)
322 return STATUS_SUCCESS;
323
324 /* VGA decodes are forced on at start, so a BAR it was not given may stay empty */
325 IsVga = ((PdoExtension->BaseClass == PCI_CLASS_PRE_20) &&
326 (PdoExtension->SubClass == PCI_SUBCLASS_PRE_20_VGA)) ||
327 ((PdoExtension->BaseClass == PCI_CLASS_DISPLAY_CTLR) &&
329
330 BarArray = PciData->u.type0.BaseAddresses;
331 for (i = 0; i < PCI_TYPE0_ADDRESSES; i++)
332 {
333 Limit = &Resources->Limit[i];
334 CmDescriptor = &Resources->Current[i];
335
336 if (CmDescriptor->Type == CmResourceTypeNull)
337 {
338 /* A requested BAR left without a range must not decode while its space is on */
339 Decode = (Limit->Type == CmResourceTypePort) ? PCI_ENABLE_IO_SPACE :
342 (PdoExtension->CommandEnables & Decode) &&
343 !IsVga)
344 {
345 DPRINT1("PCIX - pdox %p BAR %lu has no range but its decode stays on\n",
347 i);
349 }
350
351 BarArray[i] = 0;
352 continue;
353 }
354
355 /* The limit says what the BAR decodes, its read-only low bits say how wide it is */
356 Bar = BarArray[i];
357 HasUpperHalf = FALSE;
358 if (Limit->Type == CmResourceTypePort)
359 {
361 }
363 {
364 BarMask = 0xFFFF0;
365 }
366 else
367 {
369 HasUpperHalf = ((Bar & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT) &&
370 ((i + 1) < PCI_TYPE0_ADDRESSES);
371 }
372
373 if (!HasUpperHalf && CmDescriptor->u.Generic.Start.HighPart)
374 {
375 DPRINT1("PCIX - pdox %p BAR %lu cannot hold address %I64x\n",
377 i,
378 CmDescriptor->u.Generic.Start.QuadPart);
380 }
381
382 BarArray[i] = (Bar & ~BarMask) | (CmDescriptor->u.Generic.Start.LowPart & BarMask);
383 if (HasUpperHalf)
384 {
385 i++;
386 BarArray[i] = CmDescriptor->u.Generic.Start.HighPart;
387 }
388 }
389
390 /* The ROM decodes only while its enable bit is set, and reads zero when it has no range */
391 CmDescriptor = &Resources->Current[PCI_TYPE0_ADDRESSES];
392 if (CmDescriptor->Type == CmResourceTypeNull)
393 {
394 PciData->u.type0.ROMBaseAddress = 0;
395 }
396 else
397 {
398 Bar = PciData->u.type0.ROMBaseAddress & ~PCI_ADDRESS_ROM_ADDRESS_MASK;
399 PciData->u.type0.ROMBaseAddress = Bar |
400 (CmDescriptor->u.Generic.Start.LowPart &
403 }
404
405 return STATUS_SUCCESS;
406}
407
408/* EOF */
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
VOID NTAPI Device_GetAdditionalResourceDescriptors(IN PPCI_CONFIGURATOR_CONTEXT Context, IN PPCI_COMMON_HEADER PciData, IN PIO_RESOURCE_DESCRIPTOR IoDescriptor)
Definition: device.c:271
VOID NTAPI Device_SaveLimits(IN PPCI_CONFIGURATOR_CONTEXT Context)
Definition: device.c:120
NTSTATUS NTAPI Device_ChangeResourceSettings(_In_ PPCI_PDO_EXTENSION PdoExtension, _Inout_ PPCI_COMMON_HEADER PciData)
Puts the ranges assigned to a function into its BARs and ROM BAR.
Definition: device.c:308
VOID NTAPI Device_MassageHeaderForLimitsDetermination(IN PPCI_CONFIGURATOR_CONTEXT Context)
Definition: device.c:230
VOID NTAPI Device_SaveCurrentSettings(IN PPCI_CONFIGURATOR_CONTEXT Context)
Definition: device.c:20
VOID NTAPI Device_ResetDevice(IN PPCI_PDO_EXTENSION PdoExtension, IN PPCI_COMMON_HEADER PciData)
Definition: device.c:284
VOID NTAPI Device_RestoreCurrent(IN PPCI_CONFIGURATOR_CONTEXT Context)
Definition: device.c:262
BOOLEAN NTAPI PciIsRequirementDescriptor(_In_ PIO_RESOURCE_DESCRIPTOR Limit)
Tells whether a discovered limit asks the arbiter for a range.
Definition: enum.c:671
BOOLEAN NTAPI PciCreateIoDescriptorFromBarLimit(_Out_ PIO_RESOURCE_DESCRIPTOR ResourceDescriptor, _In_ ULONG Bar, _In_ ULONG NextBar, _In_ BOOLEAN Rom)
Builds the requirement of a BAR from the value it reads back after all ones were written to it.
Definition: utils.c:1252
@ PdoExtension
Definition: precomp.h:61
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_In_ PIRP _In_ PIO_COMPLETION_ROUTINE _In_ PVOID Context
Definition: kse.h:81
#define ASSERT(a)
Definition: mode.c:44
void Bar(void)
Definition: terminate.cpp:70
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
unsigned short USHORT
Definition: pedump.c:61
#define CmResourceTypeNull
Definition: restypes.h:103
#define CmResourceTypeMemory
Definition: restypes.h:106
#define CmResourceTypePort
Definition: restypes.h:104
#define STATUS_SUCCESS
Definition: shellext.h:65
union _CM_PARTIAL_RESOURCE_DESCRIPTOR::@494 u
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@494::@499 Memory
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@494::@495 Generic
struct _IO_RESOURCE_DESCRIPTOR::@2498::@2503 Generic
union _IO_RESOURCE_DESCRIPTOR::@2498 u
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define CmResourceTypeMemoryLarge
Definition: cmtypes.h:231
#define PCI_TYPE_64BIT
Definition: iotypes.h:4255
#define PCI_ADDRESS_IO_ADDRESS_MASK
Definition: iotypes.h:4249
#define PCI_TYPE0_ADDRESSES
Definition: iotypes.h:3515
#define PCI_ENABLE_IO_SPACE
Definition: iotypes.h:3631
#define PCI_CLASS_MASS_STORAGE_CTLR
Definition: iotypes.h:4119
#define PCI_ADDRESS_IO_SPACE
Definition: iotypes.h:4246
#define PCI_SUBCLASS_MSC_IDE_CTLR
Definition: iotypes.h:4144
#define PCI_ENABLE_MEMORY_SPACE
Definition: iotypes.h:3632
#define PCI_TYPE_20BIT
Definition: iotypes.h:4254
#define PCI_ADDRESS_ROM_ADDRESS_MASK
Definition: iotypes.h:4251
#define PCI_ADDRESS_MEMORY_ADDRESS_MASK
Definition: iotypes.h:4250
#define PCI_CLASS_PRE_20
Definition: iotypes.h:4118
#define PCI_ROMADDRESS_ENABLED
Definition: iotypes.h:4257
#define PCI_SUBCLASS_VID_VGA_CTLR
Definition: iotypes.h:4160
#define PCI_ADDRESS_MEMORY_TYPE_MASK
Definition: iotypes.h:4247
#define PCI_SUBCLASS_PRE_20_VGA
Definition: iotypes.h:4140
#define PCI_CLASS_DISPLAY_CTLR
Definition: iotypes.h:4121
_In_ LONG _In_ LONG Limit
Definition: kefuncs.h:304