includes: AROS_UFIxx -> AROS_INTxx change
[AROS.git] / workbench / devs / USB / drivers / OHCI / ohciclass.c
blob6055cfc05db78d3fc7e5a0c78e0d9d4fe2e5f7bb
1 /*
2 Copyright (C) 2006 by Michal Schulz
3 $Id$
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the
17 Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #define DEBUG 1
23 #include <inttypes.h>
25 #include <exec/types.h>
26 #include <exec/ports.h>
27 #include <oop/oop.h>
28 #include <usb/usb.h>
29 #include <utility/tagitem.h>
30 #include <aros/debug.h>
31 #include <aros/symbolsets.h>
33 #include <devices/timer.h>
35 #include <hidd/hidd.h>
36 #include <hidd/pci.h>
38 #include <proto/oop.h>
39 #include <proto/utility.h>
40 #include <proto/exec.h>
42 #include "ohci.h"
44 static const usb_hub_descriptor_t hub_descriptor = {
45 bDescLength: sizeof(usb_hub_descriptor_t) - 31,
46 bDescriptorType: UDESC_HUB,
47 bNbrPorts: 2,
48 wHubCharacteristics:0,
49 bPwrOn2PwrGood: 50,
50 bHubContrCurrent: 0,
51 DeviceRemovable: {0,},
54 AROS_INTP(OHCI_HubInterrupt);
55 AROS_INTP(ohci_Handler);
57 OOP_Object *METHOD(OHCI, Root, New)
59 int success = 0;
60 D(bug("[OHCI] OHCI::New()\n"));
62 BASE(cl->UserData)->LibNode.lib_OpenCnt++;
64 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
65 if (o)
67 ohci_data_t *ohci = OOP_INST_DATA(cl, o);
68 int i;
70 ohci->pendingRHSC = 1;
71 ohci->tr = ohci_CreateTimer();
72 ohci->running = 0;
74 NEWLIST(&ohci->intList);
76 NEWLIST(&ohci->timerPort.mp_MsgList);
77 ohci->timerPort.mp_Flags = PA_SOFTINT;
78 ohci->timerPort.mp_Node.ln_Type = NT_MSGPORT;
79 ohci->timerPort.mp_SigTask = &ohci->timerInt;
80 ohci->timerInt.is_Code = (VOID_FUNC)OHCI_HubInterrupt;
81 ohci->timerInt.is_Data = ohci;
83 ohci->timerReq = CreateIORequest(&ohci->timerPort, sizeof(struct timerequest));
84 OpenDevice((STRPTR)"timer.device", UNIT_VBLANK, (struct IORequest *)ohci->timerReq, 0);
86 ohci->regs = (ohci_registers_t *)GetTagData(aHidd_OHCI_MemBase, 0, msg->attrList);
87 ohci->pciDriver = (OOP_Object *)GetTagData(aHidd_OHCI_PCIDriver, 0, msg->attrList);
88 ohci->pciDevice = (OOP_Object *)GetTagData(aHidd_OHCI_PCIDevice, 0, msg->attrList);
89 ohci->irqNum = GetTagData(aHidd_OHCI_IRQ, 0, msg->attrList);
91 ohci->hcca = HIDD_PCIDriver_AllocPCIMem(ohci->pciDriver, 4096);
93 CopyMem(&hub_descriptor, &ohci->hubDescr, sizeof(usb_hub_descriptor_t));
94 ohci->hubDescr.bNbrPorts = GetTagData(aHidd_USBHub_NumPorts, 0, msg->attrList);
95 ohci->hubDescr.wHubCharacteristics = AROS_WORD2LE(UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL);
97 ohci->irqHandler.is_Node.ln_Name = "UHCI Intr";
98 ohci->irqHandler.is_Node.ln_Pri = 127;
99 ohci->irqHandler.is_Node.ln_Type = NT_INTERRUPT;
100 ohci->irqHandler.is_Code = (VOID_FUNC)ohci_Handler;
101 ohci->irqHandler.is_Data = ohci;
103 AddIntServer(INTB_KERNEL + ohci->irqNum, &ohci->irqHandler);
104 D(bug("[OHCI] IRQHandler = %08x int = %d\n", ohci->irqHandler, ohci->irqNum));
106 D(bug("[OHCI] New(): o=%p, ports=%d, regs=%p, drv=%p, dev=%p, hcca=%p\n", o,
107 ohci->hubDescr.bNbrPorts, ohci->regs, ohci->pciDriver, ohci->pciDevice,
108 ohci->hcca));
110 ohci->sd = SD(cl);
112 if (ohci->tmp)
113 AddTail(&ohci->intList, &ohci->tmp->is_Node);
115 /* Allocate empty endpoint descriptors for chaining */
116 ohci->ctrl_head = ohci_AllocED(cl, o);
117 ohci->ctrl_head->edFlags = AROS_LONG2OHCI(ED_K);
118 ohci->ctrl_head->edNextED = 0;
119 CacheClearE(ohci->ctrl_head, sizeof(ohci_ed_t), CACRF_ClearD);
121 ohci->bulk_head = ohci_AllocED(cl, o);
122 ohci->bulk_head->edFlags = AROS_LONG2OHCI(ED_K);
123 ohci->bulk_head->edNextED = 0;
124 CacheClearE(ohci->bulk_head, sizeof(ohci_ed_t), CACRF_ClearD);
126 ohci->isoc_head = ohci_AllocED(cl, o);
127 ohci->isoc_head->edFlags = AROS_LONG2OHCI(ED_K);
128 ohci->isoc_head->edNextED = 0;
129 CacheClearE(ohci->isoc_head, sizeof(ohci_ed_t), CACRF_ClearD);
132 * The endpoints for interrupts.
134 * There are 63 endpoint descriptors used for interrupt
135 * transfers. They form a tree, with several pooling rates
136 * ranging from 1ms to 32ms. The 1ms endpoint points to the
137 * isochronous queue.
139 ohci->int01 = ohci_AllocED(cl, o);
140 ohci->int01->edFlags = AROS_LONG2OHCI(ED_K);
141 ohci->int01->edNextED = AROS_LONG2OHCI((uint32_t)ohci->isoc_head);
142 CacheClearE(ohci->int01, sizeof(ohci_ed_t), CACRF_ClearD);
144 for (i=0; i < 2; i++)
146 ohci->int02[i] = ohci_AllocED(cl, o);
147 ohci->int02[i]->edFlags = AROS_LONG2OHCI(ED_K);
148 ohci->int02[i]->edNextED = AROS_LONG2OHCI((uint32_t)ohci->int01);
149 CacheClearE(ohci->int02[i], sizeof(ohci_ed_t), CACRF_ClearD);
152 for (i=0; i < 4; i++)
154 ohci->int04[i] = ohci_AllocED(cl, o);
155 ohci->int04[i]->edFlags = AROS_LONG2OHCI(ED_K);
156 ohci->int04[i]->edNextED = AROS_LONG2OHCI((uint32_t)ohci->int02[i & 0x01]);
157 CacheClearE(ohci->int04[i], sizeof(ohci_ed_t), CACRF_ClearD);
160 for (i=0; i < 8; i++)
162 ohci->int08[i] = ohci_AllocED(cl, o);
163 ohci->int08[i]->edFlags = AROS_LONG2OHCI(ED_K);
164 ohci->int08[i]->edNextED = AROS_LONG2OHCI((uint32_t)ohci->int04[i & 0x03]);
165 CacheClearE(ohci->int08[i], sizeof(ohci_ed_t), CACRF_ClearD);
168 for (i=0; i < 16; i++)
170 ohci->int16[i] = ohci_AllocED(cl, o);
171 ohci->int16[i]->edFlags = AROS_LONG2OHCI(ED_K);
172 ohci->int16[i]->edNextED = AROS_LONG2OHCI((uint32_t)ohci->int08[i & 0x07]);
173 CacheClearE(ohci->int16[i], sizeof(ohci_ed_t), CACRF_ClearD);
176 for (i=0; i < 32; i++)
178 ohci->int32[i] = ohci_AllocED(cl, o);
179 ohci->int32[i]->edFlags = AROS_LONG2OHCI(ED_K);
180 ohci->int32[i]->edNextED = AROS_LONG2OHCI((uint32_t)ohci->int16[i & 0x0f]);
181 CacheClearE(ohci->int32[i], sizeof(ohci_ed_t), CACRF_ClearD);
183 /* Link this pointers with HCCA table */
184 ohci->hcca->hccaIntrTab[i] = AROS_LONG2OHCI((uint32_t)ohci->int32[i]);
186 CacheClearE((APTR)ohci->hcca, sizeof(ohci_hcca_t), CACRF_ClearD);
188 /* Reset OHCI */
191 * Preserve some registers which were set by BIOS. I will have
192 * to get rid of it pretty soon
194 uint32_t ctl = AROS_OHCI2LONG(mmio(ohci->regs->HcControl));
195 uint32_t rwc = ctl | HC_CTRL_RWC;
196 uint32_t fm = AROS_OHCI2LONG(mmio(ohci->regs->HcFmInterval));
197 uint32_t desca = AROS_OHCI2LONG(mmio(ohci->regs->HcRhDescriptorA));
198 uint32_t descb = AROS_OHCI2LONG(mmio(ohci->regs->HcRhDescriptorB));
200 D(bug("[OHCI] ctl=%08x fm=%08x desca=%08x descb=%08x\n", ctl,fm,desca,descb));
202 desca &= ~HC_RHA_NPS;
203 desca |= HC_RHA_PSM;
204 descb |= 0x7fff0000;
207 for (i=0; i < ohci->hubDescr.bNbrPorts; i++)
209 mmio(ohci->regs->HcRhPortStatus[i]) = AROS_LONG2OHCI(UPS_LOW_SPEED);
210 ohci_Delay(ohci->tr, ohci->hubDescr.bPwrOn2PwrGood * UHD_PWRON_FACTOR + USB_EXTRA_POWER_UP_TIME);
213 mmio(ohci->regs->HcControl) = AROS_LONG2OHCI(rwc | HC_CTRL_HCFS_RESET);
214 ohci_Delay(ohci->tr, USB_BUS_RESET_DELAY);
216 mmio(ohci->regs->HcCommandStatus) = AROS_LONG2OHCI(HC_CS_HCR);
217 for (i=0; i < 10; i++)
219 ohci_Delay(ohci->tr, 1);
220 if (!(mmio(ohci->regs->HcCommandStatus) & AROS_LONG2OHCI(HC_CS_HCR)))
221 break;
224 if (i==10)
225 D(bug("[OHCI] Reset not ready...\n"));
227 /* Initial setup of OHCI */
228 D(bug("[OHCI] Initial setup\n"));
230 mmio(ohci->regs->HcHCCA) = AROS_LONG2OHCI((uint32_t)ohci->hcca);
231 mmio(ohci->regs->HcBulkHeadED) = AROS_LONG2OHCI((uint32_t)ohci->bulk_head);
232 mmio(ohci->regs->HcControlHeadED) = AROS_LONG2OHCI((uint32_t)ohci->ctrl_head);
233 mmio(ohci->regs->HcInterruptDisable) = AROS_LONG2OHCI(0xc000007f);
235 ctl = AROS_OHCI2LONG(mmio(ohci->regs->HcControl));
236 ctl &= ~(HC_CTRL_CBSR_MASK | HC_CTRL_HCFS_MASK | HC_CTRL_PLE |
237 HC_CTRL_IE | HC_CTRL_CLE | HC_CTRL_BLE | HC_CTRL_IR );
238 ctl |= HC_CTRL_PLE | HC_CTRL_IE | HC_CTRL_CLE | HC_CTRL_BLE |
239 rwc | HC_CTRL_CBSR_1_4 | HC_CTRL_HCFS_SUSPENDED;
241 /* Start OHCI */
242 mmio(ohci->regs->HcControl) = AROS_LONG2OHCI(ctl);
244 uint32_t ival = HC_FM_GET_IVAL(fm);
245 D(bug("[OHCI] ival=%08x\n", ival));
246 fm = (AROS_OHCI2LONG(mmio(ohci->regs->HcFmRemaining)) & HC_FM_FIT) ^ HC_FM_FIT;
247 fm |= HC_FM_FSMPS(ival) | ival;
248 D(bug("[OHCI] fm=%08x\n", fm));
249 mmio(ohci->regs->HcFmInterval) = AROS_LONG2OHCI(fm);
250 uint32_t per = HC_PERIODIC(ival);
251 mmio(ohci->regs->HcPeriodicStart) = AROS_LONG2OHCI(per);
252 D(bug("[OHCI] periodic start=%08x\n", per));
254 mmio(ohci->regs->HcRhDescriptorA) = AROS_LONG2OHCI(desca | HC_RHA_NOCP);
255 mmio(ohci->regs->HcRhStatus) = AROS_LONG2OHCI(HC_RHS_LPS);
256 ohci_Delay(ohci->tr, 5);
257 mmio(ohci->regs->HcRhDescriptorA) = AROS_LONG2OHCI(desca);
258 mmio(ohci->regs->HcRhDescriptorB) = AROS_LONG2OHCI(descb);
260 if (HC_RHA_GET_POTPGT(desca) != 0)
262 D(bug("[OHCI] delay=%d\n", HC_RHA_GET_POTPGT(desca) * UHD_PWRON_FACTOR));
263 ohci_Delay(ohci->tr, HC_RHA_GET_POTPGT(desca) * UHD_PWRON_FACTOR);
266 /* Enable interrupts */
267 mmio(ohci->regs->HcInterruptEnable) = AROS_LONG2OHCI(HC_INTR_MIE | HC_INTR_SO | HC_INTR_WDH |
268 HC_INTR_RD | HC_INTR_UE | HC_INTR_RHSC);
270 D(bug("[OHCI] OHCI controller up and running.\n"));
271 success = TRUE;
274 if (!success)
276 OOP_MethodID mID = OOP_GetMethodID((STRPTR)IID_Root, moRoot_Dispose);
277 OOP_CoerceMethod(cl, o, (OOP_Msg)&mID);
278 o = NULL;
281 D(bug("[OHCI] OHCI::New() = %p\n",o));
283 if (!o)
284 BASE(cl->UserData)->LibNode.lib_OpenCnt--;
286 return o;
289 void METHOD(OHCI, Root, Dispose)
291 ohci_data_t *ohci = OOP_INST_DATA(cl, o);
292 struct Library *base = &BASE(cl->UserData)->LibNode;
294 ohci_DeleteTimer(ohci->tr);
296 D(bug("[OHCI] OHCI::Dispose\n"));
298 OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
300 base->lib_OpenCnt--;
303 void METHOD(OHCI, Root, Get)
305 uint32_t idx;
307 if (IS_USBDEVICE_ATTR(msg->attrID, idx))
309 switch (idx)
311 case aoHidd_USBDevice_Address:
312 *msg->storage = 1;
313 break;
314 case aoHidd_USBDevice_Hub:
315 *msg->storage = 0;
316 break;
317 case aoHidd_USBDevice_Bus:
318 *msg->storage = (intptr_t)o;
319 break;
320 default:
321 OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
324 else
325 OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
328 /* Class initialization and destruction */
330 #undef SD
331 #define SD(x) (&LIBBASE->sd)
333 static int OHCI_InitClass(LIBBASETYPEPTR LIBBASE)
335 int i;
336 D(bug("[OHCI] InitClass\n"));
338 HiddOHCIAttrBase = OOP_ObtainAttrBase(IID_Drv_USB_OHCI);
340 if (HiddOHCIAttrBase)
342 struct TagItem tags[] = {
343 { aHidd_OHCI_MemBase, 0UL },
344 { aHidd_OHCI_PCIDevice, 0UL },
345 { aHidd_OHCI_PCIDriver, 0UL },
346 { aHidd_OHCI_IRQ, 0UL },
347 { aHidd_USBHub_NumPorts, 0UL },
348 { aHidd_USBHub_IsRoot, 1UL },
349 { aHidd_USBDevice_Address, 1UL },
350 { TAG_DONE, 0UL },
353 for (i=0; i < LIBBASE->sd.numDevices; i++)
355 tags[0].ti_Data = LIBBASE->sd.ramBase[i];
356 tags[1].ti_Data = (intptr_t)LIBBASE->sd.pciDevice[i];
357 tags[2].ti_Data = (intptr_t)LIBBASE->sd.pciDriver[i];
358 tags[3].ti_Data = (intptr_t)LIBBASE->sd.irqNum[i];
359 tags[4].ti_Data = (intptr_t)LIBBASE->sd.numPorts[i];
361 D(bug("[OHCI] Initializing driver object: dev=%p, drv=%p, %d ports @ %p\n",
362 LIBBASE->sd.pciDevice[i], LIBBASE->sd.pciDriver[i], LIBBASE->sd.numPorts[i],
363 LIBBASE->sd.ramBase[i]));
365 LIBBASE->sd.ohciDevice[i] = OOP_NewObject(NULL, CLID_Drv_USB_OHCI, tags);
366 HIDD_USB_AttachDriver(LIBBASE->sd.usb, LIBBASE->sd.ohciDevice[i]);
370 return TRUE;
373 static int OHCI_ExpungeClass(LIBBASETYPEPTR LIBBASE)
375 D(bug("[OHCI] ExpungeClass\n"));
377 OOP_ReleaseAttrBase(IID_Drv_USB_OHCI);
379 return TRUE;
382 ADD2INITLIB(OHCI_InitClass, 0)
383 ADD2EXPUNGELIB(OHCI_ExpungeClass, 0)