-Use PCI hidd stubs for reading/writing config memory
[AROS.git] / rom / usb / pciusbhc / uhci / pci_aros.c
blob9efa9552e3af2a69d0c1f188031886bfb151b02e
1 /* pci_aros.c - pci access abstraction for AROS by Chris Hodges
2 */
4 #include <aros/bootloader.h>
5 #include <aros/symbolsets.h>
6 #include <exec/types.h>
7 #include <oop/oop.h>
8 #include <devices/timer.h>
9 #include <hidd/hidd.h>
10 #include <hidd/pci.h>
11 #include <hidd/irq.h>
12 #include <proto/bootloader.h>
13 #include <proto/oop.h>
14 #include <proto/utility.h>
15 #include <proto/exec.h>
17 #include <inttypes.h>
18 #include <string.h>
20 #include "uhwcmd.h"
22 #undef HiddPCIDeviceAttrBase
23 #undef HiddAttrBase
25 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
26 #define HiddAttrBase (hd->hd_HiddAB)
28 #define PCI_BASE_CLASS_SERIAL 0x0c
29 #define PCI_SUB_CLASS_USB 0x03
30 #define PCI_INTERFACE_UHCI 0x00
32 AROS_UFH3(void, pciEnumerator,
33 AROS_UFHA(struct Hook *, hook, A0),
34 AROS_UFHA(OOP_Object *, pciDevice, A2),
35 AROS_UFHA(APTR, message, A1))
37 AROS_USERFUNC_INIT
39 struct PCIDevice *hd = (struct PCIDevice *) hook->h_Data;
40 struct PCIController *hc;
41 IPTR hcitype;
42 IPTR bus;
43 IPTR dev;
44 IPTR sub;
45 IPTR intline;
46 ULONG devid;
48 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Interface, &hcitype);
49 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Bus, &bus);
50 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &dev);
51 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &sub);
52 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &intline);
54 devid = (bus<<16)|dev;
56 KPRINTF(10, ("Found PCI device 0x%lx of type %ld, Intline=%ld\n", devid, hcitype, intline));
58 if(intline == 255) {
59 // we can't work without the correct interrupt line
60 // BIOS needs plug & play os option disabled. Alternatively AROS must support APIC reconfiguration
61 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned by BIOS, disable Plug & Play OS!\n"));
62 }else{
63 KPRINTF(10, ("Setting up device...\n"));
65 hc = AllocPooled(hd->hd_MemPool, sizeof(struct PCIController));
66 if (hc) {
67 hc->hc_Device = hd;
68 hc->hc_DevID = devid;
69 hc->hc_FunctionNum = sub;
70 hc->hc_HCIType = hcitype;
71 hc->hc_PCIDeviceObject = pciDevice;
72 hc->hc_PCIIntLine = intline;
74 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (IPTR *) &hc->hc_PCIDriverObject);
76 NEWLIST(&hc->hc_CtrlXFerQueue);
77 NEWLIST(&hc->hc_IntXFerQueue);
78 NEWLIST(&hc->hc_IsoXFerQueue);
79 NEWLIST(&hc->hc_BulkXFerQueue);
81 NEWLIST(&hc->hc_TDQueue);
82 NEWLIST(&hc->hc_AbortQueue);
83 NEWLIST(&hc->hc_PeriodicTDQueue);
85 AddTail(&hd->hd_TempHCIList, &hc->hc_Node);
89 AROS_USERFUNC_EXIT
92 BOOL pciInit(struct PCIDevice *hd) {
93 struct PCIController *hc;
94 struct PCIController *nexthc;
95 struct PCIUnit *hu;
96 ULONG unitno = 0;
98 KPRINTF(10, ("*** pciInit(%p) ***\n", hd));
100 NEWLIST(&hd->hd_TempHCIList);
102 if(!(hd->hd_IRQHidd = OOP_NewObject(NULL, (STRPTR) CLID_Hidd_IRQ, NULL))) {
103 KPRINTF(20, ("Unable to create IRQHidd object!\n"));
104 return FALSE;
107 if((hd->hd_PCIHidd = OOP_NewObject(NULL, (STRPTR) CLID_Hidd_PCI, NULL))) {
108 struct TagItem tags[] = {
109 { tHidd_PCI_Class, PCI_BASE_CLASS_SERIAL },
110 { tHidd_PCI_SubClass, PCI_SUB_CLASS_USB },
111 { tHidd_PCI_Interface, PCI_INTERFACE_UHCI },
112 { TAG_DONE, 0UL }
115 struct OOP_ABDescr attrbases[] = {
116 { (STRPTR) IID_Hidd, &hd->hd_HiddAB },
117 { (STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB },
118 { NULL, NULL }
121 struct Hook findHook = {
122 h_Entry: (IPTR (*)()) pciEnumerator,
123 h_Data: hd,
126 OOP_ObtainAttrBases(attrbases);
128 KPRINTF(20, ("Searching for devices...\n"));
130 HIDD_PCI_EnumDevices(hd->hd_PCIHidd, &findHook, (struct TagItem *) &tags);
131 } else {
132 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
133 OOP_DisposeObject(hd->hd_IRQHidd);
134 return FALSE;
137 // Create units with a list of host controllers having the same bus and device number.
138 while(hd->hd_TempHCIList.lh_Head->ln_Succ) {
139 hu = AllocPooled(hd->hd_MemPool, sizeof(struct PCIUnit));
140 if(!hu) {
141 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
142 return FALSE;
144 hu->hu_Device = hd;
145 hu->hu_UnitNo = unitno;
146 hu->hu_DevID = ((struct PCIController *) hd->hd_TempHCIList.lh_Head)->hc_DevID;
148 NEWLIST(&hu->hu_Controllers);
149 NEWLIST(&hu->hu_RHIOQueue);
151 hc = (struct PCIController *) hd->hd_TempHCIList.lh_Head;
152 while((nexthc = (struct PCIController *) hc->hc_Node.ln_Succ)) {
153 if(hc->hc_DevID == hu->hu_DevID) {
154 Remove(&hc->hc_Node);
155 hc->hc_Unit = hu;
156 AddTail(&hu->hu_Controllers, &hc->hc_Node);
158 hc = nexthc;
160 AddTail(&hd->hd_Units, (struct Node *) hu);
161 unitno++;
163 return TRUE;
166 BOOL pciAllocUnit(struct PCIUnit *hu) {
168 struct PCIController *hc;
170 BOOL allocgood = TRUE;
171 ULONG usb11ports = 0;
173 ULONG cnt;
175 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu));
177 // allocate necessary memory
178 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
179 while(hc->hc_Node.ln_Succ) {
180 allocgood = uhciInit(hc,hu);
181 if(allocgood) {
182 for(cnt = usb11ports; cnt < usb11ports + hc->hc_NumPorts; cnt++) {
183 hu->hu_PortMap11[cnt] = hc;
184 hu->hu_PortNum11[cnt] = cnt - usb11ports;
185 hc->hc_PortNumGlobal[cnt - usb11ports] = cnt;
186 KPRINTF2(200,("Mapping ports\n"));
187 KPRINTF2(200,(" Map11[%ld]= %p\n", cnt, hc));
188 KPRINTF2(200,(" Num11[%ld]= %ld\n", cnt, (cnt-usb11ports)));
189 KPRINTF2(200,(" Glo11[%ld]= %ld\n", (cnt-usb11ports), cnt));
191 usb11ports += hc->hc_NumPorts;
192 }else{
193 return FALSE;
195 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
198 hu->hu_RootHubPorts = usb11ports;
199 hu->hu_RootHubAddr = 0;
201 // put em online
202 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
203 while(hc->hc_Node.ln_Succ) {
204 hc->hc_Flags |= HCF_ONLINE;
205 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
208 KPRINTF(10, ("Unit allocated!\n"));
210 return TRUE;
213 void pciFreeUnit(struct PCIUnit *hu) {
214 struct PCIDevice *hd = hu->hu_Device;
215 struct PCIController *hc;
217 struct TagItem pciDeactivate[] = {
218 { aHidd_PCIDevice_isIO, FALSE },
219 { aHidd_PCIDevice_isMEM, FALSE },
220 { aHidd_PCIDevice_isMaster, FALSE },
221 { TAG_DONE, 0UL },
224 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu));
226 // put em offline
227 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
228 while(hc->hc_Node.ln_Succ)
230 hc->hc_Flags &= ~HCF_ONLINE;
231 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
234 uhciFree(hc, hu);
236 //FIXME: uhciFree routine actually ONLY stops the chip NOT free anything as code below...
237 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
238 while(hc->hc_Node.ln_Succ) {
239 if(hc->hc_PCIMem) {
240 HIDD_PCIDriver_FreePCIMem(hc->hc_PCIDriverObject, hc->hc_PCIMem);
241 hc->hc_PCIMem = NULL;
243 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
246 // disable and free board
247 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
248 while(hc->hc_Node.ln_Succ)
250 OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciDeactivate); // deactivate busmaster and IO/Mem
251 if(hc->hc_PCIIntHandler.h_Node.ln_Name) {
252 HIDD_IRQ_RemHandler(hd->hd_IRQHidd, &hc->hc_PCIIntHandler);
253 hc->hc_PCIIntHandler.h_Node.ln_Name = NULL;
256 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
260 void pciExpunge(struct PCIDevice *hd) {
261 struct PCIController *hc;
262 struct PCIUnit *hu;
264 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd));
266 hu = (struct PCIUnit *) hd->hd_Units.lh_Head;
267 while(((struct Node *) hu)->ln_Succ) {
268 Remove((struct Node *) hu);
269 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
270 while(hc->hc_Node.ln_Succ) {
271 Remove(&hc->hc_Node);
272 FreePooled(hd->hd_MemPool, hc, sizeof(struct PCIController));
273 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
275 FreePooled(hd->hd_MemPool, hu, sizeof(struct PCIUnit));
276 hu = (struct PCIUnit *) hd->hd_Units.lh_Head;
278 if(hd->hd_PCIHidd) {
279 struct OOP_ABDescr attrbases[] =
281 { (STRPTR) IID_Hidd, &hd->hd_HiddAB },
282 { (STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB },
283 { NULL, NULL }
286 OOP_ReleaseAttrBases(attrbases);
288 OOP_DisposeObject(hd->hd_PCIHidd);
290 if(hd->hd_IRQHidd) {
291 OOP_DisposeObject(hd->hd_IRQHidd);
295 APTR pciGetPhysical(struct PCIController *hc, APTR virtaddr) {
296 //struct PCIDevice *hd = hc->hc_Device;
297 return(HIDD_PCIDriver_CPUtoPCI(hc->hc_PCIDriverObject, virtaddr));
301 * Process some AROS-specific arguments.
302 * 'usbpoweron' helps to bring up USB ports on IntelMac,
303 * whose firmware sets them up incorrectly.
305 static int getArguments(struct PCIDevice *base) {
306 APTR BootLoaderBase = OpenResource("bootloader.resource");
308 if (BootLoaderBase)
310 struct List *args = GetBootInfo(BL_Args);
312 if (args)
314 struct Node *node;
316 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
318 if (stricmp(node->ln_Name, "forceusbpower") == 0)
320 base->hd_Flags = HDF_FORCEPOWER;
321 break;
327 return TRUE;
330 ADD2INITLIB(getArguments, 10)