1 /* pci_aros.c - pci access abstraction for AROS by Chris Hodges
4 #include <aros/bootloader.h>
5 #include <aros/symbolsets.h>
6 #include <exec/types.h>
8 #include <devices/timer.h>
12 #include <proto/bootloader.h>
13 #include <proto/oop.h>
14 #include <proto/utility.h>
15 #include <proto/exec.h>
21 #include "ohciproto.h"
23 #define NewList NEWLIST
25 #undef HiddPCIDeviceAttrBase
26 //#undef HiddUSBDeviceAttrBase
27 //#undef HiddUSBHubAttrBase
28 //#undef HiddUSBDrvAttrBase
31 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
32 //#define HiddUSBDeviceAttrBase (hd->hd_HiddUSBDeviceAB)
33 //#define HiddUSBHubAttrBase (hd->hd_HiddUSBHubAB)
34 //#define HiddUSBDrvAttrBase (hd->hd_HiddUSBDrvAB)
35 #define HiddAttrBase (hd->hd_HiddAB)
37 AROS_UFH3(void, pciEnumerator
,
38 AROS_UFHA(struct Hook
*, hook
, A0
),
39 AROS_UFHA(OOP_Object
*, pciDevice
, A2
),
40 AROS_UFHA(APTR
, message
, A1
))
44 struct PCIDevice
*hd
= (struct PCIDevice
*) hook
->h_Data
;
45 struct PCIController
*hc
;
52 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Interface
, &hcitype
);
53 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Bus
, &bus
);
54 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &dev
);
55 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &intline
);
57 devid
= (bus
<<16)|dev
;
59 KPRINTF(10, ("Found PCI device 0x%lx of type %ld, Intline=%ld\n", devid
, hcitype
, intline
));
63 // we can't work without the correct interrupt line
64 // BIOS needs plug & play os option disabled. Alternatively AROS must support APIC reconfiguration
65 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned by BIOS, disable Plug & Play OS!\n"));
72 #ifndef __powerpc__ /* It was not from me. Perhaps on PPC these drivers suffer from CPU cache problems? (sonic) */
73 #ifndef __x86_64__ /* Not 64-bit-ready yet - sonic */
78 #if defined(AROS_USB30_CODE)
81 KPRINTF(10, ("Setting up device...\n"));
83 hc
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIController
));
88 hc
->hc_HCIType
= hcitype
;
89 hc
->hc_PCIDeviceObject
= pciDevice
;
90 hc
->hc_PCIIntLine
= intline
;
92 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (IPTR
*) &hc
->hc_PCIDriverObject
);
94 NewList(&hc
->hc_CtrlXFerQueue
);
95 NewList(&hc
->hc_IntXFerQueue
);
96 NewList(&hc
->hc_IsoXFerQueue
);
97 NewList(&hc
->hc_BulkXFerQueue
);
98 NewList(&hc
->hc_TDQueue
);
99 NewList(&hc
->hc_AbortQueue
);
100 NewList(&hc
->hc_PeriodicTDQueue
);
101 NewList(&hc
->hc_OhciRetireQueue
);
102 AddTail(&hd
->hd_TempHCIList
, &hc
->hc_Node
);
107 KPRINTF(10, ("Unsupported HCI type %ld\n", hcitype
));
114 /* /// "pciInit()" */
115 BOOL
pciInit(struct PCIDevice
*hd
)
117 struct PCIController
*hc
;
118 struct PCIController
*nexthc
;
124 KPRINTF(10, ("*** pciInit(%p) ***\n", hd
));
125 /* if(sizeof(IPTR) > 4)
127 KPRINTF(200, ("I said the pciusb.device is not 64bit compatible right now. Go away!\n"));
131 NewList(&hd
->hd_TempHCIList
);
133 if(!(hd
->hd_IRQHidd
= OOP_NewObject(NULL
, (STRPTR
) CLID_Hidd_IRQ
, NULL
)))
135 KPRINTF(20, ("Unable to create IRQHidd object!\n"));
139 if((hd
->hd_PCIHidd
= OOP_NewObject(NULL
, (STRPTR
) CLID_Hidd_PCI
, NULL
)))
141 struct TagItem tags
[] =
143 { tHidd_PCI_Class
, (PCI_CLASS_SERIAL_USB
>>8) & 0xff },
144 { tHidd_PCI_SubClass
, (PCI_CLASS_SERIAL_USB
& 0xff) },
148 struct OOP_ABDescr attrbases
[] =
150 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
151 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
155 struct Hook findHook
=
157 h_Entry
: (IPTR (*)()) pciEnumerator
,
161 OOP_ObtainAttrBases(attrbases
);
163 KPRINTF(20, ("Searching for devices...\n"));
165 HIDD_PCI_EnumDevices(hd
->hd_PCIHidd
, &findHook
, (struct TagItem
*) &tags
);
167 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
168 OOP_DisposeObject(hd
->hd_IRQHidd
);
172 while(hd
->hd_TempHCIList
.lh_Head
->ln_Succ
)
174 hu
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIUnit
));
177 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
181 hu
->hu_UnitNo
= unitno
;
182 hu
->hu_DevID
= ((struct PCIController
*) hd
->hd_TempHCIList
.lh_Head
)->hc_DevID
;
184 NewList(&hu
->hu_Controllers
);
185 NewList(&hu
->hu_RHIOQueue
);
188 // find all belonging host controllers
189 hc
= (struct PCIController
*) hd
->hd_TempHCIList
.lh_Head
;
190 while((nexthc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
))
192 if(hc
->hc_DevID
== hu
->hu_DevID
)
194 Remove(&hc
->hc_Node
);
196 if(hc
->hc_HCIType
== HCITYPE_UHCI
)
198 hc
->hc_FunctionNum
= uhcicnt
++;
200 else if(hc
->hc_HCIType
== HCITYPE_OHCI
)
202 hc
->hc_FunctionNum
= ohcicnt
++;
204 hc
->hc_FunctionNum
= 0;
206 AddTail(&hu
->hu_Controllers
, &hc
->hc_Node
);
210 AddTail(&hd
->hd_Units
, (struct Node
*) hu
);
217 /* /// "PCIXReadConfigByte()" */
218 UBYTE
PCIXReadConfigByte(struct PCIController
*hc
, UBYTE offset
)
220 struct pHidd_PCIDevice_ReadConfigByte msg
;
222 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigByte
);
225 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
229 /* /// "PCIXReadConfigWord()" */
230 UWORD
PCIXReadConfigWord(struct PCIController
*hc
, UBYTE offset
)
232 struct pHidd_PCIDevice_ReadConfigWord msg
;
234 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigWord
);
237 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
241 /* /// "PCIXReadConfigLong()" */
242 ULONG
PCIXReadConfigLong(struct PCIController
*hc
, UBYTE offset
)
244 struct pHidd_PCIDevice_ReadConfigLong msg
;
246 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigLong
);
249 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
253 /* /// "PCIXWriteConfigByte()" */
254 void PCIXWriteConfigByte(struct PCIController
*hc
, ULONG offset
, UBYTE value
)
256 struct pHidd_PCIDevice_WriteConfigByte msg
;
258 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigByte
);
262 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
266 /* /// "PCIXWriteConfigWord()" */
267 void PCIXWriteConfigWord(struct PCIController
*hc
, ULONG offset
, UWORD value
)
269 struct pHidd_PCIDevice_WriteConfigWord msg
;
271 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigWord
);
275 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
279 /* /// "PCIXWriteConfigLong()" */
280 void PCIXWriteConfigLong(struct PCIController
*hc
, ULONG offset
, ULONG value
)
282 struct pHidd_PCIDevice_WriteConfigLong msg
;
284 msg
.mID
= OOP_GetMethodID(CLID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigLong
);
288 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
292 /* /// "pciStrcat()" */
293 void pciStrcat(STRPTR d
, STRPTR s
)
296 while((*d
++ = *s
++));
300 /* /// "pciAllocUnit()" */
301 BOOL
pciAllocUnit(struct PCIUnit
*hu
)
304 struct PCIDevice
*hd
= hu
->hu_Device
;
306 struct PCIController
*hc
;
308 BOOL allocgood
= TRUE
;
311 #if defined(AROS_USB30_CODE)
319 #if defined(AROS_USB30_CODE)
324 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu
));
325 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
326 while(hc
->hc_Node
.ln_Succ
)
328 #if 0 // FIXME this needs to be replaced by something AROS supports
329 PCIXObtainBoard(hc
->hc_BoardObject
);
330 if (PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, (ULONG
) hd
->hd_Library
.lib_Node
.ln_Name
))
331 hc
->hc_Flags
|= HCF_BOARD_ALLOCATED
;
334 KPRINTF(20, ("Couldn't allocate board, already allocated by %s\n", PCIXGetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
)));
337 PCIXReleaseBoard(hc
->hc_BoardObject
);
340 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
345 // allocate necessary memory
346 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
347 while(hc
->hc_Node
.ln_Succ
)
349 switch(hc
->hc_HCIType
)
353 allocgood
= uhciInit(hc
,hu
);
359 allocgood
= ohciInit(hc
,hu
);
365 allocgood
= ehciInit(hc
,hu
);
368 #if defined(AROS_USB30_CODE)
371 allocgood
= xhciInit(hc
,hu
);
376 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
382 // free previously allocated boards
383 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
384 while(hc
->hc_Node
.ln_Succ
)
387 PCIXObtainBoard(hc
->hc_BoardObject
);
388 if (hc
->hc_Flags
& HCF_ALLOCATED
)
390 hc
->hc_Flags
&= ~HCF_ALLOCATED
;
391 PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, 0);
393 PCIXReleaseBoard(hc
->hc_BoardObject
);
395 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
400 // find all belonging host controllers
403 #if defined(AROS_USB30_CODE)
407 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
408 while(hc
->hc_Node
.ln_Succ
)
410 #if defined(AROS_USB30_CODE)
411 if(hc
->hc_HCIType
== HCITYPE_XHCI
)
416 KPRINTF(200, ("WARNING: Two XHCI controllers per Board?!?\n"));
418 usb30ports
= hc
->hc_NumPorts
;
422 if(hc
->hc_HCIType
== HCITYPE_EHCI
)
427 KPRINTF(200, ("WARNING: Two EHCI controllers per Board?!?\n"));
429 usb20ports
= hc
->hc_NumPorts
;
430 for(cnt
= 0; cnt
< usb20ports
; cnt
++)
432 hu
->hu_PortMap20
[cnt
] = hc
;
433 hc
->hc_PortNum20
[cnt
] = cnt
;
436 else if(hc
->hc_HCIType
== HCITYPE_UHCI
)
440 else if(hc
->hc_HCIType
== HCITYPE_OHCI
)
444 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
447 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
448 while(hc
->hc_Node
.ln_Succ
)
450 if((hc
->hc_HCIType
== HCITYPE_UHCI
) || (hc
->hc_HCIType
== HCITYPE_OHCI
))
452 if(hc
->hc_complexrouting
)
455 for(cnt
= 0; cnt
< usb20ports
; cnt
++)
457 if(((hc
->hc_portroute
>> (cnt
<<2)) & 0xf) == hc
->hc_FunctionNum
)
459 KPRINTF(10, ("CHC %ld Port %ld assigned to global Port %ld\n", hc
->hc_FunctionNum
, locport
, cnt
));
460 hu
->hu_PortMap11
[cnt
] = hc
;
461 hu
->hu_PortNum11
[cnt
] = locport
;
462 hc
->hc_PortNum20
[locport
] = cnt
;
467 for(cnt
= usb11ports
; cnt
< usb11ports
+ hc
->hc_NumPorts
; cnt
++)
469 hu
->hu_PortMap11
[cnt
] = hc
;
470 hu
->hu_PortNum11
[cnt
] = cnt
- usb11ports
;
471 hc
->hc_PortNum20
[cnt
- usb11ports
] = cnt
;
474 usb11ports
+= hc
->hc_NumPorts
;
476 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
478 if((usb11ports
!= usb20ports
) && usb20ports
)
480 KPRINTF(20, ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n", usb20ports
, usb11ports
));
483 hu
->hu_RootHub11Ports
= usb11ports
;
484 hu
->hu_RootHub20Ports
= usb20ports
;
485 #if defined(AROS_USB30_CODE)
486 // FIXME: This is probably wrong as well...
487 hu
->hu_RootHub30Ports
= usb30ports
;
488 hu
->hu_RootHubPorts
= (usb11ports
> usb20ports
) ? ((usb11ports
> usb30ports
) ? usb11ports
: usb30ports
) : ((usb30ports
> usb20ports
) ? usb30ports
: usb20ports
);
490 hu
->hu_RootHubPorts
= (usb11ports
> usb20ports
) ? usb11ports
: usb20ports
;
492 for(cnt
= 0; cnt
< hu
->hu_RootHubPorts
; cnt
++)
494 hu
->hu_EhciOwned
[cnt
] = hu
->hu_PortMap20
[cnt
] ? TRUE
: FALSE
;
497 #if defined(AROS_USB30_CODE)
498 KPRINTF(1000, ("Unit %ld: USB Board %08lx has %ld USB1.1, %ld USB2.0 and %ld USB3.0 ports!\n", hu
->hu_UnitNo
, hu
->hu_DevID
, hu
->hu_RootHub11Ports
, hu
->hu_RootHub20Ports
, hu
->hu_RootHub30Ports
));
500 KPRINTF(10, ("Unit %ld: USB Board %08lx has %ld USB1.1 and %ld USB2.0 ports!\n", hu
->hu_UnitNo
, hu
->hu_DevID
, hu
->hu_RootHub11Ports
, hu
->hu_RootHub20Ports
));
503 hu
->hu_FrameCounter
= 1;
504 hu
->hu_RootHubAddr
= 0;
507 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
508 while(hc
->hc_Node
.ln_Succ
)
510 hc
->hc_Flags
|= HCF_ONLINE
;
511 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
514 // create product name of device
515 prodname
= hu
->hu_ProductName
;
517 pciStrcat(prodname
, "PCI ");
518 if(ohcicnt
+ uhcicnt
)
520 if(ohcicnt
+ uhcicnt
>1)
522 prodname
[4] = ohcicnt
+ uhcicnt
+ '0';
526 pciStrcat(prodname
, ohcicnt
? "OHCI" : "UHCI");
529 pciStrcat(prodname
, " +");
531 pciStrcat(prodname
, " USB 1.1");
536 pciStrcat(prodname
, " EHCI USB 2.0");
538 #if defined(AROS_USB30_CODE)
543 prodname
[4] = xhcicnt
+ '0';
547 pciStrcat(prodname
, " XHCI USB 3.0");
550 #if 0 // user can use pcitool to check what the chipset is and not guess it from this
551 pciStrcat(prodname
, " Host Controller (");
552 if(ohcicnt
+ uhcicnt
)
554 pciStrcat(prodname
, ohcicnt
? "NEC)" : "VIA, Intel, ALI, etc.)");
556 pciStrcat(prodname
, "Emulated?)");
559 pciStrcat(prodname
, " Host Controller");
561 KPRINTF(10, ("Unit allocated!\n"));
567 /* /// "pciFreeUnit()" */
568 void pciFreeUnit(struct PCIUnit
*hu
)
570 struct PCIDevice
*hd
= hu
->hu_Device
;
571 struct PCIController
*hc
;
573 struct TagItem pciDeactivate
[] =
575 { aHidd_PCIDevice_isIO
, FALSE
},
576 { aHidd_PCIDevice_isMEM
, FALSE
},
577 { aHidd_PCIDevice_isMaster
, FALSE
},
581 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu
));
584 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
585 while(hc
->hc_Node
.ln_Succ
)
587 hc
->hc_Flags
&= ~HCF_ONLINE
;
588 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
591 #if defined(AROS_USB30_CODE)
594 // doing this in three steps to avoid these damn host errors
599 //FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT free anything as below...
600 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
601 while(hc
->hc_Node
.ln_Succ
) {
603 HIDD_PCIDriver_FreePCIMem(hc
->hc_PCIDriverObject
, hc
->hc_PCIMem
);
604 hc
->hc_PCIMem
= NULL
;
606 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
609 // disable and free board
610 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
611 while(hc
->hc_Node
.ln_Succ
)
613 OOP_SetAttrs(hc
->hc_PCIDeviceObject
, (struct TagItem
*) pciDeactivate
); // deactivate busmaster and IO/Mem
614 if(hc
->hc_PCIIntHandler
.h_Node
.ln_Name
)
616 HIDD_IRQ_RemHandler(hd
->hd_IRQHidd
, &hc
->hc_PCIIntHandler
);
617 hc
->hc_PCIIntHandler
.h_Node
.ln_Name
= NULL
;
621 PCIXObtainBoard(hc
->hc_BoardObject
);
622 hc
->hc_Flags
&= ~HCF_ALLOCATED
;
623 PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, 0);
624 PCIXReleaseBoard(hc
->hc_BoardObject
);
626 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
631 /* /// "pciExpunge()" */
632 void pciExpunge(struct PCIDevice
*hd
)
634 struct PCIController
*hc
;
637 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd
));
639 hu
= (struct PCIUnit
*) hd
->hd_Units
.lh_Head
;
640 while(((struct Node
*) hu
)->ln_Succ
)
642 Remove((struct Node
*) hu
);
643 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
644 while(hc
->hc_Node
.ln_Succ
)
646 Remove(&hc
->hc_Node
);
647 FreePooled(hd
->hd_MemPool
, hc
, sizeof(struct PCIController
));
648 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
650 FreePooled(hd
->hd_MemPool
, hu
, sizeof(struct PCIUnit
));
651 hu
= (struct PCIUnit
*) hd
->hd_Units
.lh_Head
;
655 struct OOP_ABDescr attrbases
[] =
657 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
658 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
662 OOP_ReleaseAttrBases(attrbases
);
664 OOP_DisposeObject(hd
->hd_PCIHidd
);
668 OOP_DisposeObject(hd
->hd_IRQHidd
);
673 /* /// "pciGetPhysical()" */
674 APTR
pciGetPhysical(struct PCIController
*hc
, APTR virtaddr
)
676 //struct PCIDevice *hd = hc->hc_Device;
677 return(HIDD_PCIDriver_CPUtoPCI(hc
->hc_PCIDriverObject
, virtaddr
));
682 * Process some AROS-specific arguments.
683 * 'usbpoweron' helps to bring up USB ports on IntelMac,
684 * whose firmware sets them up incorrectly.
686 static int getArguments(struct PCIDevice
*base
)
688 APTR BootLoaderBase
= OpenResource("bootloader.resource");
692 struct List
*args
= GetBootInfo(BL_Args
);
698 for (node
= args
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
700 if (stricmp(node
->ln_Name
, "forceusbpower") == 0)
702 base
->hd_Flags
= HDF_FORCEPOWER
;
712 ADD2INITLIB(getArguments
, 10)