update for HEAD-2003050101
[reactos.git] / drivers / bus / pci / pci.c
1 /* $Id$
2  *
3  * PROJECT:         ReactOS PCI Bus driver
4  * FILE:            pci.c
5  * PURPOSE:         Driver entry
6  * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * UPDATE HISTORY:
8  *      10-09-2001  CSH  Created
9  */
10 #include <pci.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 #ifdef  ALLOC_PRAGMA
17
18 // Make the initialization routines discardable, so that they 
19 // don't waste space
20
21 #pragma  alloc_text(init, DriverEntry)
22
23 #endif  /*  ALLOC_PRAGMA  */
24
25 /*** PUBLIC ******************************************************************/
26
27 PCI_BUS_TYPE PciBusConfigType = pbtUnknown;
28
29
30 /*** PRIVATE *****************************************************************/
31
32 static NTSTATUS
33 PciReadConfigUchar(UCHAR Bus,
34                    UCHAR Slot,
35                    UCHAR Offset,
36                    PUCHAR Value)
37 {
38    switch (PciBusConfigType)
39      {
40      case pbtType1:
41         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
42         *Value = READ_PORT_UCHAR((PUCHAR)0xCFC + (Offset & 3));
43         return STATUS_SUCCESS;
44
45      case pbtType2:
46         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
47         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
48         *Value = READ_PORT_UCHAR((PUCHAR)(IOADDR(Slot, Offset)));
49         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
50         return STATUS_SUCCESS;
51      }
52    return STATUS_UNSUCCESSFUL;
53 }
54
55
56 static NTSTATUS
57 PciReadConfigUshort(UCHAR Bus,
58                     UCHAR Slot,
59                     UCHAR Offset,
60                     PUSHORT Value)
61 {
62    if ((Offset & 1) != 0)
63      {
64         return STATUS_INVALID_PARAMETER;
65      }
66
67    switch (PciBusConfigType)
68      {
69      case pbtType1:
70         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
71         *Value = READ_PORT_USHORT((PUSHORT)0xCFC + (Offset & 2));
72         return STATUS_SUCCESS;
73
74      case pbtType2:
75         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
76         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
77         *Value = READ_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)));
78         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
79         return STATUS_SUCCESS;
80      }
81    return STATUS_UNSUCCESSFUL;
82 }
83
84
85 static NTSTATUS
86 PciReadConfigUlong(UCHAR Bus,
87                    UCHAR Slot,
88                    UCHAR Offset,
89                    PULONG Value)
90 {
91    if ((Offset & 3) != 0)
92      {
93         return STATUS_INVALID_PARAMETER;
94      }
95
96    switch (PciBusConfigType)
97      {
98      case pbtType1:
99         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
100         *Value = READ_PORT_ULONG((PULONG)0xCFC);
101         return STATUS_SUCCESS;
102
103      case pbtType2:
104         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
105         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
106         *Value = READ_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)));
107         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
108         return STATUS_SUCCESS;
109      }
110    return STATUS_UNSUCCESSFUL;
111 }
112
113
114 static NTSTATUS
115 PciWriteConfigUchar(UCHAR Bus,
116                     UCHAR Slot,
117                     UCHAR Offset,
118                     UCHAR Value)
119 {
120    switch (PciBusConfigType)
121      {
122      case pbtType1:
123         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
124         WRITE_PORT_UCHAR((PUCHAR)0xCFC + (Offset&3), Value);
125         return STATUS_SUCCESS;
126
127      case pbtType2:
128         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
129         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
130         WRITE_PORT_UCHAR((PUCHAR)(IOADDR(Slot,Offset)), Value);
131         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
132         return STATUS_SUCCESS;
133      }
134    return STATUS_UNSUCCESSFUL;
135 }
136
137
138 static NTSTATUS
139 PciWriteConfigUshort(UCHAR Bus,
140                      UCHAR Slot,
141                      UCHAR Offset,
142                      USHORT Value)
143 {
144    if ((Offset & 1) != 0)
145      {
146         return STATUS_INVALID_PARAMETER;
147      }
148
149    switch (PciBusConfigType)
150      {
151      case pbtType1:
152         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
153         WRITE_PORT_USHORT((PUSHORT)0xCFC + (Offset & 2), Value);
154         return STATUS_SUCCESS;
155
156      case pbtType2:
157         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
158         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
159         WRITE_PORT_USHORT((PUSHORT)(IOADDR(Slot, Offset)), Value);
160         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
161         return STATUS_SUCCESS;
162      }
163    return STATUS_UNSUCCESSFUL;
164 }
165
166
167 static NTSTATUS
168 PciWriteConfigUlong(UCHAR Bus,
169                     UCHAR Slot,
170                     UCHAR Offset,
171                     ULONG Value)
172 {
173    if ((Offset & 3) != 0)
174      {
175         return STATUS_INVALID_PARAMETER;
176      }
177
178    switch (PciBusConfigType)
179      {
180      case pbtType1:
181         WRITE_PORT_ULONG((PULONG)0xCF8, CONFIG_CMD(Bus, Slot, Offset));
182         WRITE_PORT_ULONG((PULONG)0xCFC, Value);
183         return STATUS_SUCCESS;
184
185      case pbtType2:
186         WRITE_PORT_UCHAR((PUCHAR)0xCF8, FUNC(Slot));
187         WRITE_PORT_UCHAR((PUCHAR)0xCFA, Bus);
188         WRITE_PORT_ULONG((PULONG)(IOADDR(Slot, Offset)), Value);
189         WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0);
190         return STATUS_SUCCESS;
191      }
192    return STATUS_UNSUCCESSFUL;
193 }
194
195
196 ULONG
197 PciGetBusData(ULONG BusNumber,
198                ULONG SlotNumber,
199                PVOID Buffer,
200                ULONG Offset,
201                ULONG Length)
202 {
203    PVOID Ptr = Buffer;
204    ULONG Address = Offset;
205    ULONG Len = Length;
206    ULONG Vendor;
207    UCHAR HeaderType;
208
209 #if 0
210    DPRINT("  BusNumber %lu\n", BusNumber);
211    DPRINT("  SlotNumber %lu\n", SlotNumber);
212    DPRINT("  Offset 0x%lx\n", Offset);
213    DPRINT("  Length 0x%lx\n", Length);
214 #endif
215
216    if ((Length == 0) || (PciBusConfigType == 0))
217      return 0;
218
219    /* 0E=PCI_HEADER_TYPE */
220    PciReadConfigUchar(BusNumber,
221                       SlotNumber & 0xF8,
222                       0x0E,
223                       &HeaderType);
224    if (((HeaderType & 0x80) == 0) && ((SlotNumber & 0x07) != 0))
225      return 0;
226
227    PciReadConfigUlong(BusNumber,
228                       SlotNumber,
229                       0x00,
230                       &Vendor);
231    /* some broken boards return 0 if a slot is empty: */
232    if (Vendor == 0xFFFFFFFF || Vendor == 0)
233      return 0;
234
235    if ((Address & 1) && (Len >= 1))
236      {
237         PciReadConfigUchar(BusNumber,
238                            SlotNumber,
239                            Address,
240                            Ptr);
241         Ptr = Ptr + 1;
242         Address++;
243         Len--;
244      }
245
246    if ((Address & 2) && (Len >= 2))
247      {
248         PciReadConfigUshort(BusNumber,
249                             SlotNumber,
250                             Address,
251                             Ptr);
252         Ptr = Ptr + 2;
253         Address += 2;
254         Len -= 2;
255      }
256
257    while (Len >= 4)
258      {
259         PciReadConfigUlong(BusNumber,
260                            SlotNumber,
261                            Address,
262                            Ptr);
263         Ptr = Ptr + 4;
264         Address += 4;
265         Len -= 4;
266      }
267
268    if (Len >= 2)
269      {
270         PciReadConfigUshort(BusNumber,
271                             SlotNumber,
272                             Address,
273                             Ptr);
274         Ptr = Ptr + 2;
275         Address += 2;
276         Len -= 2;
277      }
278
279    if (Len >= 1)
280      {
281         PciReadConfigUchar(BusNumber,
282                            SlotNumber,
283                            Address,
284                            Ptr);
285         Ptr = Ptr + 1;
286         Address++;
287         Len--;
288      }
289
290    return Length - Len;
291 }
292
293
294 ULONG
295 PciSetBusData(ULONG BusNumber,
296                ULONG SlotNumber,
297                PVOID Buffer,
298                ULONG Offset,
299                ULONG Length)
300 {
301    PVOID Ptr = Buffer;
302    ULONG Address = Offset;
303    ULONG Len = Length;
304    ULONG Vendor;
305    UCHAR HeaderType;
306
307 #if 0
308    DPRINT("  BusNumber %lu\n", BusNumber);
309    DPRINT("  SlotNumber %lu\n", SlotNumber);
310    DPRINT("  Offset 0x%lx\n", Offset);
311    DPRINT("  Length 0x%lx\n", Length);
312 #endif
313
314    if ((Length == 0) || (PciBusConfigType == 0))
315      return 0;
316
317    /* 0E=PCI_HEADER_TYPE */
318    PciReadConfigUchar(BusNumber,
319                       SlotNumber & 0xF8,
320                       0x0E,
321                       &HeaderType);
322    if (((HeaderType & 0x80) == 0) && ((SlotNumber & 0x07) != 0))
323      return 0;
324
325    PciReadConfigUlong(BusNumber,
326                       SlotNumber,
327                       0x00,
328                       &Vendor);
329    /* some broken boards return 0 if a slot is empty: */
330    if (Vendor == 0xFFFFFFFF || Vendor == 0)
331      return 0;
332
333    if ((Address & 1) && (Len >= 1))
334      {
335         PciWriteConfigUchar(BusNumber,
336                             SlotNumber,
337                             Address,
338                             *(PUCHAR)Ptr);
339         Ptr = Ptr + 1;
340         Address++;
341         Len--;
342      }
343
344    if ((Address & 2) && (Len >= 2))
345      {
346         PciWriteConfigUshort(BusNumber,
347                              SlotNumber,
348                              Address,
349                              *(PUSHORT)Ptr);
350         Ptr = Ptr + 2;
351         Address += 2;
352         Len -= 2;
353      }
354
355    while (Len >= 4)
356      {
357         PciWriteConfigUlong(BusNumber,
358                             SlotNumber,
359                             Address,
360                             *(PULONG)Ptr);
361         Ptr = Ptr + 4;
362         Address += 4;
363         Len -= 4;
364      }
365
366    if (Len >= 2)
367      {
368         PciWriteConfigUshort(BusNumber,
369                              SlotNumber,
370                              Address,
371                              *(PUSHORT)Ptr);
372         Ptr = Ptr + 2;
373         Address += 2;
374         Len -= 2;
375      }
376
377    if (Len >= 1)
378      {
379         PciWriteConfigUchar(BusNumber,
380                             SlotNumber,
381                             Address,
382                             *(PUCHAR)Ptr);
383         Ptr = Ptr + 1;
384         Address++;
385         Len--;
386      }
387
388    return Length - Len;
389 }
390
391
392 PCI_BUS_TYPE
393 PciGetBusConfigType(VOID)
394 {
395    ULONG Value;
396
397    DPRINT("Called\n");
398
399    DPRINT("Checking configuration type 1:\n");
400    WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x01);
401    Value = READ_PORT_ULONG((PULONG)0xCF8);
402    WRITE_PORT_ULONG((PULONG)0xCF8, 0x80000000);
403    if (READ_PORT_ULONG((PULONG)0xCF8) == 0x80000000)
404      {
405         WRITE_PORT_ULONG((PULONG)0xCF8, Value);
406         DPRINT("  Success!\n");
407         return pbtType1;
408      }
409    WRITE_PORT_ULONG((PULONG)0xCF8, Value);
410    DPRINT("  Unsuccessful!\n");
411
412    DPRINT("Checking configuration type 2:\n");
413    WRITE_PORT_UCHAR((PUCHAR)0xCFB, 0x00);
414    WRITE_PORT_UCHAR((PUCHAR)0xCF8, 0x00);
415    WRITE_PORT_UCHAR((PUCHAR)0xCFA, 0x00);
416    if (READ_PORT_UCHAR((PUCHAR)0xCF8) == 0x00 &&
417        READ_PORT_UCHAR((PUCHAR)0xCFB) == 0x00)
418      {
419         DPRINT("  Success!\n");
420         return pbtType2;
421      }
422    DPRINT("  Unsuccessful!\n");
423
424    DPRINT("No pci bus found!\n");
425    return pbtUnknown;
426 }
427
428
429 NTSTATUS
430 STDCALL
431 PciDispatchDeviceControl(
432   IN PDEVICE_OBJECT DeviceObject, 
433   IN PIRP Irp) 
434 {
435   PIO_STACK_LOCATION IrpSp;
436   NTSTATUS Status;
437
438   DPRINT("Called. IRP is at (0x%X)\n", Irp);
439
440   Irp->IoStatus.Information = 0;
441
442   IrpSp = IoGetCurrentIrpStackLocation(Irp);
443   switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
444   default:
445     DPRINT("Unknown IOCTL 0x%X\n", IrpSp->Parameters.DeviceIoControl.IoControlCode);
446     Status = STATUS_NOT_IMPLEMENTED;
447     break;
448   }
449
450   if (Status != STATUS_PENDING) {
451     Irp->IoStatus.Status = Status;
452
453     DPRINT("Completing IRP at 0x%X\n", Irp);
454
455     IoCompleteRequest(Irp, IO_NO_INCREMENT);
456   }
457
458   DPRINT("Leaving. Status 0x%X\n", Status);
459
460   return Status;
461 }
462
463
464 NTSTATUS
465 STDCALL
466 PciPnpControl(
467   IN PDEVICE_OBJECT DeviceObject,
468   IN PIRP Irp)
469 /*
470  * FUNCTION: Handle Plug and Play IRPs
471  * ARGUMENTS:
472  *     DeviceObject = Pointer to PDO or FDO
473  *     Irp          = Pointer to IRP that should be handled
474  * RETURNS:
475  *     Status
476  */
477 {
478   PCOMMON_DEVICE_EXTENSION DeviceExtension;
479   NTSTATUS Status;
480
481   DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
482
483   DPRINT("IsFDO %d\n", DeviceExtension->IsFDO);
484
485   if (DeviceExtension->IsFDO) {
486     Status = FdoPnpControl(DeviceObject, Irp);
487   } else {
488     Status = PdoPnpControl(DeviceObject, Irp);
489   }
490
491   return Status;
492 }
493
494
495 NTSTATUS
496 STDCALL
497 PciPowerControl(
498   IN PDEVICE_OBJECT DeviceObject,
499   IN PIRP Irp)
500 /*
501  * FUNCTION: Handle power management IRPs
502  * ARGUMENTS:
503  *     DeviceObject = Pointer to PDO or FDO
504  *     Irp          = Pointer to IRP that should be handled
505  * RETURNS:
506  *     Status
507  */
508 {
509   PCOMMON_DEVICE_EXTENSION DeviceExtension;
510   NTSTATUS Status;
511
512   DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
513
514   if (DeviceExtension->IsFDO) {
515     Status = FdoPowerControl(DeviceObject, Irp);
516   } else {
517     Status = PdoPowerControl(DeviceObject, Irp);
518   }
519
520   return Status;
521 }
522
523
524 NTSTATUS
525 STDCALL
526 PciAddDevice(
527   IN PDRIVER_OBJECT DriverObject,
528   IN PDEVICE_OBJECT PhysicalDeviceObject)
529 {
530   PFDO_DEVICE_EXTENSION DeviceExtension;
531   PDEVICE_OBJECT Fdo;
532   NTSTATUS Status;
533
534   DPRINT("Called\n");
535
536   Status = IoCreateDevice(DriverObject, sizeof(FDO_DEVICE_EXTENSION),
537     NULL, FILE_DEVICE_BUS_EXTENDER, FILE_DEVICE_SECURE_OPEN, TRUE, &Fdo);
538   if (!NT_SUCCESS(Status)) {
539     DPRINT("IoCreateDevice() failed with status 0x%X\n", Status);
540     return Status;
541   }
542
543   DeviceExtension = (PFDO_DEVICE_EXTENSION)Fdo->DeviceExtension;
544
545   RtlZeroMemory(DeviceExtension, sizeof(FDO_DEVICE_EXTENSION));
546
547   DeviceExtension->Common.IsFDO = TRUE;
548
549   DeviceExtension->Ldo =
550     IoAttachDeviceToDeviceStack(Fdo, PhysicalDeviceObject);
551
552   DeviceExtension->State = dsStopped;
553
554   Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
555
556   //Fdo->Flags |= DO_POWER_PAGABLE;
557
558   DPRINT("Done AddDevice\n");
559
560   return STATUS_SUCCESS;
561 }
562
563
564 NTSTATUS
565 STDCALL
566 DriverEntry(
567   IN PDRIVER_OBJECT DriverObject,
568   IN PUNICODE_STRING RegistryPath)
569 {
570   DbgPrint("Peripheral Component Interconnect Bus Driver\n");
571
572   DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH) PciDispatchDeviceControl;
573   DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH) PciPnpControl;
574   DriverObject->MajorFunction[IRP_MJ_POWER] = (PDRIVER_DISPATCH) PciPowerControl;
575   DriverObject->DriverExtension->AddDevice = PciAddDevice;
576
577   return STATUS_SUCCESS;
578 }
579
580
581 BOOLEAN
582 PciCreateUnicodeString(
583   PUNICODE_STRING       Destination,
584   PWSTR Source,
585   POOL_TYPE PoolType)
586 {
587   ULONG Length;
588
589   if (!Source)
590   {
591     RtlInitUnicodeString(Destination, NULL);
592     return TRUE;
593   }
594
595   Length = (wcslen(Source) + 1) * sizeof(WCHAR);
596
597   Destination->Buffer = ExAllocatePool(PoolType, Length);
598
599   if (Destination->Buffer == NULL)
600   {
601     return FALSE;
602   }
603
604   RtlCopyMemory(Destination->Buffer, Source, Length);
605
606   Destination->MaximumLength = Length;
607
608   Destination->Length = Length - sizeof(WCHAR);
609
610   return TRUE;
611 }
612
613 /* EOF */