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>
13 #include <resources/acpi.h>
15 #include <proto/acpi.h>
16 #include <proto/bootloader.h>
17 #include <proto/oop.h>
18 #include <proto/utility.h>
19 #include <proto/exec.h>
20 #include <clib/alib_protos.h>
28 #include "chip_protos.h"
29 #include "cmd_protos.h"
38 #undef HiddPCIDeviceAttrBase
41 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
42 #define HiddAttrBase (hd->hd_HiddAB)
44 static TEXT product_name
[] = "PCI OHCI USB 1.1 Host Controller";
46 AROS_UFH3(void, pciEnumerator
,
47 AROS_UFHA(struct Hook
*, hook
, A0
),
48 AROS_UFHA(OOP_Object
*, pciDevice
, A2
), AROS_UFHA(APTR
, message
, A1
))
52 struct PCIDevice
*hd
= (struct PCIDevice
*)hook
->h_Data
;
53 struct PCIController
*hc
;
61 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Bus
, &bus
);
62 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &dev
);
63 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &sub
);
64 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &intline
);
66 devid
= (bus
<< 16) | dev
;
68 KPRINTF(10, ("Found PCI device 0x%lx Intline=%ld\n", devid
, intline
));
72 // we can't work without the correct interrupt line.
73 // BIOS needs plug & play os option disabled.
74 // Alternatively AROS must support APIC reconfiguration
75 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned "
76 "by BIOS, disable Plug & Play OS!\n"));
80 KPRINTF(10, ("Setting up device...\n"));
82 hc
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIController
));
87 hc
->hc_FunctionNum
= sub
;
88 hc
->hc_PCIDeviceObject
= pciDevice
;
89 hc
->hc_PCIIntLine
= intline
;
91 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
,
92 (IPTR
*) & hc
->hc_PCIDriverObject
);
94 for (i
= 0; i
< XFER_COUNT
; i
++)
95 NewList(&hc
->hc_XferQueues
[i
]);
96 NewList(&hc
->hc_TDQueue
);
97 NewList(&hc
->hc_AbortQueue
);
98 NewList(&hc
->hc_PeriodicTDQueue
);
99 NewList(&hc
->hc_RetireQueue
);
100 AddTail(&hd
->hd_TempHCIList
, &hc
->hc_Node
);
107 /* /// "pciInit()" */
108 BOOL
pciInit(struct PCIDevice
*hd
)
110 struct PCIController
*hc
;
111 struct PCIController
*nexthc
;
115 KPRINTF(10, ("*** pciInit(%p) ***\n", hd
));
117 NewList(&hd
->hd_TempHCIList
);
119 if ((hd
->hd_PCIHidd
=
120 OOP_NewObject(NULL
, (STRPTR
) CLID_Hidd_PCI
, NULL
)))
122 struct TagItem tags
[] = {
123 {tHidd_PCI_Class
, (PCI_CLASS_SERIAL_USB
>> 8) & 0xff},
124 {tHidd_PCI_SubClass
, (PCI_CLASS_SERIAL_USB
& 0xff)},
125 {tHidd_PCI_Interface
, 0x10},
129 struct OOP_ABDescr attrbases
[] = {
130 {(STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
131 {(STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
135 struct Hook findHook
= {
136 h_Entry
:(IPTR(*)())pciEnumerator
,
140 OOP_ObtainAttrBases(attrbases
);
142 KPRINTF(20, ("Searching for devices...\n"));
144 HIDD_PCI_EnumDevices(hd
->hd_PCIHidd
, &findHook
,
145 (struct TagItem
*)&tags
);
149 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
153 // Create units with a list of host controllers having the same bus
154 // and device number.
155 while (hd
->hd_TempHCIList
.lh_Head
->ln_Succ
)
157 hu
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIUnit
));
160 // actually, we should get rid of the allocated memory first,
161 // but we don't care as DeletePool() will take care of this
166 hu
->hu_UnitNo
= unitno
;
168 ((struct PCIController
*)hd
->hd_TempHCIList
.lh_Head
)->hc_DevID
;
170 NewList(&hu
->hu_Controllers
);
171 NewList(&hu
->hu_RHIOQueue
);
173 hc
= (struct PCIController
*)hd
->hd_TempHCIList
.lh_Head
;
174 while ((nexthc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
))
176 if (hc
->hc_DevID
== hu
->hu_DevID
)
178 Remove(&hc
->hc_Node
);
180 AddTail(&hu
->hu_Controllers
, &hc
->hc_Node
);
184 AddTail(&hd
->hd_Units
, (struct Node
*)hu
);
191 /* /// "pciAllocUnit()" */
192 BOOL
pciAllocUnit(struct PCIUnit
* hu
)
194 struct PCIController
*hc
;
196 BOOL allocgood
= TRUE
;
197 ULONG usb11ports
= 0;
198 ULONG usb20ports
= 0;
203 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu
));
205 // allocate necessary memory
206 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
207 while (hc
->hc_Node
.ln_Succ
)
209 allocgood
= InitController(hc
, hu
);
215 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
223 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
224 while (hc
->hc_Node
.ln_Succ
)
226 if (hc
->hc_complexrouting
)
229 for (cnt
= 0; cnt
< usb20ports
; cnt
++)
231 if (((hc
->hc_portroute
>> (cnt
<< 2)) & 0xf) ==
235 ("CHC %ld Port %ld assigned to global Port %ld\n",
236 hc
->hc_FunctionNum
, locport
, cnt
));
237 hu
->hu_PortMap11
[cnt
] = hc
;
238 hu
->hu_PortNum11
[cnt
] = locport
;
239 hc
->hc_PortNum20
[locport
] = cnt
;
246 for (cnt
= usb11ports
; cnt
< usb11ports
+ hc
->hc_NumPorts
;
249 hu
->hu_PortMap11
[cnt
] = hc
;
250 hu
->hu_PortNum11
[cnt
] = cnt
- usb11ports
;
251 hc
->hc_PortNum20
[cnt
- usb11ports
] = cnt
;
254 usb11ports
+= hc
->hc_NumPorts
;
255 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
257 if ((usb11ports
!= usb20ports
) && usb20ports
)
260 ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n",
261 usb20ports
, usb11ports
));
264 hu
->hu_RootHub11Ports
= usb11ports
;
265 hu
->hu_RootHub20Ports
= usb20ports
;
266 hu
->hu_RootHubPorts
=
267 (usb11ports
> usb20ports
) ? usb11ports
: usb20ports
;
268 for (cnt
= 0; cnt
< hu
->hu_RootHubPorts
; cnt
++)
270 hu
->hu_EhciOwned
[cnt
] = hu
->hu_PortMap20
[cnt
] ? TRUE
: FALSE
;
273 KPRINTF(10, ("Unit %ld: USB Board %08lx has %ld USB1.1 ports\n",
274 hu
->hu_UnitNo
, hu
->hu_DevID
, hu
->hu_RootHub11Ports
));
276 hu
->hu_FrameCounter
= 1;
277 hu
->hu_RootHubAddr
= 0;
280 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
281 while (hc
->hc_Node
.ln_Succ
)
283 hc
->hc_Flags
|= HCF_ONLINE
;
284 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
287 // create product name of device
288 CopyMem(product_name
, hu
->hu_ProductName
, sizeof(product_name
));
290 KPRINTF(10, ("Unit allocated!\n"));
296 /* /// "pciFreeUnit()" */
297 void pciFreeUnit(struct PCIUnit
*hu
)
299 struct PCIDevice
*hd
= hu
->hu_Device
;
300 struct PCIController
*hc
;
302 struct TagItem pciDeactivate
[] = {
303 {aHidd_PCIDevice_isIO
, FALSE
},
304 {aHidd_PCIDevice_isMEM
, FALSE
},
305 {aHidd_PCIDevice_isMaster
, FALSE
},
309 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu
));
312 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
313 while (hc
->hc_Node
.ln_Succ
)
315 hc
->hc_Flags
&= ~HCF_ONLINE
;
316 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
319 FreeController(hc
, hu
);
321 // FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT
322 // free anything as below...
323 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
324 while (hc
->hc_Node
.ln_Succ
)
328 HIDD_PCIDriver_FreePCIMem(hc
->hc_PCIDriverObject
,
330 hc
->hc_PCIMem
= NULL
;
332 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
335 // disable and free board
336 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
337 while (hc
->hc_Node
.ln_Succ
)
339 // deactivate busmaster and IO/Mem
340 OOP_SetAttrs(hc
->hc_PCIDeviceObject
, (struct TagItem
*)pciDeactivate
);
341 if (hc
->hc_PCIIntHandler
.is_Node
.ln_Name
)
343 RemIntServer(INTB_KERNEL
+ hc
->hc_PCIIntLine
,
344 &hc
->hc_PCIIntHandler
);
345 hc
->hc_PCIIntHandler
.is_Node
.ln_Name
= NULL
;
347 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
352 /* /// "pciExpunge()" */
353 void pciExpunge(struct PCIDevice
*hd
)
355 struct PCIController
*hc
;
358 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd
));
360 hu
= (struct PCIUnit
*)hd
->hd_Units
.lh_Head
;
361 while (((struct Node
*)hu
)->ln_Succ
)
363 Remove((struct Node
*)hu
);
364 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
365 while (hc
->hc_Node
.ln_Succ
)
367 Remove(&hc
->hc_Node
);
368 FreePooled(hd
->hd_MemPool
, hc
, sizeof(struct PCIController
));
369 hc
= (struct PCIController
*)hu
->hu_Controllers
.lh_Head
;
371 FreePooled(hd
->hd_MemPool
, hu
, sizeof(struct PCIUnit
));
372 hu
= (struct PCIUnit
*)hd
->hd_Units
.lh_Head
;
376 struct OOP_ABDescr attrbases
[] = {
377 {(STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
378 {(STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
382 OOP_ReleaseAttrBases(attrbases
);
384 OOP_DisposeObject(hd
->hd_PCIHidd
);
389 /* /// "pciGetPhysical()" */
390 APTR
pciGetPhysical(struct PCIController
*hc
, APTR virtaddr
)
392 //struct PCIDevice *hd = hc->hc_Device;
393 return HIDD_PCIDriver_CPUtoPCI(hc
->hc_PCIDriverObject
, virtaddr
);
398 * Process some AROS-specific arguments.
399 * 'usbpoweron' helps to bring up USB ports on IntelMac,
400 * whose firmware sets them up incorrectly.
402 static int getArguments(struct PCIDevice
*base
)
406 struct ACPIBase
*ACPIBase
;
408 ACPIBase
= OpenResource("acpi.resource");
412 * Use ACPI IDs to identify known machines which need HDF_FORCEPOWER
413 * to work. Currently we know only MacMini.
415 struct ACPI_TABLE_DEF_HEADER
*dsdt
=
416 ACPI_FindSDT(ACPI_MAKE_ID('D', 'S', 'D', 'T'));
420 /* Yes, the last byte in ID is zero */
421 if (strcmp(dsdt
->oem_table_id
, "Macmini") == 0)
423 base
->hd_Flags
= HDF_FORCEPOWER
;
430 BootLoaderBase
= OpenResource("bootloader.resource");
433 struct List
*args
= GetBootInfo(BL_Args
);
439 for (node
= args
->lh_Head
; node
->ln_Succ
; node
= node
->ln_Succ
)
441 if (stricmp(node
->ln_Name
, "forceusbpower") == 0)
443 base
->hd_Flags
= HDF_FORCEPOWER
;
453 ADD2INITLIB(getArguments
, 10)