:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / hal / halx86 / pci.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/hal/x86/pci.c
6  * PURPOSE:         Interfaces to the PCI bus
7  * PROGRAMMER:      David Welch (welch@mcmail.com)
8  *                  Eric Kohl (ekohl@rz-online.de)
9  * UPDATE HISTORY:
10  *                  05/06/1998: Created
11  *                  17/08/2000: Added preliminary pci bus scanner
12  *                  13/06/2001: Implemented access to pci configuration space
13  */
14
15 /*
16  * NOTES: Sections copied from the Linux pci support
17  */
18
19 /* INCLUDES *****************************************************************/
20
21 #include <ddk/ntddk.h>
22 #include <bus.h>
23
24 #define NDEBUG
25 #include <internal/debug.h>
26
27
28 /* MACROS ******************************************************************/
29
30 /* access type 1 macros */
31 #define PCI_FUNC(devfn) \
32         ((devfn) & 0x07)
33 #define CONFIG_CMD(bus, device_fn, where) \
34         (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
35
36 /* access type 2 macros */
37 #define IOADDR(devfn, where) \
38         ((0xC000 | ((devfn & 0x78) << 5)) + where)
39 #define FUNC(devfn) \
40         (((devfn & 7) << 1) | 0xf0)
41
42
43 #define PCIBIOS_SUCCESSFUL              0x00
44 #define PCIBIOS_DEVICE_NOT_FOUND        0x86
45 #define PCIBIOS_BAD_REGISTER_NUMBER     0x87
46
47
48 /* GLOBALS ******************************************************************/
49
50 static ULONG BusConfigType = 0;  /* undetermined config type */
51
52
53 /* FUNCTIONS ****************************************************************/
54
55 static NTSTATUS
56 ReadPciConfigUchar(UCHAR Bus,
57                    UCHAR Slot,
58                    UCHAR Offset,
59                    PUCHAR Value)
60 {
61    switch (BusConfigType)
62      {
63      case 1:
64         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
65         *Value = READ_PORT_UCHAR((PUCHAR)0xCFC + (Offset & 3));
66         return STATUS_SUCCESS;
67
68      case 2:
69         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
70         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
71         *Value = READ_PORT_UCHAR((PUCHAR)(IOADDR(Slot, Offset)));
72         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
73         return STATUS_SUCCESS;
74      }
75    return STATUS_UNSUCCESSFUL;
76 }
77
78
79 static NTSTATUS
80 ReadPciConfigUshort(UCHAR Bus,
81                     UCHAR Slot,
82                     UCHAR Offset,
83                     PUSHORT Value)
84 {
85    if ((Offset & 1) != 0)
86      {
87         return PCIBIOS_BAD_REGISTER_NUMBER;
88      }
89
90    switch (BusConfigType)
91      {
92      case 1:
93         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
94         *Value = READ_PORT_USHORT((PUSHORT)0xCFC + (Offset & 1));
95         return STATUS_SUCCESS;
96
97      case 2:
98         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
99         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
100         *Value = READ_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)));
101         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
102         return STATUS_SUCCESS;
103      }
104    return STATUS_UNSUCCESSFUL;
105 }
106
107
108 static NTSTATUS
109 ReadPciConfigUlong(UCHAR Bus,
110                    UCHAR Slot,
111                    UCHAR Offset,
112                    PULONG Value)
113 {
114    if ((Offset & 3) != 0)
115      {
116         return PCIBIOS_BAD_REGISTER_NUMBER;
117      }
118
119    switch (BusConfigType)
120      {
121      case 1:
122         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
123         *Value = READ_PORT_ULONG((PULONG)0xCFC);
124         return STATUS_SUCCESS;
125
126      case 2:
127         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
128         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
129         *Value = READ_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)));
130         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
131         return STATUS_SUCCESS;
132      }
133    return STATUS_UNSUCCESSFUL;
134 }
135
136
137 static NTSTATUS
138 WritePciConfigUchar(UCHAR Bus,
139                     UCHAR Slot,
140                     UCHAR Offset,
141                     UCHAR Value)
142 {
143    switch (BusConfigType)
144      {
145      case 1:
146         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
147         WRITE_PORT_UCHAR((PUCHAR)0xCFC + (Offset&3), Value);
148         return STATUS_SUCCESS;
149
150      case 2:
151         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
152         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
153         WRITE_PORT_UCHAR((PUCHAR)(IOADDR(Slot,Offset)), Value);
154         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
155         return STATUS_SUCCESS;
156      }
157    return STATUS_UNSUCCESSFUL;
158 }
159
160
161 static NTSTATUS
162 WritePciConfigUshort(UCHAR Bus,
163                      UCHAR Slot,
164                      UCHAR Offset,
165                      USHORT Value)
166 {
167    if ((Offset & 1) != 0)
168      {
169         return PCIBIOS_BAD_REGISTER_NUMBER;
170      }
171
172    switch (BusConfigType)
173      {
174      case 1:
175         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
176         WRITE_PORT_USHORT((PUSHORT)0xCFC + (Offset & 1), Value);
177         return STATUS_SUCCESS;
178
179      case 2:
180         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
181         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
182         WRITE_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)), Value);
183         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
184         return STATUS_SUCCESS;
185      }
186    return STATUS_UNSUCCESSFUL;
187 }
188
189
190 static NTSTATUS
191 WritePciConfigUlong(UCHAR Bus,
192                     UCHAR Slot,
193                     UCHAR Offset,
194                     ULONG Value)
195 {
196    if ((Offset & 3) != 0)
197      {
198         return PCIBIOS_BAD_REGISTER_NUMBER;
199      }
200
201    switch (BusConfigType)
202      {
203      case 1:
204         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
205         WRITE_PORT_ULONG((PULONG)0xCFC, Value);
206         return STATUS_SUCCESS;
207
208      case 2:
209         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
210         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
211         WRITE_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)), Value);
212         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
213         return STATUS_SUCCESS;
214      }
215    return STATUS_UNSUCCESSFUL;
216 }
217
218
219 static ULONG STDCALL
220 HalpGetPciData(PBUS_HANDLER BusHandler,
221                ULONG BusNumber,
222                ULONG SlotNumber,
223                PVOID Buffer,
224                ULONG Offset,
225                ULONG Length)
226 {
227    PVOID Ptr = Buffer;
228    ULONG Address = Offset;
229    ULONG Len = Length;
230    ULONG Vendor;
231    UCHAR HeaderType;
232
233    DPRINT("HalpGetPciData() called.\n");
234    DPRINT("  BusNumber %lu\n", BusNumber);
235    DPRINT("  SlotNumber %lu\n", SlotNumber);
236    DPRINT("  Offset 0x%lx\n", Offset);
237    DPRINT("  Length 0x%lx\n", Length);
238
239    if ((Length == 0) || (BusConfigType == 0))
240      return 0;
241
242    /* 0E=PCI_HEADER_TYPE */
243    ReadPciConfigUchar(BusNumber,
244                       SlotNumber & 0xF8,
245                       0x0E,
246                       &HeaderType);
247    if (((HeaderType & 0x80) == 0) && ((SlotNumber & 0x07) != 0))
248      return 0;
249
250    ReadPciConfigUlong(BusNumber,
251                       SlotNumber,
252                       0x00,
253                       &Vendor);
254    /* some broken boards return 0 if a slot is empty: */
255    if (Vendor == 0xFFFFFFFF || Vendor == 0)
256      return 0;
257
258    if ((Address & 1) && (Len >= 1))
259      {
260         ReadPciConfigUchar(BusNumber,
261                            SlotNumber,
262                            Address,
263                            Ptr);
264         Ptr = Ptr + 1;
265         Address++;
266         Len--;
267      }
268
269    if ((Address & 2) && (Len >= 2))
270      {
271         ReadPciConfigUshort(BusNumber,
272                             SlotNumber,
273                             Address,
274                             Ptr);
275         Ptr = Ptr + 2;
276         Address += 2;
277         Len -= 2;
278      }
279
280    while (Len >= 4)
281      {
282         ReadPciConfigUlong(BusNumber,
283                            SlotNumber,
284                            Address,
285                            Ptr);
286         Ptr = Ptr + 4;
287         Address += 4;
288         Len -= 4;
289      }
290
291    if (Len >= 2)
292      {
293         ReadPciConfigUshort(BusNumber,
294                             SlotNumber,
295                             Address,
296                             Ptr);
297         Ptr = Ptr + 2;
298         Address += 2;
299         Len -= 2;
300      }
301
302    if (Len >= 1)
303      {
304         ReadPciConfigUchar(BusNumber,
305                            SlotNumber,
306                            Address,
307                            Ptr);
308         Ptr = Ptr + 1;
309         Address++;
310         Len--;
311      }
312
313    return Length - Len;
314 }
315
316
317 static ULONG STDCALL
318 HalpSetPciData(PBUS_HANDLER BusHandler,
319                ULONG BusNumber,
320                ULONG SlotNumber,
321                PVOID Buffer,
322                ULONG Offset,
323                ULONG Length)
324 {
325    PVOID Ptr = Buffer;
326    ULONG Address = Offset;
327    ULONG Len = Length;
328    ULONG Vendor;
329    UCHAR HeaderType;
330
331    DPRINT("HalpSetPciData() called.\n");
332    DPRINT("  BusNumber %lu\n", BusNumber);
333    DPRINT("  SlotNumber %lu\n", SlotNumber);
334    DPRINT("  Offset 0x%lx\n", Offset);
335    DPRINT("  Length 0x%lx\n", Length);
336
337    if ((Length == 0) || (BusConfigType == 0))
338      return 0;
339
340    /* 0E=PCI_HEADER_TYPE */
341    ReadPciConfigUchar(BusNumber,
342                       SlotNumber & 0xF8,
343                       0x0E,
344                       &HeaderType);
345    if (((HeaderType & 0x80) == 0) && ((SlotNumber & 0x07) != 0))
346      return 0;
347
348    ReadPciConfigUlong(BusNumber,
349                       SlotNumber,
350                       0x00,
351                       &Vendor);
352    /* some broken boards return 0 if a slot is empty: */
353    if (Vendor == 0xFFFFFFFF || Vendor == 0)
354      return 0;
355
356    if ((Address & 1) && (Len >= 1))
357      {
358         WritePciConfigUchar(BusNumber,
359                             SlotNumber,
360                             Address,
361                             *(PUCHAR)Ptr);
362         Ptr = Ptr + 1;
363         Address++;
364         Len--;
365      }
366
367    if ((Address & 2) && (Len >= 2))
368      {
369         WritePciConfigUshort(BusNumber,
370                              SlotNumber,
371                              Address,
372                              *(PUSHORT)Ptr);
373         Ptr = Ptr + 2;
374         Address += 2;
375         Len -= 2;
376      }
377
378    while (Len >= 4)
379      {
380         WritePciConfigUlong(BusNumber,
381                             SlotNumber,
382                             Address,
383                             *(PULONG)Ptr);
384         Ptr = Ptr + 4;
385         Address += 4;
386         Len -= 4;
387      }
388
389    if (Len >= 2)
390      {
391         WritePciConfigUshort(BusNumber,
392                              SlotNumber,
393                              Address,
394                              *(PUSHORT)Ptr);
395         Ptr = Ptr + 2;
396         Address += 2;
397         Len -= 2;
398      }
399
400    if (Len >= 1)
401      {
402         WritePciConfigUchar(BusNumber,
403                             SlotNumber,
404                             Address,
405                             *(PUCHAR)Ptr);
406         Ptr = Ptr + 1;
407         Address++;
408         Len--;
409      }
410
411    return Length - Len;
412 }
413
414
415 static ULONG
416 GetBusConfigType(VOID)
417 {
418    ULONG Value;
419
420    DPRINT("GetBusConfigType() called\n");
421
422    DPRINT("Checking configuration type 1:");
423    WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x01);
424    Value = READ_PORT_ULONG((PULONG)0xCF8);
425    WRITE_PORT_ULONG((PULONG)0xCF8, 0x80000000);
426    if (READ_PORT_ULONG((PULONG)0xCF8) == 0x80000000)
427      {
428         WRITE_PORT_ULONG((PULONG)0xCF8, Value);
429         DPRINT("  Success!\n");
430         return 1;
431      }
432    WRITE_PORT_ULONG((PULONG)0xCF8, Value);
433    DPRINT("  Unsuccessful!\n");
434
435    DPRINT("Checking configuration type 2:");
436    WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x00);
437    WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0x00);
438    WRITE_PORT_UCHAR((PUCHAR)0xCFA, 0x00);
439    if (READ_PORT_UCHAR((PUCHAR)0xCF8) == 0x00 &&
440        READ_PORT_UCHAR((PUCHAR)0xCFB) == 0x00)
441      {
442         DPRINT("  Success!\n");
443         return 2;
444      }
445    DPRINT("  Unsuccessful!\n");
446
447    DPRINT("No pci bus found!\n");
448    return 0;
449 }
450
451
452 static ULONG STDCALL
453 HalpGetPciInterruptVector(PVOID BusHandler,
454                           ULONG BusNumber,
455                           ULONG BusInterruptLevel,
456                           ULONG BusInterruptVector,
457                           PKIRQL Irql,
458                           PKAFFINITY Affinity)
459 {
460   *Irql = HIGH_LEVEL - BusInterruptVector;
461   *Affinity = 0xFFFFFFFF;
462   return BusInterruptVector;
463 }
464
465
466 VOID
467 HalpInitPciBus(VOID)
468 {
469   PBUS_HANDLER BusHandler;
470
471   DPRINT("HalpInitPciBus() called.\n");
472
473   BusConfigType = GetBusConfigType();
474   if (BusConfigType == 0)
475     return;
476
477   DPRINT("Bus configuration %lu used\n", BusConfigType);
478
479   /* pci bus (bus 0) handler */
480   BusHandler = HalpAllocateBusHandler(PCIBus,
481                                       PCIConfiguration,
482                                       0);
483   BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData;
484   BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData;
485   BusHandler->GetInterruptVector =
486     (pGetInterruptVector)HalpGetPciInterruptVector;
487 //      BusHandler->AdjustResourceList =
488 //              (pGetSetBusData)HalpAdjustPciResourceList;
489 //      BusHandler->AssignSlotResources =
490 //              (pGetSetBusData)HalpAssignPciSlotResources;
491
492
493   /* agp bus (bus 1) handler */
494   BusHandler = HalpAllocateBusHandler(PCIBus,
495                                       PCIConfiguration,
496                                       1);
497   BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData;
498   BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData;
499   BusHandler->GetInterruptVector =
500     (pGetInterruptVector)HalpGetPciInterruptVector;
501 //      BusHandler->AdjustResourceList =
502 //              (pGetSetBusData)HalpAdjustPciResourceList;
503 //      BusHandler->AssignSlotResources =
504 //              (pGetSetBusData)HalpAssignPciSlotResources;
505
506   DPRINT("HalpInitPciBus() finished.\n");
507 }
508
509 /* EOF */