2 Copyright © 2002-2009, Chris Hodges. All rights reserved.
3 Copyright © 2009-2012, The AROS Development Team. All rights reserved.
7 #include <aros/bootloader.h>
8 #include <exec/types.h>
10 #include <devices/timer.h>
11 #include <hidd/hidd.h>
14 #include <proto/bootloader.h>
15 #include <proto/oop.h>
16 #include <proto/utility.h>
17 #include <proto/exec.h>
18 #include <clib/alib_protos.h>
26 #include "chip_protos.h"
27 #include "cmd_protos.h"
37 #include <proto/acpica.h>
40 #undef HiddPCIDeviceAttrBase
43 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
44 #define HiddAttrBase (hd->hd_HiddAB)
46 static TEXT product_name
[] = "PCI OHCI USB 1.1 Host Controller";
48 AROS_UFH3(void, pciEnumerator
,
49 AROS_UFHA(struct Hook
*, hook
, A0
),
50 AROS_UFHA(OOP_Object
*, pciDevice
, A2
), AROS_UFHA(APTR
, message
, A1
))
54 struct PCIDevice
*hd
= (struct PCIDevice
*)hook
->h_Data
;
55 struct PCIController
*hc
;
63 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Bus
, &bus
);
64 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &dev
);
65 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Sub
, &sub
);
66 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &intline
);
68 devid
= (bus
<< 16) | dev
;
70 KPRINTF(10, ("Found PCI device 0x%lx Intline=%ld\n", devid
, intline
));
74 // we can't work without the correct interrupt line.
75 // BIOS needs plug & play os option disabled.
76 // Alternatively AROS must support APIC reconfiguration
77 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned "
78 "by BIOS, disable Plug & Play OS!\n"));
82 KPRINTF(10, ("Setting up device...\n"));
84 hc
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIController
));
89 hc
->hc_FunctionNum
= sub
;
90 hc
->hc_PCIDeviceObject
= pciDevice
;
91 hc
->hc_PCIIntLine
= intline
;
93 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
,
94 (IPTR
*) & hc
->hc_PCIDriverObject
);
96 for (i
= 0; i
< XFER_COUNT
; i
++)
97 NewList(&hc
->hc_XferQueues
[i
]);
98 NewList(&hc
->hc_TDQueue
);
99 NewList(&hc
->hc_AbortQueue
);
100 NewList(&hc
->hc_PeriodicTDQueue
);
101 NewList(&hc
->hc_RetireQueue
);
102 AddTail(&hd
->hd_TempHCIList
, &hc
->hc_Node
);
109 /* /// "pciInit()" */
110 BOOL
pciInit(struct PCIDevice
*hd
)
112 struct PCIController
*hc
;
113 struct PCIController
*nexthc
;
117 KPRINTF(10, ("*** pciInit(%p) ***\n", hd
));
119 NewList(&hd
->hd_TempHCIList
);
121 if ((hd
->hd_PCIHidd
=
122 OOP_NewObject(NULL
, (STRPTR
) CLID_Hidd_PCI
, NULL
)))
124 struct TagItem tags
[] = {
125 {tHidd_PCI_Class
, (PCI_CLASS_SERIAL_USB
>> 8) & 0xff},
126 {tHidd_PCI_SubClass
, (PCI_CLASS_SERIAL_USB
& 0xff)},
127 {tHidd_PCI_Interface
, 0x10},
131 struct OOP_ABDescr attrbases
[] = {
132 {(STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
133 {(STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
137 struct Hook findHook
= {
138 h_Entry
:(IPTR(*)())pciEnumerator
,
142 OOP_ObtainAttrBases(attrbases
);
144 KPRINTF(20, ("Searching for devices...\n"));
146 HIDD_PCI_EnumDevices(hd
->hd_PCIHidd
, &findHook
,
147 (struct TagItem
*)&tags
);
151 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
155 // Create units with a list of host controllers having the same bus
156 // and device number.
157 while (hd
->hd_TempHCIList
.lh_Head
->ln_Succ
)
159 hu
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIUnit
));
162 // actually, we should get rid of the allocated memory first,
163 // but we don't care as DeletePool() will take care of this
168 hu
->hu_UnitNo
= unitno
;
170 ((struct PCIController
*)hd
->hd_TempHCIList
.lh_Head
)->hc_DevID
;
172 NewList(&hu
->hu_Controllers
);
173 NewList(&hu
->hu_RHIOQueue
);
175 hc
= (struct PCIController
*)hd
->hd_TempHCIList
.lh_Head
;
176 while ((nexthc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
))
178 if (hc
->hc_DevID
== hu
->hu_DevID
)
180 Remove(&hc
->hc_Node
);
182 AddTail(&hu
->hu_Controllers
, &hc
->hc_Node
);
186 AddTail(&hd
->hd_Units
, (struct Node
*)hu
);
193 /* /// "pciAllocUnit()" */
194 BOOL
pciAllocUnit(struct PCIUnit
* hu
)
196 struct PCIController
*hc
;
198 BOOL allocgood
= TRUE
;
199 ULONG usb11ports
= 0;
200 ULONG usb20ports
= 0;
205 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu
));
207 // allocate necessary memory
208 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
209 while (hc
->hc_Node
.ln_Succ
)
211 allocgood
= InitController(hc
, hu
);
217 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
225 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
226 while (hc
->hc_Node
.ln_Succ
)
228 if (hc
->hc_complexrouting
)
231 for (cnt
= 0; cnt
< usb20ports
; cnt
++)
233 if (((hc
->hc_portroute
>> (cnt
<< 2)) & 0xf) ==
237 ("CHC %ld Port %ld assigned to global Port %ld\n",
238 hc
->hc_FunctionNum
, locport
, cnt
));
239 hu
->hu_PortMap11
[cnt
] = hc
;
240 hu
->hu_PortNum11
[cnt
] = locport
;
241 hc
->hc_PortNum20
[locport
] = cnt
;
248 for (cnt
= usb11ports
; cnt
< usb11ports
+ hc
->hc_NumPorts
;
251 hu
->hu_PortMap11
[cnt
] = hc
;
252 hu
->hu_PortNum11
[cnt
] = cnt
- usb11ports
;
253 hc
->hc_PortNum20
[cnt
- usb11ports
] = cnt
;
256 usb11ports
+= hc
->hc_NumPorts
;
257 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
259 if ((usb11ports
!= usb20ports
) && usb20ports
)
262 ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n",
263 usb20ports
, usb11ports
));
266 hu
->hu_RootHub11Ports
= usb11ports
;
267 hu
->hu_RootHub20Ports
= usb20ports
;
268 hu
->hu_RootHubPorts
=
269 (usb11ports
> usb20ports
) ? usb11ports
: usb20ports
;
270 for (cnt
= 0; cnt
< hu
->hu_RootHubPorts
; cnt
++)
272 hu
->hu_EhciOwned
[cnt
] = hu
->hu_PortMap20
[cnt
] ? TRUE
: FALSE
;
275 KPRINTF(10, ("Unit %ld: USB Board %08lx has %ld USB1.1 ports\n",
276 hu
->hu_UnitNo
, hu
->hu_DevID
, hu
->hu_RootHub11Ports
));
278 hu
->hu_FrameCounter
= 1;
279 hu
->hu_RootHubAddr
= 0;
282 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
283 while (hc
->hc_Node
.ln_Succ
)
285 hc
->hc_Flags
|= HCF_ONLINE
;
286 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
289 // create product name of device
290 CopyMem(product_name
, hu
->hu_ProductName
, sizeof(product_name
));
292 KPRINTF(10, ("Unit allocated!\n"));
298 /* /// "pciFreeUnit()" */
299 void pciFreeUnit(struct PCIUnit
*hu
)
301 struct PCIDevice
*hd
= hu
->hu_Device
;
302 struct PCIController
*hc
;
304 struct TagItem pciDeactivate
[] = {
305 {aHidd_PCIDevice_isIO
, FALSE
},
306 {aHidd_PCIDevice_isMEM
, FALSE
},
307 {aHidd_PCIDevice_isMaster
, FALSE
},
311 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu
));
314 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
315 while (hc
->hc_Node
.ln_Succ
)
317 hc
->hc_Flags
&= ~HCF_ONLINE
;
318 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
321 FreeController(hc
, hu
);
323 // FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT
324 // free anything as below...
325 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
326 while (hc
->hc_Node
.ln_Succ
)
330 HIDD_PCIDriver_FreePCIMem(hc
->hc_PCIDriverObject
,
332 hc
->hc_PCIMem
= NULL
;
334 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
337 // disable and free board
338 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
339 while (hc
->hc_Node
.ln_Succ
)
341 // deactivate busmaster and IO/Mem
342 OOP_SetAttrs(hc
->hc_PCIDeviceObject
, (struct TagItem
*)pciDeactivate
);
343 if (hc
->hc_PCIIntHandler
.is_Node
.ln_Name
)
345 RemIntServer(INTB_KERNEL
+ hc
->hc_PCIIntLine
,
346 &hc
->hc_PCIIntHandler
);
347 hc
->hc_PCIIntHandler
.is_Node
.ln_Name
= NULL
;
349 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
354 /* /// "pciExpunge()" */
355 void pciExpunge(struct PCIDevice
*hd
)
357 struct PCIController
*hc
;
360 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd
));
362 hu
= (struct PCIUnit
*)hd
->hd_Units
.lh_Head
;
363 while (((struct Node
*)hu
)->ln_Succ
)
365 Remove((struct Node
*)hu
);
366 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
367 while (hc
->hc_Node
.ln_Succ
)
369 Remove(&hc
->hc_Node
);
370 FreePooled(hd
->hd_MemPool
, hc
, sizeof(struct PCIController
));
371 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
373 FreePooled(hd
->hd_MemPool
, hu
, sizeof(struct PCIUnit
));
374 hu
= (struct PCIUnit
*)hd
->hd_Units
.lh_Head
;
378 struct OOP_ABDescr attrbases
[] = {
379 {(STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
380 {(STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
384 OOP_ReleaseAttrBases(attrbases
);
386 OOP_DisposeObject(hd
->hd_PCIHidd
);
391 /* /// "pciGetPhysical()" */
392 APTR
pciGetPhysical(struct PCIController
*hc
, APTR virtaddr
)
394 //struct PCIDevice *hd = hc->hc_Device;
395 return HIDD_PCIDriver_CPUtoPCI(hc
->hc_PCIDriverObject
, virtaddr
);
400 * Process some AROS-specific arguments.
401 * 'usbpoweron' helps to bring up USB ports on IntelMac,
402 * whose firmware sets them up incorrectly.
404 static int getArguments(struct PCIDevice
*base
)
408 ACPI_TABLE_HEADER
*dsdt
;
412 * Use ACPI IDs to identify known machines which need HDF_FORCEPOWER
413 * to work. Currently we know only MacMini.
415 err
= AcpiGetTable("DSDT", 1, &dsdt
);
417 /* Yes, the last byte in ID is zero */
418 if (strcmp(dsdt
->OemTableId
, "Macmini") == 0)
420 base
->hd_Flags
= HDF_FORCEPOWER
;
426 BootLoaderBase
= OpenResource("bootloader.resource");
429 struct List
*args
= GetBootInfo(BL_Args
);
435 for (node
= args
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
437 if (stricmp(node
->ln_Name
, "forceusbpower") == 0)
439 base
->hd_Flags
= HDF_FORCEPOWER
;
449 ADD2INITLIB(getArguments
, 10)