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>
11 #include <proto/bootloader.h>
12 #include <proto/oop.h>
13 #include <proto/utility.h>
14 #include <proto/exec.h>
21 #undef HiddPCIDeviceAttrBase
24 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
25 #define HiddAttrBase (hd->hd_HiddAB)
27 #define PCI_BASE_CLASS_SERIAL 0x0c
28 #define PCI_SUB_CLASS_USB 0x03
29 #define PCI_INTERFACE_UHCI 0x00
31 AROS_UFH3(void, pciEnumerator
,
32 AROS_UFHA(struct Hook
*, hook
, A0
),
33 AROS_UFHA(OOP_Object
*, pciDevice
, A2
),
34 AROS_UFHA(APTR
, message
, A1
))
38 struct PCIDevice
*hd
= (struct PCIDevice
*) hook
->h_Data
;
39 struct PCIController
*hc
;
47 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Interface
, &hcitype
);
48 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Bus
, &bus
);
49 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &dev
);
50 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Sub
, &sub
);
51 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &intline
);
53 devid
= (bus
<<16)|dev
;
55 KPRINTF(10, ("Found PCI device 0x%lx of type %ld, Intline=%ld\n", devid
, hcitype
, intline
));
58 // we can't work without the correct interrupt line
59 // BIOS needs plug & play os option disabled. Alternatively AROS must support APIC reconfiguration
60 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned by BIOS, disable Plug & Play OS!\n"));
62 KPRINTF(10, ("Setting up device...\n"));
64 hc
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIController
));
68 hc
->hc_FunctionNum
= sub
;
69 hc
->hc_HCIType
= hcitype
;
70 hc
->hc_PCIDeviceObject
= pciDevice
;
71 hc
->hc_PCIIntLine
= intline
;
73 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (IPTR
*) &hc
->hc_PCIDriverObject
);
75 NEWLIST(&hc
->hc_CtrlXFerQueue
);
76 NEWLIST(&hc
->hc_IntXFerQueue
);
77 NEWLIST(&hc
->hc_IsoXFerQueue
);
78 NEWLIST(&hc
->hc_BulkXFerQueue
);
80 NEWLIST(&hc
->hc_TDQueue
);
81 NEWLIST(&hc
->hc_AbortQueue
);
82 NEWLIST(&hc
->hc_PeriodicTDQueue
);
84 AddTail(&hd
->hd_TempHCIList
, &hc
->hc_Node
);
91 BOOL
pciInit(struct PCIDevice
*hd
) {
92 struct PCIController
*hc
;
93 struct PCIController
*nexthc
;
97 KPRINTF(10, ("*** pciInit(%p) ***\n", hd
));
99 NEWLIST(&hd
->hd_TempHCIList
);
101 if((hd
->hd_PCIHidd
= OOP_NewObject(NULL
, (STRPTR
) CLID_Hidd_PCI
, NULL
))) {
102 struct TagItem tags
[] = {
103 { tHidd_PCI_Class
, PCI_BASE_CLASS_SERIAL
},
104 { tHidd_PCI_SubClass
, PCI_SUB_CLASS_USB
},
105 { tHidd_PCI_Interface
, PCI_INTERFACE_UHCI
},
109 struct OOP_ABDescr attrbases
[] = {
110 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
111 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
115 struct Hook findHook
= {
116 h_Entry
: (IPTR (*)()) pciEnumerator
,
120 OOP_ObtainAttrBases(attrbases
);
122 KPRINTF(20, ("Searching for devices...\n"));
124 HIDD_PCI_EnumDevices(hd
->hd_PCIHidd
, &findHook
, (struct TagItem
*) &tags
);
126 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
130 // Create units with a list of host controllers having the same bus and device number.
131 while(hd
->hd_TempHCIList
.lh_Head
->ln_Succ
) {
132 hu
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIUnit
));
134 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
138 hu
->hu_UnitNo
= unitno
;
139 hu
->hu_DevID
= ((struct PCIController
*) hd
->hd_TempHCIList
.lh_Head
)->hc_DevID
;
141 NEWLIST(&hu
->hu_Controllers
);
142 NEWLIST(&hu
->hu_RHIOQueue
);
144 hc
= (struct PCIController
*) hd
->hd_TempHCIList
.lh_Head
;
145 while((nexthc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
)) {
146 if(hc
->hc_DevID
== hu
->hu_DevID
) {
147 Remove(&hc
->hc_Node
);
149 AddTail(&hu
->hu_Controllers
, &hc
->hc_Node
);
153 AddTail(&hd
->hd_Units
, (struct Node
*) hu
);
159 BOOL
pciAllocUnit(struct PCIUnit
*hu
) {
161 struct PCIController
*hc
;
163 BOOL allocgood
= TRUE
;
164 ULONG usb11ports
= 0;
168 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu
));
170 // allocate necessary memory
171 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
172 while(hc
->hc_Node
.ln_Succ
) {
173 allocgood
= uhciInit(hc
,hu
);
175 for(cnt
= usb11ports
; cnt
< usb11ports
+ hc
->hc_NumPorts
; cnt
++) {
176 hu
->hu_PortMap11
[cnt
] = hc
;
177 hu
->hu_PortNum11
[cnt
] = cnt
- usb11ports
;
178 hc
->hc_PortNumGlobal
[cnt
- usb11ports
] = cnt
;
179 KPRINTF2(200,("Mapping ports\n"));
180 KPRINTF2(200,(" Map11[%ld]= %p\n", cnt
, hc
));
181 KPRINTF2(200,(" Num11[%ld]= %ld\n", cnt
, (cnt
-usb11ports
)));
182 KPRINTF2(200,(" Glo11[%ld]= %ld\n", (cnt
-usb11ports
), cnt
));
184 usb11ports
+= hc
->hc_NumPorts
;
188 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
191 hu
->hu_RootHubPorts
= usb11ports
;
192 hu
->hu_RootHubAddr
= 0;
195 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
196 while(hc
->hc_Node
.ln_Succ
) {
197 hc
->hc_Flags
|= HCF_ONLINE
;
198 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
201 KPRINTF(10, ("Unit allocated!\n"));
206 void pciFreeUnit(struct PCIUnit
*hu
) {
207 struct PCIDevice
*hd
= hu
->hu_Device
;
208 struct PCIController
*hc
;
210 struct TagItem pciDeactivate
[] = {
211 { aHidd_PCIDevice_isIO
, FALSE
},
212 { aHidd_PCIDevice_isMEM
, FALSE
},
213 { aHidd_PCIDevice_isMaster
, FALSE
},
217 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu
));
220 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
221 while(hc
->hc_Node
.ln_Succ
)
223 hc
->hc_Flags
&= ~HCF_ONLINE
;
224 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
229 //FIXME: uhciFree routine actually ONLY stops the chip NOT free anything as code below...
230 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
231 while(hc
->hc_Node
.ln_Succ
) {
233 HIDD_PCIDriver_FreePCIMem(hc
->hc_PCIDriverObject
, hc
->hc_PCIMem
);
234 hc
->hc_PCIMem
= NULL
;
236 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
239 // disable and free board
240 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
241 while(hc
->hc_Node
.ln_Succ
)
243 OOP_SetAttrs(hc
->hc_PCIDeviceObject
, (struct TagItem
*) pciDeactivate
); // deactivate busmaster and IO/Mem
244 if(hc
->hc_PCIIntHandler
.is_Node
.ln_Name
) {
245 RemIntServer(INTB_KERNEL
+ hc
->hc_PCIIntLine
, &hc
->hc_PCIIntHandler
);
246 hc
->hc_PCIIntHandler
.is_Node
.ln_Name
= NULL
;
249 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
253 void pciExpunge(struct PCIDevice
*hd
) {
254 struct PCIController
*hc
;
257 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd
));
259 hu
= (struct PCIUnit
*) hd
->hd_Units
.lh_Head
;
260 while(((struct Node
*) hu
)->ln_Succ
) {
261 Remove((struct Node
*) hu
);
262 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
263 while(hc
->hc_Node
.ln_Succ
) {
264 Remove(&hc
->hc_Node
);
265 FreePooled(hd
->hd_MemPool
, hc
, sizeof(struct PCIController
));
266 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
268 FreePooled(hd
->hd_MemPool
, hu
, sizeof(struct PCIUnit
));
269 hu
= (struct PCIUnit
*) hd
->hd_Units
.lh_Head
;
272 struct OOP_ABDescr attrbases
[] =
274 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
275 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
279 OOP_ReleaseAttrBases(attrbases
);
281 OOP_DisposeObject(hd
->hd_PCIHidd
);
285 APTR
pciGetPhysical(struct PCIController
*hc
, APTR virtaddr
) {
286 //struct PCIDevice *hd = hc->hc_Device;
287 return(HIDD_PCIDriver_CPUtoPCI(hc
->hc_PCIDriverObject
, virtaddr
));
291 * Process some AROS-specific arguments.
292 * 'usbpoweron' helps to bring up USB ports on IntelMac,
293 * whose firmware sets them up incorrectly.
295 static int getArguments(struct PCIDevice
*base
) {
296 APTR BootLoaderBase
= OpenResource("bootloader.resource");
300 struct List
*args
= GetBootInfo(BL_Args
);
306 for (node
= args
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
308 if (stricmp(node
->ln_Name
, "forceusbpower") == 0)
310 base
->hd_Flags
= HDF_FORCEPOWER
;
320 ADD2INITLIB(getArguments
, 10)