+ntoskrnl/ke/mutex.c
[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 CONFIG_CMD(bus, dev_fn, where) \
32         (0x80000000 | (((ULONG)(bus)) << 16) | (((dev_fn) & 0x1F) << 11) | (((dev_fn) & 0xE0) << 3) | ((where) & ~3))
33
34 /* access type 2 macros */
35 #define IOADDR(dev_fn, where) \
36         (0xC000 | (((dev_fn) & 0x1F) << 8) | (where))
37 #define FUNC(dev_fn) \
38         ((((dev_fn) & 0xE0) >> 4) | 0xf0)
39
40
41 /* GLOBALS ******************************************************************/
42
43 static ULONG BusConfigType = 0;  /* undetermined config type */
44 static KSPIN_LOCK PciLock;
45
46 /* FUNCTIONS ****************************************************************/
47
48 static NTSTATUS
49 ReadPciConfigUchar(UCHAR Bus,
50                    UCHAR Slot,
51                    UCHAR Offset,
52                    PUCHAR Value)
53 {
54    KIRQL oldIrql;
55
56    switch (BusConfigType)
57      {
58      case 1:
59         KeAcquireSpinLock(&PciLock, &oldIrql);
60         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
61         *Value = READ_PORT_UCHAR((PUCHAR)0xCFC + (Offset & 3));
62         KeReleaseSpinLock(&PciLock, oldIrql);
63         return STATUS_SUCCESS;
64
65      case 2:
66         KeAcquireSpinLock(&PciLock, &oldIrql);
67         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
68         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
69         *Value = READ_PORT_UCHAR((PUCHAR)(IOADDR(Slot, Offset)));
70         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
71         KeReleaseSpinLock(&PciLock, oldIrql);
72         return STATUS_SUCCESS;
73      }
74    return STATUS_UNSUCCESSFUL;
75 }
76
77
78 static NTSTATUS
79 ReadPciConfigUshort(UCHAR Bus,
80                     UCHAR Slot,
81                     UCHAR Offset,
82                     PUSHORT Value)
83 {
84    KIRQL oldIrql;
85
86    if ((Offset & 1) != 0)
87      {
88         return STATUS_INVALID_PARAMETER;
89      }
90
91    switch (BusConfigType)
92      {
93      case 1:
94         KeAcquireSpinLock(&PciLock, &oldIrql);
95         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
96         *Value = READ_PORT_USHORT((PUSHORT)0xCFC + (Offset & 1));
97         KeReleaseSpinLock(&PciLock, oldIrql);
98         return STATUS_SUCCESS;
99
100      case 2:
101         KeAcquireSpinLock(&PciLock, &oldIrql);
102         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
103         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
104         *Value = READ_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)));
105         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
106         KeReleaseSpinLock(&PciLock, oldIrql);
107         return STATUS_SUCCESS;
108      }
109    return STATUS_UNSUCCESSFUL;
110 }
111
112
113 static NTSTATUS
114 ReadPciConfigUlong(UCHAR Bus,
115                    UCHAR Slot,
116                    UCHAR Offset,
117                    PULONG Value)
118 {
119    KIRQL oldIrql;
120
121    if ((Offset & 3) != 0)
122      {
123         return STATUS_INVALID_PARAMETER;
124      }
125
126    switch (BusConfigType)
127      {
128      case 1:
129         KeAcquireSpinLock(&PciLock, &oldIrql);
130         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
131         *Value = READ_PORT_ULONG((PULONG)0xCFC);
132         KeReleaseSpinLock(&PciLock, oldIrql);
133         return STATUS_SUCCESS;
134
135      case 2:
136         KeAcquireSpinLock(&PciLock, &oldIrql);
137         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
138         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
139         *Value = READ_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)));
140         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
141         KeReleaseSpinLock(&PciLock, oldIrql);
142         return STATUS_SUCCESS;
143      }
144    return STATUS_UNSUCCESSFUL;
145 }
146
147
148 static NTSTATUS
149 WritePciConfigUchar(UCHAR Bus,
150                     UCHAR Slot,
151                     UCHAR Offset,
152                     UCHAR Value)
153 {
154    KIRQL oldIrql;
155
156    switch (BusConfigType)
157      {
158      case 1:
159         KeAcquireSpinLock(&PciLock, &oldIrql);
160         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
161         WRITE_PORT_UCHAR((PUCHAR)0xCFC + (Offset&3), Value);
162         KeReleaseSpinLock(&PciLock, oldIrql);
163         return STATUS_SUCCESS;
164
165      case 2:
166         KeAcquireSpinLock(&PciLock, &oldIrql);
167         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
168         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
169         WRITE_PORT_UCHAR((PUCHAR)(IOADDR(Slot,Offset)), Value);
170         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
171         KeReleaseSpinLock(&PciLock, oldIrql);
172         return STATUS_SUCCESS;
173      }
174    return STATUS_UNSUCCESSFUL;
175 }
176
177
178 static NTSTATUS
179 WritePciConfigUshort(UCHAR Bus,
180                      UCHAR Slot,
181                      UCHAR Offset,
182                      USHORT Value)
183 {
184    KIRQL oldIrql;
185
186    if ((Offset & 1) != 0)
187      {
188         return  STATUS_INVALID_PARAMETER;
189      }
190
191    switch (BusConfigType)
192      {
193      case 1:
194         KeAcquireSpinLock(&PciLock, &oldIrql);
195         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
196         WRITE_PORT_USHORT((PUSHORT)0xCFC + (Offset & 1), Value);
197         KeReleaseSpinLock(&PciLock, oldIrql);
198         return STATUS_SUCCESS;
199
200      case 2:
201         KeAcquireSpinLock(&PciLock, &oldIrql);
202         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
203         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
204         WRITE_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)), Value);
205         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
206         KeReleaseSpinLock(&PciLock, oldIrql);
207         return STATUS_SUCCESS;
208      }
209    return STATUS_UNSUCCESSFUL;
210 }
211
212
213 static NTSTATUS
214 WritePciConfigUlong(UCHAR Bus,
215                     UCHAR Slot,
216                     UCHAR Offset,
217                     ULONG Value)
218 {
219    KIRQL oldIrql;
220
221    if ((Offset & 3) != 0)
222      {
223         return  STATUS_INVALID_PARAMETER;
224      }
225
226    switch (BusConfigType)
227      {
228      case 1:
229         KeAcquireSpinLock(&PciLock, &oldIrql);
230         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
231         WRITE_PORT_ULONG((PULONG)0xCFC, Value);
232         KeReleaseSpinLock(&PciLock, oldIrql);
233         return STATUS_SUCCESS;
234
235      case 2:
236         KeAcquireSpinLock(&PciLock, &oldIrql);
237         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
238         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
239         WRITE_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)), Value);
240         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
241         KeReleaseSpinLock(&PciLock, oldIrql);
242         return STATUS_SUCCESS;
243      }
244    return STATUS_UNSUCCESSFUL;
245 }
246
247
248 static ULONG STDCALL
249 HalpGetPciData(PBUS_HANDLER BusHandler,
250                ULONG BusNumber,
251                ULONG SlotNumber,
252                PVOID Buffer,
253                ULONG Offset,
254                ULONG Length)
255 {
256    PVOID Ptr = Buffer;
257    ULONG Address = Offset;
258    ULONG Len = Length;
259    ULONG Vendor;
260    UCHAR HeaderType;
261
262    DPRINT("HalpGetPciData() called.\n");
263    DPRINT("  BusNumber %lu\n", BusNumber);
264    DPRINT("  SlotNumber %lu\n", SlotNumber);
265    DPRINT("  Offset 0x%lx\n", Offset);
266    DPRINT("  Length 0x%lx\n", Length);
267
268    if ((Length == 0) || (BusConfigType == 0))
269      return 0;
270
271    ReadPciConfigUlong(BusNumber,
272                       SlotNumber & 0x1F,
273                       0x00,
274                       &Vendor);
275    /* some broken boards return 0 if a slot is empty: */
276    if (Vendor == 0xFFFFFFFF || Vendor == 0)
277    {
278      if (BusNumber == 0 && Offset == 0 && Length >= 2)
279      {
280         *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
281         return 2;
282      }
283      return 0;
284    }
285
286    /* 0E=PCI_HEADER_TYPE */
287    ReadPciConfigUchar(BusNumber,
288                       SlotNumber & 0x1F,
289                       0x0E,
290                       &HeaderType);
291    if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0))
292    {
293      if (Offset == 0 && Length >= 2)
294      {
295         *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
296         return 2;
297      }
298      return 0;
299    }
300    ReadPciConfigUlong(BusNumber,
301                       SlotNumber,
302                       0x00,
303                       &Vendor);
304    /* some broken boards return 0 if a slot is empty: */
305    if (Vendor == 0xFFFFFFFF || Vendor == 0)
306    {
307      if (BusNumber == 0 && Offset == 0 && Length >= 2)
308      {
309         *(PUSHORT)Buffer = PCI_INVALID_VENDORID;
310         return 2;
311      }
312      return 0;
313    }
314
315    if ((Address & 1) && (Len >= 1))
316      {
317         ReadPciConfigUchar(BusNumber,
318                            SlotNumber,
319                            Address,
320                            Ptr);
321         Ptr = Ptr + 1;
322         Address++;
323         Len--;
324      }
325
326    if ((Address & 2) && (Len >= 2))
327      {
328         ReadPciConfigUshort(BusNumber,
329                             SlotNumber,
330                             Address,
331                             Ptr);
332         Ptr = Ptr + 2;
333         Address += 2;
334         Len -= 2;
335      }
336
337    while (Len >= 4)
338      {
339         ReadPciConfigUlong(BusNumber,
340                            SlotNumber,
341                            Address,
342                            Ptr);
343         Ptr = Ptr + 4;
344         Address += 4;
345         Len -= 4;
346      }
347
348    if (Len >= 2)
349      {
350         ReadPciConfigUshort(BusNumber,
351                             SlotNumber,
352                             Address,
353                             Ptr);
354         Ptr = Ptr + 2;
355         Address += 2;
356         Len -= 2;
357      }
358
359    if (Len >= 1)
360      {
361         ReadPciConfigUchar(BusNumber,
362                            SlotNumber,
363                            Address,
364                            Ptr);
365         Ptr = Ptr + 1;
366         Address++;
367         Len--;
368      }
369
370    return Length - Len;
371 }
372
373
374 static ULONG STDCALL
375 HalpSetPciData(PBUS_HANDLER BusHandler,
376                ULONG BusNumber,
377                ULONG SlotNumber,
378                PVOID Buffer,
379                ULONG Offset,
380                ULONG Length)
381 {
382    PVOID Ptr = Buffer;
383    ULONG Address = Offset;
384    ULONG Len = Length;
385    ULONG Vendor;
386    UCHAR HeaderType;
387
388    DPRINT("HalpSetPciData() called.\n");
389    DPRINT("  BusNumber %lu\n", BusNumber);
390    DPRINT("  SlotNumber %lu\n", SlotNumber);
391    DPRINT("  Offset 0x%lx\n", Offset);
392    DPRINT("  Length 0x%lx\n", Length);
393
394    if ((Length == 0) || (BusConfigType == 0))
395      return 0;
396
397    ReadPciConfigUlong(BusNumber,
398                       SlotNumber & 0x1F,
399                       0x00,
400                       &Vendor);
401    /* some broken boards return 0 if a slot is empty: */
402    if (Vendor == 0xFFFFFFFF || Vendor == 0)
403      return 0;
404
405
406    /* 0E=PCI_HEADER_TYPE */
407    ReadPciConfigUchar(BusNumber,
408                       SlotNumber & 0x1F,
409                       0x0E,
410                       &HeaderType);
411    if (((HeaderType & PCI_MULTIFUNCTION) == 0) && ((SlotNumber & 0xE0) != 0))
412      return 0;
413
414    ReadPciConfigUlong(BusNumber,
415                       SlotNumber,
416                       0x00,
417                       &Vendor);
418    /* some broken boards return 0 if a slot is empty: */
419    if (Vendor == 0xFFFFFFFF || Vendor == 0)
420      return 0;
421
422    if ((Address & 1) && (Len >= 1))
423      {
424         WritePciConfigUchar(BusNumber,
425                             SlotNumber,
426                             Address,
427                             *(PUCHAR)Ptr);
428         Ptr = Ptr + 1;
429         Address++;
430         Len--;
431      }
432
433    if ((Address & 2) && (Len >= 2))
434      {
435         WritePciConfigUshort(BusNumber,
436                              SlotNumber,
437                              Address,
438                              *(PUSHORT)Ptr);
439         Ptr = Ptr + 2;
440         Address += 2;
441         Len -= 2;
442      }
443
444    while (Len >= 4)
445      {
446         WritePciConfigUlong(BusNumber,
447                             SlotNumber,
448                             Address,
449                             *(PULONG)Ptr);
450         Ptr = Ptr + 4;
451         Address += 4;
452         Len -= 4;
453      }
454
455    if (Len >= 2)
456      {
457         WritePciConfigUshort(BusNumber,
458                              SlotNumber,
459                              Address,
460                              *(PUSHORT)Ptr);
461         Ptr = Ptr + 2;
462         Address += 2;
463         Len -= 2;
464      }
465
466    if (Len >= 1)
467      {
468         WritePciConfigUchar(BusNumber,
469                             SlotNumber,
470                             Address,
471                             *(PUCHAR)Ptr);
472         Ptr = Ptr + 1;
473         Address++;
474         Len--;
475      }
476
477    return Length - Len;
478 }
479
480
481 static ULONG
482 GetBusConfigType(VOID)
483 {
484    ULONG Value;
485    KIRQL oldIrql;
486
487    DPRINT("GetBusConfigType() called\n");
488
489    KeAcquireSpinLock(&PciLock, &oldIrql);
490  
491    DPRINT("Checking configuration type 1:");
492    WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x01);
493    Value = READ_PORT_ULONG((PULONG)0xCF8);
494    WRITE_PORT_ULONG((PULONG)0xCF8, 0x80000000);
495    if (READ_PORT_ULONG((PULONG)0xCF8) == 0x80000000)
496      {
497         WRITE_PORT_ULONG((PULONG)0xCF8, Value);
498         KeReleaseSpinLock(&PciLock, oldIrql);
499         DPRINT("  Success!\n");
500         return 1;
501      }
502    WRITE_PORT_ULONG((PULONG)0xCF8, Value);
503    DPRINT("  Unsuccessful!\n");
504
505    DPRINT("Checking configuration type 2:");
506    WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x00);
507    WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0x00);
508    WRITE_PORT_UCHAR((PUCHAR)0xCFA, 0x00);
509    if (READ_PORT_UCHAR((PUCHAR)0xCF8) == 0x00 &&
510        READ_PORT_UCHAR((PUCHAR)0xCFB) == 0x00)
511      {
512         KeReleaseSpinLock(&PciLock, oldIrql);
513         DPRINT("  Success!\n");
514         return 2;
515      }
516    KeReleaseSpinLock(&PciLock, oldIrql);
517    DPRINT("  Unsuccessful!\n");
518
519    DPRINT("No pci bus found!\n");
520    return 0;
521 }
522
523
524 static ULONG STDCALL
525 HalpGetPciInterruptVector(PVOID BusHandler,
526                           ULONG BusNumber,
527                           ULONG BusInterruptLevel,
528                           ULONG BusInterruptVector,
529                           PKIRQL Irql,
530                           PKAFFINITY Affinity)
531 {
532   *Irql = PROFILE_LEVEL - BusInterruptVector;
533   *Affinity = 0xFFFFFFFF;
534   return BusInterruptVector;
535 }
536
537 static BOOLEAN STDCALL
538 HalpTranslatePciAddress(PBUS_HANDLER BusHandler,
539                         ULONG BusNumber,
540                         PHYSICAL_ADDRESS BusAddress,
541                         PULONG AddressSpace,
542                         PPHYSICAL_ADDRESS TranslatedAddress)
543 {
544    if (*AddressSpace == 0)
545      {
546         /* memory space */
547
548      }
549    else if (*AddressSpace == 1)
550      {
551         /* io space */
552
553      }
554    else
555      {
556         /* other */
557         return FALSE;
558      }
559
560    TranslatedAddress->QuadPart = BusAddress.QuadPart;
561
562    return TRUE;
563 }
564
565
566 VOID
567 HalpInitPciBus(VOID)
568 {
569   PBUS_HANDLER BusHandler;
570
571   DPRINT("HalpInitPciBus() called.\n");
572
573   KeInitializeSpinLock (&PciLock);
574
575   BusConfigType = GetBusConfigType();
576   if (BusConfigType == 0)
577     return;
578
579   DPRINT("Bus configuration %lu used\n", BusConfigType);
580
581   /* pci bus (bus 0) handler */
582   BusHandler = HalpAllocateBusHandler(PCIBus,
583                                       PCIConfiguration,
584                                       0);
585   BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData;
586   BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData;
587   BusHandler->GetInterruptVector =
588     (pGetInterruptVector)HalpGetPciInterruptVector;
589   BusHandler->TranslateBusAddress = 
590     (pTranslateBusAddress)HalpTranslatePciAddress;
591 //      BusHandler->AdjustResourceList =
592 //              (pGetSetBusData)HalpAdjustPciResourceList;
593 //      BusHandler->AssignSlotResources =
594 //              (pGetSetBusData)HalpAssignPciSlotResources;
595
596
597   /* agp bus (bus 1) handler */
598   BusHandler = HalpAllocateBusHandler(PCIBus,
599                                       PCIConfiguration,
600                                       1);
601   BusHandler->GetBusData = (pGetSetBusData)HalpGetPciData;
602   BusHandler->SetBusData = (pGetSetBusData)HalpSetPciData;
603   BusHandler->GetInterruptVector =
604     (pGetInterruptVector)HalpGetPciInterruptVector;
605   BusHandler->TranslateBusAddress = 
606     (pTranslateBusAddress)HalpTranslatePciAddress;
607 //      BusHandler->AdjustResourceList =
608 //              (pGetSetBusData)HalpAdjustPciResourceList;
609 //      BusHandler->AssignSlotResources =
610 //              (pGetSetBusData)HalpAssignPciSlotResources;
611
612   DPRINT("HalpInitPciBus() finished.\n");
613 }
614
615 /* EOF */