revert between 56095 -> 55830 in arch
[AROS.git] / rom / usb / pciusbhc / xhci / pcixhci_controller.c
blob1a69106be8f13a0071ce3f8fb0a68b793256ba8d
1 /*
2 Copyright © 2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: PCI XHCI USB host controller
6 Lang: English
7 */
9 #ifdef DEBUG
10 #undef DEBUG
11 #endif
12 #define DEBUG 1
14 #include <aros/io.h>
15 #include <aros/debug.h>
16 #include <aros/macros.h>
17 #include <aros/asmcall.h>
18 #include <aros/symbolsets.h>
20 #include <proto/oop.h>
21 #include <proto/exec.h>
22 #include <proto/stdc.h>
23 #include <proto/arossupport.h>
25 #include <devices/usb.h>
26 #include <devices/usb_hub.h>
27 #include <devices/newstyle.h>
28 #include <devices/usbhardware.h>
29 #include <devices/timer.h>
31 #include <asm/io.h>
32 #include <inttypes.h>
34 #include <hidd/pci.h>
35 #include <hidd/hidd.h>
37 #include "pcixhci_intern.h"
39 #include "pcixhci_controller.h"
41 #include LC_LIBDEFS_FILE
43 #define PCIXHCIBase unit->pcixhcibase
45 static AROS_INTH1(PCIXHCI_IntCode, struct PCIXHCIUnit *, unit) {
46 AROS_INTFUNC_INIT
48 ULONG usbsts, portsc;
50 usbsts = operational_readl(XHCI_USBSTS);
52 if(usbsts & XHCF_STS_PCD) {
53 operational_writel(XHCI_USBSTS, XHCF_STS_PCD);
54 mybug_unit(-1, ("cleared usbsts = %08x\n", operational_readl(XHCI_USBSTS)));
55 struct PCIXHCIPort *port = NULL;
57 ForeachNode(&unit->roothub.port_list, port) {
58 portsc = operational_readl(XHCI_PORTSC(port->number));
60 if(portsc & XHCF_PS_CSC) {
61 operational_writel(XHCI_PORTSC(port->number), (portsc | ~XHCF_PS_CSC));
62 mybug_unit(-1,("%s XHCF_PS_CSC\n",port->node.ln_Name));
65 if(portsc & XHCF_PS_PEC) {
66 operational_writel(XHCI_PORTSC(port->number), (portsc | ~XHCF_PS_PEC));
67 mybug_unit(-1,("%s XHCF_PS_PEC\n",port->node.ln_Name));
70 if(portsc & XHCF_PS_OCC) {
71 operational_writel(XHCI_PORTSC(port->number), (portsc | ~XHCF_PS_OCC));
72 mybug_unit(-1,("%s XHCF_PS_OCC\n",port->node.ln_Name));
75 if(portsc & XHCF_PS_WRC) {
76 operational_writel(XHCI_PORTSC(port->number), (portsc | ~XHCF_PS_WRC));
77 mybug_unit(-1,("%s XHCF_PS_WRC\n",port->node.ln_Name));
80 if(portsc & XHCF_PS_PRC) {
81 operational_writel(XHCI_PORTSC(port->number), (portsc | ~XHCF_PS_PRC));
82 mybug_unit(-1,("%s XHCF_PS_PRC\n",port->node.ln_Name));
85 if(portsc & XHCF_PS_PLC) {
86 operational_writel(XHCI_PORTSC(port->number), (portsc | ~XHCF_PS_PLC));
87 mybug_unit(-1,("%s XHCF_PS_PLC\n",port->node.ln_Name));
90 if(portsc & XHCF_PS_CEC) {
91 operational_writel(XHCI_PORTSC(port->number), (portsc | ~XHCF_PS_CEC));
92 mybug_unit(-1,("%s XHCF_PS_CEC\n",port->node.ln_Name));
96 return 0;
97 AROS_INTFUNC_EXIT
101 We get called only once (per controller) when the driver inits
102 We own the controller until our driver expunges so we assume that nobody messes with our stuff...
103 Driver NEVER expunges, it messes Poseidon,
104 Trident actually, as controller hardware is not removed from hw list and Trident will not reopen our driver but calls on expunged code.
106 BOOL PCIXHCI_HCInit(struct PCIXHCIUnit *unit) {
107 //mybug(0, ("[PCIXHCI] PCIXHCI_HCInit: Entering function\n"));
109 /* Our unit is in suspended state until it is reset (cmdUsbReset) */
110 unit->state = UHSF_SUSPENDED;
112 snprintf(unit->name, 255, "PCIXHCI[%02x:%02x.%01x]", (UBYTE)unit->hc.bus, (UBYTE)unit->hc.dev, (UBYTE)unit->hc.sub);
113 unit->node.ln_Name = (STRPTR)&unit->name;
115 NEWLIST(&unit->roothub.port_list);
116 NEWLIST(&unit->roothub.intxferqueue_list);
118 /* Needed before halt or reset */
119 if(!PCIXHCI_CreateTimer(unit)) {
120 return FALSE;
123 /* We use pointers and stuff... */
124 struct TagItem pciActivateMemAndBusmaster[] = {
125 { aHidd_PCIDevice_isIO, FALSE },
126 { aHidd_PCIDevice_isMEM, TRUE },
127 { aHidd_PCIDevice_isMaster, TRUE },
128 { TAG_DONE, 0UL },
131 OOP_SetAttrs(unit->hc.pcidevice, (struct TagItem *)pciActivateMemAndBusmaster);
133 PCIXHCI_GetFromBIOS(unit);
135 if(!PCIXHCI_HCHalt(unit)) {
136 return FALSE;
139 if(!PCIXHCI_HCReset(unit)) {
140 return FALSE;
143 mybug_unit(-1, ("unit node name %s\n", unit->node.ln_Name));
144 mybug_unit(-1, ("pcidevice = %p\n", unit->hc.pcidevice));
145 mybug_unit(-1, ("pcidriver = %p\n", unit->hc.pcidriver));
146 mybug_unit(-1, ("bus = %x\n", unit->hc.bus));
147 mybug_unit(-1, ("dev = %x\n", unit->hc.dev));
148 mybug_unit(-1, ("sub = %x\n", unit->hc.sub));
149 mybug_unit(-1, ("intline = %d\n", unit->hc.intline));
151 mybug_unit(-1, ("capability = %p\n", unit->hc.capability_base));
152 mybug_unit(-1, ("operational = %p\n", unit->hc.operational_base));
153 mybug_unit(-1, ("doorbell = %p\n", unit->hc.doorbell_base));
154 mybug_unit(-1, ("runtime = %p\n", unit->hc.runtime_base));
156 if(!PCIXHCI_FindPorts(unit)) {
157 return FALSE;
160 struct PCIXHCIPort *port = NULL;
162 mybug_unit(-1, ("Unit %d at %p %s\n", unit->number, unit, unit->name));
163 ForeachNode(&unit->roothub.port_list, port) {
164 mybug_unit(-1, (" port %d at %p %s\n", port->number, port, port->name));
166 mybug(-1,("\n"));
168 unit->hc.pagesize = 1<<(AROS_LEAST_BIT_POS(operational_readl(XHCI_PAGESIZE) & 0xffff) + 12);
169 unit->hc.maxslots = XHCV_MaxSlots(capability_readl(XHCI_HCSPARAMS1));
170 unit->hc.maxintrs = XHCV_MaxIntrs(capability_readl(XHCI_HCSPARAMS1));
171 unit->hc.maxscratchpads = XHCV_SPB_Max(capability_readl(XHCI_HCSPARAMS2));
172 unit->hc.maxeventringsegments = (1<<XHCV_ERST_Max(capability_readl(XHCI_HCSPARAMS2)));
174 mybug_unit(-1,("Page size = %d\n", unit->hc.pagesize));
175 mybug_unit(-1,("Number of Device Slots = %d\n", unit->hc.maxslots));
176 mybug_unit(-1,("Number of Interrupters = %d\n", unit->hc.maxintrs));
177 mybug_unit(-1,("Max Scratchpad Buffers = %d\n", unit->hc.maxscratchpads));
178 mybug_unit(-1,("Max event ring segments (ERST Max) = %d\n", unit->hc.maxeventringsegments));
179 if(!(unit->hc.maxeventringsegments)) {
180 mybug_unit(-1,(" -> FAILING!\n"));
181 return FALSE;
184 mybug_unit(-1,("XHCI_CONFIG = %08x\n", operational_readl(XHCI_CONFIG)));
185 mybug_unit(-1,("XHCI_DNCTRL = %08x\n", operational_readl(XHCI_DNCTRL)));
187 /* Enable all the slots */
188 operational_writel(XHCI_CONFIG, (operational_readl(XHCI_CONFIG)&~XHCM_CONFIG_MaxSlotsEn) | unit->hc.maxslots);
190 /* Already zeroed on my hardware */
191 operational_writel(XHCI_DNCTRL, 0);
193 /* Testing */
194 //unit->hc.maxscratchpads = 4;
196 ULONG i;
198 /* Allocate device context base address array (DCBAA), 64-bit pointer array */
199 mybug_unit(-1,("Allocating space for DCBAA(%d UQUAD's + 1)\n",unit->hc.maxslots));
201 unit->hc.dcbaa = AllocVecOnBoundary((unit->hc.maxslots + unit->hc.maxscratchpads + 1) * sizeof(UQUAD), unit->hc.pagesize, "Device context base address array (DCBAA) + (SPBABA)");
202 if(!unit->hc.dcbaa) {
203 mybug_unit(-1, ("Failed allocating space for DCBAA and SPBABA!\n"));
204 return FALSE;
207 char scratch_pad_page_desc[32];
208 if(unit->hc.maxscratchpads) {
209 unit->hc.spbaba = (unit->hc.dcbaa + unit->hc.maxslots + 1);
210 unit->hc.dcbaa[0] = (UQUAD)((IPTR)unit->hc.spbaba);
211 mybug(-1,("DCBAA %p\nSPBABA %p\n", unit->hc.dcbaa, unit->hc.spbaba));
212 for (i=0; i<(unit->hc.maxscratchpads); i++) {
213 snprintf(scratch_pad_page_desc, 31, "Scratch pad page %d", i);
214 unit->hc.spbaba[i] = (UQUAD)(IPTR)AllocVecOnBoundary(unit->hc.pagesize, unit->hc.pagesize, scratch_pad_page_desc);
215 if(!unit->hc.spbaba[i]) {
216 return FALSE;
219 } else {
220 unit->hc.dcbaa[0] = (UQUAD)((IPTR)(unit->hc.spbaba = NULL));
221 mybug(-1,("DCBAA %p SPBABA %p\n", unit->hc.dcbaa, unit->hc.spbaba));
224 operational_writeq(XHCI_DCBAAP, (UQUAD)((IPTR)&unit->hc.dcbaa[0]));
226 for (i=0; i<(unit->hc.maxslots + unit->hc.maxscratchpads + 1); i++) {
227 if(&unit->hc.dcbaa[i] == unit->hc.dcbaa) {
228 mybug(-1,("DCBAA "));
229 } else if(&unit->hc.dcbaa[i] == unit->hc.spbaba) {
230 mybug(-1,("SPBABA "))
231 }else {
232 mybug(-1,(" "));
234 /* I fail to understand how to print quads directly... */
235 mybug(-1,("%2d %p %08x%08x\n",i, &unit->hc.dcbaa[i], (ULONG)(unit->hc.dcbaa[i]>>32), (ULONG)unit->hc.dcbaa[i]));
240 We can only use interrupter number 0 (PCI pin int)
241 Note: The Primary Event Ring (0) shall receive all Port Status Change Events.
243 Make sure secondary interrupters are disabled.
247 Allocate space for Event Ring Segment Table Entries
248 - Maximum number of entries is 1<<ERST_Max, boundary none and alignment of 64 bytes
249 - Max size 512K (=(2^15)*(sizeof(xhci_erste)=16 bytes))
252 //unit->hc.maxeventringsegments = 1;
254 unit->hc.erstbl = AllocVecOnBoundary((unit->hc.maxeventringsegments*sizeof(struct xhci_erste)), 0, "Event ring segment table (ERSTBL)");
255 if(!unit->hc.erstbl) {
256 return FALSE;
258 mybug_unit(-1,("Event ring segment table at (ERSTBL) %p\n", unit->hc.erstbl));
261 unit->hc.eventringsegmenttbl = AllocVecOnBoundary((unit->hc.maxeventringsegments* sizeof(struct PCIXHCIEventRingTable)), 0);
262 if(!unit->hc.eventringsegmenttbl) {
263 mybug_unit(-1, ("Failed allocating event ring segment table!\n"));
264 return FALSE;
269 One Event Ring Segment constitutes from at least 16 TRB's (max 4096)
270 - Hardcode this to be 64 for now
271 - Event TRB has 16-byte boundary, same as Transfer TRB's (CHECKME:)
274 #define MAX_ER_TRB 4096
276 char event_ring_trb_desc[32];
278 for(i=0;i<unit->hc.maxeventringsegments;i++) {
279 snprintf(event_ring_trb_desc, 31, "Event Ring Segment %d TRB space", i);
280 unit->hc.erstbl[i].address = (UQUAD) ((IPTR) AllocVecOnBoundary((MAX_ER_TRB*sizeof(struct xhci_trb_template)), 0, event_ring_trb_desc));
281 if(!(unit->hc.erstbl[i].address)) {
282 return FALSE;
284 unit->hc.erstbl[i].size = MAX_ER_TRB;
285 /* I fail to understand how to print quads directly... */
286 mybug(-1,("hi: %08x lo: %08x\n",(ULONG)(unit->hc.erstbl[i].address>>32), (ULONG)unit->hc.erstbl[i].address));
290 unit->hc.eventringsegmenttbl->address = (UQUAD)((IPTR)AllocVecOnBoundary((sizeof(struct PCIXHCITransferRequestBlock)*100), 64*1024));
291 if(!unit->hc.eventringsegmenttbl->address) {
292 mybug_unit(-1, ("Failed allocating event ring segment!\n"));
293 return FALSE;
295 unit->hc.eventringsegmenttbl->size = 100;
303 mybug_unit(-1, ("Enabling interrupter 0\n"));
304 runtime_writel(XHCI_IMOD(0), 500);
305 runtime_writel(XHCI_IMAN(0), 3);
306 mybug_unit(-1, ("IMAN %08x\n",runtime_readl(XHCI_IMAN(0)))); //Flush
307 runtime_writel(XHCI_ERSTSZ(0), unit->hc.maxeventringsegments);
308 runtime_writeq(XHCI_ERDP(0), (UQUAD)((IPTR)unit->hc.erstbl->address));
309 /* Write to ERSTBA sets Event Ring State Machine state to start */
310 runtime_writeq(XHCI_ERSTBA(0), (UQUAD)((IPTR)unit->hc.erstbl));
314 mybug(-1, ("Enable interrupter 0\n"));
315 runtime_writel(XHCI_IMOD(0), 500);
316 runtime_writel(XHCI_IMAN(0), 3);
317 bug("IMAN %08x\n",runtime_readl(XHCI_IMAN(0))); //Flush
318 runtime_writel(XHCI_ERSTSZ(0), unit->hc.maxeventringsegments);
319 runtime_writeq(XHCI_ERDP(0), (UQUAD)((IPTR)unit->hc.eventringsegmenttbl->address));
320 runtime_writeq(XHCI_ERSTBA(0), (UQUAD)((IPTR)unit->hc.eventringsegmenttbl));
322 mybug(-1, ("Enabling interrupts and setting run bit\n"));
331 /* Add interrupt handler */
332 snprintf(unit->hc.intname, 255, "%s interrupt handler", unit->node.ln_Name);
333 unit->hc.inthandler.is_Node.ln_Name = (STRPTR)&unit->hc.intname;
334 unit->hc.inthandler.is_Node.ln_Pri = 15;
335 unit->hc.inthandler.is_Node.ln_Type = NT_INTERRUPT;
336 unit->hc.inthandler.is_Code = (VOID_FUNC)PCIXHCI_IntCode;
337 unit->hc.inthandler.is_Data = unit;
338 if(!HIDD_PCIDevice_AddInterrupt(unit->hc.pcidevice, &unit->hc.inthandler)) {
339 mybug_unit(-1, ("Failed setting up interrupt handler!\n"));
340 return FALSE;
343 mybug_unit(-1, ("Enabling interrupts and setting run bit\n"));
344 /* Enable host controller to issue interrupts */
345 mybug_unit(-1, ("usbcmd = %08x\n", operational_readl(XHCI_USBCMD)));
346 mybug_unit(-1, ("usbsts = %08x\n", operational_readl(XHCI_USBSTS)));
347 operational_writel(XHCI_USBCMD, (operational_readl(XHCI_USBCMD) | (XHCF_CMD_RS | XHCF_CMD_INTE | XHCF_CMD_HSEE) ));
348 mybug_unit(-1, ("usbcmd = %08x\n", operational_readl(XHCI_USBCMD)));
349 mybug_unit(-1, ("usbsts = %08x\n", operational_readl(XHCI_USBSTS)));
351 return TRUE;
355 BOOL PCIXHCI_HCReset(struct PCIXHCIUnit *unit) {
356 mybug_unit(-1, ("Entering function\n"));
358 ULONG timeout;
360 /* our unit is in reset state until the higher level usb reset is called */
361 unit->state = UHSF_RESET;
363 /* Reset controller by setting HCRST-bit */
364 operational_writel(XHCI_USBCMD, (operational_readl(XHCI_USBCMD) | XHCF_CMD_HCRST));
367 Controller clears HCRST bit when reset is done, wait for it and the CNR-bit to be cleared
369 timeout = 250; //FIXME: arbitrary value of 2500ms
370 while ((operational_readl(XHCI_USBCMD) & XHCF_CMD_HCRST) && (timeout-- != 0)) {
371 if(!timeout) {
372 mybug_unit(-1, ("Time is up for XHCF_CMD_HCRST bit!\n"));
373 return FALSE;
375 /* Wait 10ms and check again */
376 PCIXHCI_Delay(unit, 10);
379 timeout = 250; //FIXME: arbitrary value of 2500ms
380 while ((operational_readl(XHCI_USBSTS) & XHCF_STS_CNR) && (timeout-- != 0)) {
381 if(!timeout) {
382 mybug_unit(-1, ("Time is up for XHCF_STS_CNR bit!\n"));
383 return FALSE;
385 /* Wait 10ms and check again */
386 PCIXHCI_Delay(unit, 10);
389 mybug_unit(-1, ("controller reseted!\n"));
391 return TRUE;
394 BOOL PCIXHCI_HCHalt(struct PCIXHCIUnit *unit) {
395 mybug_unit(-1, ("Entering function\n"));
397 ULONG timeout, temp;
399 /* Halt the controller by clearing Run/Stop bit */
400 temp = operational_readl(XHCI_USBCMD);
401 operational_writel(XHCI_USBCMD, (temp & ~XHCF_CMD_RS));
403 /* Our unit advertises that it is in suspended state */
404 unit->state = UHSF_SUSPENDED;
407 The xHC shall halt within 16 ms. after software clears the Run/Stop bit if certain conditions have been met.
408 The HCHalted (HCH) bit in the USBSTS register indicates when the xHC has finished its
409 pending pipelined transactions and has entered the stopped state.
411 timeout = 250; //FIXME: arbitrary value of 2500ms
412 do {
413 temp = operational_readl(XHCI_USBSTS);
414 if( (temp & XHCF_STS_HCH) ) {
415 mybug_unit(-1, ("controller halted!\n"));
416 return TRUE;
418 /* Wait 10ms and check again */
419 PCIXHCI_Delay(unit, 10);
420 } while(--timeout);
422 mybug_unit(-1, ("halt failed!\n"));
423 return FALSE;
426 BOOL PCIXHCI_GetFromBIOS(struct PCIXHCIUnit *unit) {
427 mybug_unit(-1, ("Entering function\n"));
429 /* Get the host controller from BIOS if possible */
430 IPTR cap_legacy;
431 ULONG usblegsup, usblegctlsts, timeout;
433 cap_legacy = PCIXHCI_SearchExtendedCap(unit, XHCI_EXT_CAPS_LEGACY, (IPTR) NULL);
434 if(cap_legacy) {
435 usblegsup = READREG32(cap_legacy, XHCI_USBLEGSUP);
436 mybug_unit(0, ("usblegsup1 = %08x\n", usblegsup));
438 /* Check if not OS owned or BIOS owned*/
439 if( ((!(usblegsup & XHCF_OSOWNED)) || (usblegsup & XHCF_BIOSOWNED)) ){
440 WRITEMEM32(cap_legacy, (usblegsup|XHCF_OSOWNED));
442 usblegsup = READREG32(cap_legacy, XHCI_USBLEGSUP);
443 mybug_unit(0, ("usblegsup2 = %08x\n", usblegsup));
445 /* Spec says "no more than a second", we give it a little more */
446 timeout = 250;
448 while(1) {
449 usblegsup = READREG32(cap_legacy, XHCI_USBLEGSUP);
450 mybug_unit(0, ("usblegsup3 = %08x\n", usblegsup));
451 if( (usblegsup & XHCF_OSOWNED) && (!(usblegsup & XHCF_BIOSOWNED)) ){
452 break;
455 if(timeout--) {
456 mybug_unit(-1, ("BIOS didn't release XHCI. Forcing and praying...\n"));
457 WRITEMEM32(cap_legacy, ((usblegsup|XHCF_OSOWNED)&~XHCF_BIOSOWNED));
458 break;
461 /* Wait 10ms and check again */
462 PCIXHCI_Delay(unit, 10);
464 } else {
465 mybug_unit(-1, ("Controller is already owned by the OS\n"));
468 usblegctlsts = READREG32(cap_legacy, XHCI_USBLEGCTLSTS);
469 mybug_unit(0, ("usblegctlsts1 = %08x\n", usblegctlsts));
470 /* Disable all legacy SMI's */
471 usblegctlsts &= ~(XHCF_SMI_USBE|XHCF_SMI_HSEE|XHCF_SMI_OSOE|XHCF_SMI_PCICE|XHCF_SMI_BARE);
472 WRITEREG32(cap_legacy, XHCI_USBLEGCTLSTS, usblegctlsts);
473 usblegctlsts = READREG32(cap_legacy, XHCI_USBLEGCTLSTS);
474 mybug_unit(0, ("usblegctlsts2 = %08x\n", usblegctlsts));
477 mybug_unit(-1, ("Controller owned!\n"));
479 return TRUE;
482 IPTR PCIXHCI_SearchExtendedCap(struct PCIXHCIUnit *unit, ULONG id, IPTR extcapoff) {
484 IPTR extcap = (IPTR) NULL;
486 mybug_unit(0,("searching for extended capability id(%ld)\n", id));
488 if(extcapoff) {
489 /* Last known good */
490 if(XHCV_EXT_CAPS_NEXT(READMEM32(extcapoff))) {
491 extcap = extcapoff + XHCV_EXT_CAPS_NEXT(READMEM32(extcapoff));
492 } else {
493 extcap = (IPTR) NULL;
495 } else {
496 extcap = XHCV_xECP(capability_readl(XHCI_HCCPARAMS1)) + (IPTR) unit->hc.capability_base;
497 mybug_unit(0, ("searching from beginning %p\n", extcap));
500 /* Either the first (if exist) or the next from last known (if exist) else (IPTR) NULL */
501 while(extcap != (IPTR) NULL) {
502 if((XHCV_EXT_CAPS_ID(READMEM32(extcap)) == id)) {
503 mybug_unit(0, ("found matching extended capability id at %lx\n", extcap));
504 break;
505 } else {
506 if(XHCV_EXT_CAPS_NEXT(READMEM32(extcap))) {
507 mybug_unit(0, ("skipping extended capability id at %lx\n", extcap));
508 extcap += XHCV_EXT_CAPS_NEXT(READMEM32(extcap));
509 } else {
510 extcap = (IPTR) NULL;
511 break;
516 return (IPTR) extcap;
519 BOOL PCIXHCI_FindPorts(struct PCIXHCIUnit *unit) {
521 struct PCIXHCIPort *port = NULL;
523 IPTR cap_protocol = (IPTR) NULL;
525 ULONG portnum = 0, portcount = 0, temp, major, minor, po, pc;
527 /* Build the port list of our unit */
529 portcount = XHCV_MaxPorts(capability_readl(XHCI_HCSPARAMS1));
530 mybug_unit(-1, ("Controller advertises port count to be %d\n", portcount));
532 do {
533 port = AllocVec(sizeof(struct PCIXHCIPort), MEMF_ANY|MEMF_CLEAR);
534 if(port == NULL) {
535 mybug_unit(-1, ("Failed to create new port structure\n"));
537 /* Give up easily when memory is not available and delete previous ports (if any) from the roothub */
538 ForeachNode(&unit->roothub.port_list, port) {
539 mybug_unit(-1, ("Deleting port %d named %s at %p\n", port->number, port->name, port));
540 REMOVE(port);
541 FreeVec(port);
543 return FALSE;
544 } else {
545 port->node.ln_Type = NT_USER;
546 port->number = ++portnum;
547 port->status = 0;
548 AddTail(&unit->roothub.port_list, (struct Node *)port);
550 mybug_unit(-1, ("Created new port %d at %p\n", port->number, port));
552 } while(--portcount);
556 We may get more than one capability protocol header or just one
558 while((cap_protocol = PCIXHCI_SearchExtendedCap(unit, XHCI_EXT_CAPS_PROTOCOL, cap_protocol))) {
559 temp = READREG32(cap_protocol, XHCI_SPFD);
560 major = XHCV_SPFD_RMAJOR(temp);
561 minor = XHCV_SPFD_RMINOR(temp);
563 temp = READREG32(cap_protocol, XHCI_SPPORT);
564 po = XHCV_SPPORT_CPO(temp);
565 pc = XHCV_SPPORT_CPCNT(temp);
567 mybug_unit(-1, ("Version %ld.%ld port offset %d port count %d\n", major, minor, po, pc));
569 /* Iterate through port list and place the name for one that fits inside the offset and count */
570 ForeachNode(&unit->roothub.port_list, port) {
571 if( (port->number>=po) && (port->number<(po+pc)) ){
572 snprintf(port->name, 255, "%s USB %d.%d port %d", unit->node.ln_Name, major, minor, port->number);
573 port->node.ln_Name = (STRPTR)&port->name;
578 /* Check if any port is left unnamed */
579 ForeachNode(&unit->roothub.port_list, port) {
580 if(port->node.ln_Name == NULL){
581 snprintf(port->name, 255, "%s USB 2.0 port %d (guessed)", unit->node.ln_Name, port->number);
582 port->node.ln_Name = (STRPTR)&port->name;
586 return TRUE;
589 BOOL PCIXHCI_PortPower(struct PCIXHCIUnit *unit, ULONG portnum, BOOL poweron) {
591 Check for port power control
593 if(capability_readl(XHCI_HCCPARAMS1) & XHCF_PPC) {
594 mybug_unit(-1, ("Port has power switch\n"));
595 } else {
596 mybug_unit(-1, ("Port does not have power switch\n"));
599 /* We have power on by default, skip this for now */
601 ULONG portsc;
603 portsc = operational_readl(XHCI_PORTSC(portnum));
605 mybug_unit(-1, ("portsc = %08x\n", portsc));
606 portsc = portsc & 0x7F00FF08;
607 mybug_unit(-1, ("portsc = %08x\n", portsc));
609 if(poweron) {
610 portsc = (portsc | XHCF_PS_PP);
611 mybug_unit(-1, ("Port powering up\n"));
612 } else {
613 mybug_unit(-1, ("Port powering down\n"));
614 portsc = (portsc & ~XHCF_PS_PP);
617 operational_writel(XHCI_PORTSC(portnum), portsc);
619 portsc = operational_readl(XHCI_PORTSC(portnum));
620 mybug_unit(-1, ("portsc = %08x\n", portsc));
622 return TRUE;