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