2 Copyright (C) 2006 by Michal Schulz
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.
22 #include <aros/symbolsets.h>
26 #include <hidd/hidd.h>
33 #include <devices/timer.h>
35 #include <proto/exec.h>
36 #include <proto/oop.h>
37 #include <aros/debug.h>
42 #define SD(x) (&LIBBASE->sd)
45 AROS_UFH3(void, Enumerator
,
46 AROS_UFHA(struct Hook
*, hook
, A0
),
47 AROS_UFHA(OOP_Object
*, pciDevice
, A2
),
48 AROS_UFHA(APTR
, message
, A1
))
52 LIBBASETYPE
*LIBBASE
= (LIBBASETYPE
*)hook
->h_Data
;
53 char *base
, *reg_base
;
55 uint8_t cap_length
, offset
;
59 struct timerequest
*tr
;
61 port
= CreateMsgPort();
62 tr
= CreateIORequest(port
, sizeof(struct timerequest
));
64 OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tr
, 0);
66 struct pHidd_PCIDevice_WriteConfigLong wl
;
67 struct pHidd_PCIDevice_ReadConfigLong rl
;
68 struct pHidd_PCIDevice_WriteConfigByte wb
;
70 wl
.mID
= OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigLong
);
71 rl
.mID
= OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_ReadConfigLong
);
72 wb
.mID
= OOP_GetMethodID(IID_Hidd_PCIDevice
, moHidd_PCIDevice_WriteConfigByte
);
74 struct TagItem attrs
[] = {
75 { aHidd_PCIDevice_isMEM
, TRUE
},
76 { aHidd_PCIDevice_isMaster
, TRUE
},
80 OOP_SetAttrs(pciDevice
, (struct TagItem
*)attrs
);
81 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Base0
, (IPTR
*)&base
);
82 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (void *)&driver
);
84 cap_length
= mmio_b(base
);
85 reg_base
= base
+ cap_length
;
87 D(bug("[EHCI] EHCI device Device @ %p, cap_length: %d\n", base
, cap_length
));
89 uint32_t hcc_params
= mmio_l(base
+ 0x08);
90 offset
= (hcc_params
>> 8) & 0xff; // Get the address of first capability
92 D(bug("[EHCI] hcc_params=%08x\n", hcc_params
));
94 D(bug("[EHCI] Try to perform the BIOS handoff procedure\n"));
96 while(offset
&& count
--)
100 cap
= OOP_DoMethod(driver
, &rl
.mID
);
102 if ((cap
& 0xff) == 1)
104 D(bug("[EHCI] cap=%08x\n", cap
));
106 D(bug("[EHCI] LEGSUP capability found\n"));
111 D(bug("[EHCI] BIOS was owning the EHCI. Changing it.\n"));
114 OOP_DoMethod(driver
, &wb
.mID
);
117 while((cap
& 0x10000) && delay
> 0)
119 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
120 tr
->tr_time
.tv_sec
= 0;
121 tr
->tr_time
.tv_usec
= 40000;
122 DoIO((struct IORequest
*)tr
);
125 cap
= OOP_DoMethod(driver
, &rl
.mID
);
130 D(bug("[EHCI] BIOS is not going to give up! Forcing it...\n"));
134 OOP_DoMethod(driver
, &wb
.mID
);
137 D(bug("[EHCI] Disabling SMI\n"));
140 OOP_DoMethod(driver
, &wl
.mID
);
142 else if ((cap
& 0xff) == 0)
145 offset
= (cap
>> 8) & 0xff;
148 D(bug("[EHCI] Performing full reset of the EHCI\n"));
150 uint32_t value
= mmio_l(reg_base
+ 0x04); // Read the status register
151 if ((value
& 0x1000) == 0) // Halted flag not cleared? Then the EHCI is still running. Stop it.
155 value
= mmio_l(reg_base
+ 0); // USBCMD reg
156 value
&= ~1; // clear RUN flag
157 mmio_l(reg_base
+ 0) = value
;
160 mmio_l(reg_base
+ 0x04) = 0x3f;
161 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
162 tr
->tr_time
.tv_sec
= 0;
163 tr
->tr_time
.tv_usec
= 40000;
164 DoIO((struct IORequest
*)tr
);
165 value
= mmio_l(reg_base
+ 0x04);
166 if ((value
== ~(uint32_t)0) || value
& 0x1000)
168 } while(--nloop
> 0);
171 mmio_l(reg_base
+ 0x08) = 0; // USBINTR = 0, no interrupts allowed
172 mmio_l(reg_base
+ 0x04) = 0x3f; // USBSTS flags cleared
173 mmio_l(reg_base
+ 0x40) = 0; // Unconfigure the chip
175 mmio_l(reg_base
+ 0) = 2;
176 tr
->tr_node
.io_Command
= TR_ADDREQUEST
;
177 tr
->tr_time
.tv_sec
= 0;
178 tr
->tr_time
.tv_usec
= 100000;
179 DoIO((struct IORequest
*)tr
);
180 mmio_l(reg_base
+ 0) = 0;
186 mmio_l(reg_base
+ 0x44 + 4*hcc_params
) = 1 << 13;
189 CloseDevice((struct IORequest
*)tr
);
196 static int EHCI_Init(LIBBASETYPEPTR LIBBASE
)
198 D(bug("[EHCI] EHCI_Init()\n"));
200 LIBBASE
->sd
.usb
= OOP_NewObject(NULL
, (STRPTR
)CLID_Hidd_USB
, NULL
);
202 if (!LIBBASE
->sd
.usb
)
204 bug("[EHCI] Cannot create the instance of base USB class\n");
208 if ((LIBBASE
->sd
.pci
=OOP_NewObject(NULL
, (STRPTR
)CLID_Hidd_PCI
, NULL
)))
210 struct TagItem tags
[] = {
211 { tHidd_PCI_Class
, PCI_BASE_CLASS_SERIAL
},
212 { tHidd_PCI_SubClass
, PCI_SUB_CLASS_USB
},
213 { tHidd_PCI_Interface
, PCI_INTERFACE_EHCI
},
217 struct OOP_ABDescr attrbases
[] = {
218 { (STRPTR
)IID_Hidd
, &HiddAttrBase
},
219 { (STRPTR
)IID_Hidd_PCIDevice
, &HiddPCIDeviceAttrBase
},
220 { (STRPTR
)IID_Hidd_USBDevice
, &HiddUSBDeviceAttrBase
},
221 { (STRPTR
)IID_Hidd_USBHub
, &HiddUSBHubAttrBase
},
222 { (STRPTR
)IID_Hidd_USBDrv
, &HiddUSBDrvAttrBase
},
226 struct Hook FindHook
= {
227 h_Entry
: (IPTR (*)())Enumerator
,
231 OOP_ObtainAttrBases(attrbases
);
233 D(bug("[EHCI] Searching for EHCI devices...\n"));
235 HIDD_PCI_EnumDevices(LIBBASE
->sd
.pci
, &FindHook
, (struct TagItem
*)&tags
);
237 D(bug("[EHCI] Done\n"));
239 OOP_DisposeObject(LIBBASE
->sd
.pci
);
245 static int EHCI_Expunge(LIBBASETYPEPTR LIBBASE
)
247 struct OOP_ABDescr attrbases
[] = {
248 { (STRPTR
)IID_Hidd
, &HiddAttrBase
},
249 { (STRPTR
)IID_Hidd_PCIDevice
, &HiddPCIDeviceAttrBase
},
250 { (STRPTR
)IID_Hidd_USBDevice
, &HiddUSBDeviceAttrBase
},
251 { (STRPTR
)IID_Hidd_USBHub
, &HiddUSBHubAttrBase
},
252 { (STRPTR
)IID_Hidd_USBDrv
, &HiddUSBDrvAttrBase
},
256 OOP_ReleaseAttrBases(attrbases
);
261 OOP_Object
*METHOD(EHCI
, Root
, New
)
266 void METHOD(EHCI
, Root
, Dispose
)
270 ADD2INITLIB(EHCI_Init
, 0)
271 ADD2EXPUNGELIB(EHCI_Expunge
, 0)
272 ADD2LIBS((STRPTR
)"usb.hidd", 0, static struct Library
*, __usbbase
)