Forgotten changes that should have been part of the r45368 64-bit fix.
[AROS.git] / rom / usb / pciusb / xhcichip.c
blob95008afe54e81d655dbc60196ce96e523890c682
1 /*
2 Copyright © 2010-2011, The AROS Development Team. All rights reserved
3 $Id$
4 */
6 #include <proto/exec.h>
7 #include <proto/oop.h>
8 #include <hidd/pci.h>
10 #include <devices/usb_hub.h>
12 #include "uhwcmd.h"
14 #ifdef AROS_USB30_CODE
16 #undef HiddPCIDeviceAttrBase
17 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
18 #undef HiddAttrBase
19 #define HiddAttrBase (hd->hd_HiddAB)
21 static
22 AROS_UFH3(void, xhciResetHandler,
23 AROS_UFHA(struct PCIController *, hc, A1),
24 AROS_UFHA(APTR, unused, A5),
25 AROS_UFHA(struct ExecBase *, SysBase, A6))
27 AROS_USERFUNC_INIT
29 /* Halt controller */
30 #ifdef DEBUG
31 if(!xhciHaltHC(hc))
32 KPRINTF(1000, ("Halting HC failed, reset may result in undefined behavior!\n"));
33 #else
34 xhciHaltHC(hc);
35 #endif
37 /* Reset controller */
38 xhciResetHC(hc);
40 AROS_USERFUNC_EXIT
43 void xhciCompleteInt(struct PCIController *hc)
45 KPRINTF(1, ("CompleteInt!\n"));
47 KPRINTF(1, ("CompleteDone\n"));
50 void xhciIntCode(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
52 struct PCIController *hc = (struct PCIController *) irq->h_Data;
53 // struct PCIDevice *base = hc->hc_Device;
54 // struct PCIUnit *unit = hc->hc_Unit;
56 ULONG intr, portn;
58 intr = opreg_readl(XHCI_USBSTS);
59 if(intr & XHCF_STS_EINT) {
60 /* Clear (RW1C) Event Interrupt (EINT) */
61 opreg_writel(XHCI_USBSTS, XHCF_STS_EINT);
63 if (hc->hc_Flags & HCF_ONLINE)
65 if(intr & XHCF_STS_HSE) {
66 KPRINTF(1000, ("Host System Error (HSE)!\n"));
69 if(intr & XHCF_STS_PCD) {
70 /* There are seven status change bits in the PORTSC register,
71 Connect Status Change (CSC)
72 Port Enabled/Disabled Change (PEC)
73 Warm Port Reset Change (WRC)
74 Over-current Change (OCC)
75 Port Reset Change (PRC)
76 Port Link State Change (PLC)
77 Port Config Error Change (CEC)
79 for (portn = 1; portn <= hc->xhc_NumPorts; portn++) {
80 if (opreg_readl(XHCI_PORTSC(portn)) & (XHCF_PS_CSC|XHCF_PS_PEC|XHCF_PS_OCC|XHCF_PS_WRC|XHCF_PS_PRC|XHCF_PS_PLC|XHCF_PS_CEC)) {
81 KPRINTF(1000,("port %d changed\n", portn));
86 if(intr & XHCF_STS_SRE) {
87 KPRINTF(1000, ("Host Controller Error (HCE)!\n"));
90 } // not online
94 IPTR xhciSearchExtCap(struct PCIController *hc, ULONG id, IPTR extcap) {
96 IPTR extcapoff = (IPTR) 0;
97 ULONG cnt = XHCI_EXT_CAPS_MAX;
99 KPRINTF(100,("search for ext cap with id(%ld)\n", id));
101 if(extcap) {
102 KPRINTF(100, ("continue search from %p\n", extcap));
103 extcap = (IPTR) XHCV_EXT_CAPS_NEXT(READMEM32_LE(extcap));
104 } else {
105 extcap = (IPTR) hc->xhc_capregbase + XHCV_xECP(capreg_readl(XHCI_HCCPARAMS));
106 KPRINTF(100, ("search from the beginning %p\n", extcap));
109 do {
110 extcap += extcapoff;
111 if((XHCV_EXT_CAPS_ID(READMEM32_LE(extcap)) == id)) {
112 KPRINTF(100, ("found matching ext cap %lx\n", extcap));
113 return (IPTR) extcap;
115 #if DEBUG
116 if(extcap)
117 KPRINTF(100, ("skipping ext cap with id(%ld)\n", XHCV_EXT_CAPS_ID(READMEM32_LE(extcap))));
118 #endif
119 extcapoff = (IPTR) XHCV_EXT_CAPS_NEXT(READMEM32_LE(extcap));
120 cnt--;
121 } while(cnt & extcapoff);
123 KPRINTF(100, ("not found!\n"));
124 return (IPTR) 0;
127 BOOL xhciHaltHC(struct PCIController *hc) {
129 struct PCIUnit *hu = hc->hc_Unit;
131 ULONG timeout, temp;
133 /* Halt the controller by clearing Run/Stop bit */
134 temp = opreg_readl(XHCI_USBCMD);
135 opreg_writel(XHCI_USBCMD, (temp & ~XHCF_CMD_RS));
138 The xHC shall halt within 16 ms. after software clears the Run/Stop bit if certain conditions have been met.
139 The HCHalted (HCH) bit in the USBSTS register indicates when the xHC has finished its
140 pending pipelined transactions and has entered the stopped state.
142 timeout = 250; //FIXME: arbitrary value of 2500ms
143 do {
144 temp = opreg_readl(XHCI_USBSTS);
145 if( (temp & XHCF_STS_HCH) ) {
146 KPRINTF(1000, ("controller halted!\n"));
147 return TRUE;
149 uhwDelayMS(10, hu);
150 } while(--timeout);
152 KPRINTF(1000, ("halt failed!\n"));
153 return FALSE;
156 BOOL xhciResetHC(struct PCIController *hc) {
158 struct PCIUnit *hu = hc->hc_Unit;
160 ULONG timeout, temp;
162 /* Reset controller by setting HCRST-bit */
163 temp = opreg_readl(XHCI_USBCMD);
164 opreg_writel(XHCI_USBCMD, (temp | XHCF_CMD_HCRST));
167 Controller clears HCRST bit when reset is done, wait for it and the CNR-bit to be cleared
169 timeout = 250; //FIXME: arbitrary value of 2500ms
170 do {
171 temp = opreg_readl(XHCI_USBCMD);
172 if( !(temp & XHCF_CMD_HCRST) ) {
173 /* Wait for CNR-bit to clear */
174 timeout = 250; //FIXME: arbitrary value of 2500ms
175 do {
176 temp = opreg_readl(XHCI_USBSTS);
177 if( !(temp & XHCF_STS_CNR) ) {
178 KPRINTF(1000, ("reset succeeded!\n"));
179 return TRUE;
181 uhwDelayMS(10, hu);
182 } while(--timeout);
183 return FALSE;
185 uhwDelayMS(10, hu);
186 } while(--timeout);
188 KPRINTF(1000, ("reset failed!\n"));
189 return FALSE;
192 BOOL xhciInit(struct PCIController *hc, struct PCIUnit *hu) {
194 struct PCIDevice *hd = hu->hu_Device;
196 ULONG cnt, timeout, temp;
197 IPTR extcap;
198 APTR memptr = NULL;
200 volatile APTR pciregbase;
202 struct TagItem pciActivateMemAndBusmaster[] =
204 { aHidd_PCIDevice_isIO, FALSE },
205 { aHidd_PCIDevice_isMEM, TRUE },
206 { aHidd_PCIDevice_isMaster, TRUE },
207 { TAG_DONE, 0UL },
210 memptr = AllocVecAligned(2000, 0x100);
211 KPRINTF(1000,("AllocVedAligned %p\n", memptr));
212 FreeVecAligned(memptr);
214 /* Activate Mem and Busmaster as pciFreeUnit will disable them! (along with IO, but we don't have that...) */
215 OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciActivateMemAndBusmaster);
217 OOP_GetAttr(hc->hc_PCIDeviceObject, aHidd_PCIDevice_Base0, (APTR) &pciregbase);
218 // KPRINTF(1000, ("XHCI MMIO address space (%p)\n",pciregbase));
220 // Store capregbase in xhc_capregbase
221 hc->xhc_capregbase = (APTR) pciregbase;
222 KPRINTF(1000, ("xhc_capregbase (%p)\n",hc->xhc_capregbase));
224 // Store opregbase in xhc_opregbase
225 hc->xhc_opregbase = (APTR) ((ULONG) pciregbase + capreg_readb(XHCI_CAPLENGTH));
226 KPRINTF(1000, ("xhc_opregbase (%p)\n",hc->xhc_opregbase));
228 // KPRINTF(1000, ("XHCI CAPLENGTH (%02x)\n", capreg_readb(XHCI_CAPLENGTH)));
229 // KPRINTF(1000, ("XHCI Version (%04x)\n", capreg_readw(XHCI_HCIVERSION)));
230 // KPRINTF(1000, ("XHCI HCSPARAMS1 (%08x)\n", capreg_readl(XHCI_HCSPARAMS1)));
231 // KPRINTF(1000, ("XHCI HCSPARAMS2 (%08x)\n", capreg_readl(XHCI_HCSPARAMS2)));
232 // KPRINTF(1000, ("XHCI HCSPARAMS3 (%08x)\n", capreg_readl(XHCI_HCSPARAMS3)));
233 // KPRINTF(1000, ("XHCI HCCPARAMS (%08x)\n", capreg_readl(XHCI_HCCPARAMS)));
236 This field defines the page size supported by the xHC implementation.
237 This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
238 if bit 0 is set, the xHC supports 4k byte page sizes.
240 cnt = 12;
241 temp = opreg_readl(XHCI_PAGESIZE)&0xffff;
242 while((~temp&1) & temp){
243 temp = temp>>1;
244 cnt++;
246 hc->xhc_pagesize = 1<<(cnt);
247 KPRINTF(1000, ("Pagesize 2^(n+12) = 0x%lx\n", hc->xhc_pagesize));
249 /* Testing scratchpad allocations */
250 hc->xhc_scratchpads = 4;
251 // hc->xhc_scratchpads = XHCV_SPB_Max(capreg_readl(XHCI_HCSPARAMS2));
252 KPRINTF(1000, ("Max Scratchpad Buffers %lx\n",hc->xhc_scratchpads));
254 hc->xhc_NumPorts = XHCV_MaxPorts(capreg_readl(XHCI_HCSPARAMS1));
255 KPRINTF(1000, ("MaxPorts %lx\n",hc->xhc_NumPorts));
258 We don't yeat know how many we have each of them, xhciParseSupProtocol takes care of that
260 hc->xhc_NumPorts20 = 0;
261 hc->xhc_NumPorts30 = 0;
264 Number of Device Slots (MaxSlots). This field specifies the maximum number of Device
265 Context Structures and Doorbell Array entries this host controller can support. Valid values are
266 in the range of 1 to 255. The value of ‘0’ is reserved, fail gracefully on it
268 hc->xhc_maxslots = (XHCV_MaxSlots(capreg_readl(XHCI_HCSPARAMS1)) & XHCM_CONFIG_MaxSlotsEn);
269 if(hc->xhc_maxslots == 0){
270 KPRINTF(1000, ("MaxSlots count is 0, failing!\n"));
271 return FALSE;
274 KPRINTF(1000, ("MaxSlots %lx\n",hc->xhc_maxslots));
276 KPRINTF(1000, ("MaxIntrs %lx\n",XHCV_MaxIntrs(capreg_readl(XHCI_HCSPARAMS1))));
278 /* 64 byte or 32 byte context data structures? */
279 if(capreg_readl(XHCI_HCCPARAMS) & XHCF_CSZ) {
280 hc->xhc_contextsize64=TRUE;
283 /* xHCI Extended Capabilities, search for USB Legacy Support */
284 extcap = xhciSearchExtCap(hc, XHCI_EXT_CAPS_LEGACY, 0);
285 if(extcap) {
287 temp = READMEM32_LE(extcap);
288 if( (temp & XHCF_BIOSOWNED) ){
289 KPRINTF(1000, ("controller owned by BIOS\n"));
291 /* Spec says "no more than a second", we give it a little more */
292 timeout = 250;
294 WRITEMEM32_LE(extcap, (temp | XHCF_OSOWNED) );
295 do {
296 temp = READMEM32_LE(extcap);
297 if( !(temp & XHCF_BIOSOWNED) ) {
298 KPRINTF(1000, ("BIOS gave up on XHCI. Pwned!\n"));
299 break;
301 uhwDelayMS(10, hu);
302 } while(--timeout);
304 if(!timeout) {
305 KPRINTF(1000, ("BIOS didn't release XHCI. Forcing and praying...\n"));
306 WRITEMEM32_LE(extcap, (temp & ~XHCF_BIOSOWNED) );
311 /* XHCI spec says that there is at least one "Supported Protocol" capability, fail if none is found as this is used for port logic */
312 extcap = xhciSearchExtCap(hc, XHCI_EXT_CAPS_PROTOCOL, 0);
313 if(extcap) {
314 KPRINTF(1000, ("Supported Protocol found!\n"));
315 xhciParseSupProtocol(hc, extcap);
317 /* Parse rest, if any...*/
318 do {
319 extcap = xhciSearchExtCap(hc, XHCI_EXT_CAPS_PROTOCOL, extcap);
320 if(extcap) {
321 KPRINTF(1000, ("More Supported Protocols found!\n"));
322 xhciParseSupProtocol(hc, extcap);
324 }while(extcap);
325 }else{
326 KPRINTF(1000, ("No Supported Protocol found, failing!\n"));
327 return FALSE;
331 If no USB2.0 ports were found but max port count is greater than USB3.0 count assume the overhead to be USB2.0
333 if( (hc->xhc_NumPorts < (hc->xhc_NumPorts20 + hc->xhc_NumPorts30)) ) {
334 KPRINTF(1000, ("Too many ports in Supported Protocol!\n"));
335 return FALSE;
336 }else if ( (hc->xhc_NumPorts > (hc->xhc_NumPorts20 + hc->xhc_NumPorts30)) ) {
337 hc->xhc_NumPorts20 = (hc->xhc_NumPorts - hc->xhc_NumPorts30);
340 KPRINTF(1000, ("Number of USB2.0 ports %ld\n", hc->xhc_NumPorts20 ));
341 KPRINTF(1000, ("Number of USB3.0 ports %ld\n", hc->xhc_NumPorts30 ));
343 if(xhciHaltHC(hc)) {
344 if(xhciResetHC(hc)) {
346 // for(cnt = 1; cnt <=hc->xhc_NumPorts; cnt++) {
347 // temp = opreg_readl(XHCI_PORTSC(cnt));
348 // KPRINTF(1000, ("Attached device's speed on port #%d is %d (PORTSC %lx)\n",cnt, XHCV_PS_SPEED(temp), temp ));
349 // }
351 hc->hc_PCIMemSize = 1024; //Arbitrary number
353 /* CHECKME: Removed this memory allocation as it was not used in any way (at least for now) */
354 // memptr = HIDD_PCIDriver_AllocPCIMem(hc->hc_PCIDriverObject, hc->hc_PCIMemSize);
355 // hc->hc_PCIMem = (APTR) memptr;
356 hc->hc_PCIMem = NULL;
358 // if(memptr) {
360 // PhysicalAddress - VirtualAdjust = VirtualAddress
361 // VirtualAddress + VirtualAdjust = PhysicalAddress
362 // hc->hc_PCIVirtualAdjust = pciGetPhysical(hc, memptr) - (APTR)memptr;
363 // KPRINTF(10, ("VirtualAdjust 0x%08lx\n", hc->hc_PCIVirtualAdjust));
365 hc->hc_CompleteInt.is_Node.ln_Type = NT_INTERRUPT;
366 hc->hc_CompleteInt.is_Node.ln_Name = "XHCI CompleteInt";
367 hc->hc_CompleteInt.is_Node.ln_Pri = 0;
368 hc->hc_CompleteInt.is_Data = hc;
369 hc->hc_CompleteInt.is_Code = (void (*)(void)) &xhciCompleteInt;
371 // add reset handler
372 hc->hc_ResetInt.is_Code = xhciResetHandler;
373 hc->hc_ResetInt.is_Data = hc;
374 AddResetCallback(&hc->hc_ResetInt);
376 // add interrupt handler
377 hc->hc_PCIIntHandler.h_Node.ln_Name = "XHCI PCI (pciusb.device)";
378 hc->hc_PCIIntHandler.h_Node.ln_Pri = 5;
379 hc->hc_PCIIntHandler.h_Code = xhciIntCode;
380 hc->hc_PCIIntHandler.h_Data = hc;
381 HIDD_IRQ_AddHandler(hd->hd_IRQHidd, &hc->hc_PCIIntHandler, hc->hc_PCIIntLine);
383 /* Clears (RW1C) Host System Error(HSE), Event Interrupt(EINT), Port Change Detect(PCD) and Save/Restore Error(SRE) */
384 temp = opreg_readl(XHCI_USBSTS);
385 opreg_writel(XHCI_USBSTS, temp);
387 /* After reset all notifications should be automatically disabled but ensure anyway */
388 opreg_writel(XHCI_DNCTRL, 0);
390 /* Program the Max Device Slots Enabled (MaxSlotsEn) field */
392 Max Device Slots Enabled (MaxSlotsEn) – RW. Default = ‘0’. This field specifies the maximum
393 number of enabled Device Slots. Valid values are in the range of 0 to MaxSlots. Enabled Devices
394 Slots are allocated contiguously. e.g. A value of 16 specifies that Device Slots 1 to 16 are active.
395 A value of ‘0’ disables all Device Slots. A disabled Device Slot shall not respond to Doorbell
396 Register references.
397 This field shall not be modified by software if the xHC is running (Run/Stop (R/S) = ‘1’).
399 opreg_writel(XHCI_CONFIG, ((opreg_readl(XHCI_CONFIG) & ~XHCM_CONFIG_MaxSlotsEn) | hc->xhc_maxslots));
401 if(hc->xhc_scratchpads) {
404 Scratchpad array is 64 byte aligned as is Device Context Base array, neither can cross page boundary
406 hc->xhc_scratchpadarray = AllocVecAligned( (hc->xhc_scratchpads*sizeof(UQUAD) ), hc->xhc_pagesize);
407 if( !(hc->xhc_scratchpadarray) ){
408 KPRINTF(1000, ("Unable to allocate scratchpad array, failing!\n"));
409 return FALSE;
412 hc->xhc_dcbaa = AllocVecAligned( ((hc->xhc_maxslots + 1)*sizeof(UQUAD)) , hc->xhc_pagesize);
413 if( !(hc->xhc_scratchpadarray) ){
414 FreeVecAligned(hc->xhc_scratchpadarray);
415 KPRINTF(1000, ("Unable to allocate device context base array, failing!\n"));
416 return FALSE;
419 hc->xhc_dcbaa[0] = (UQUAD) hc->xhc_scratchpadarray;
421 KPRINTF(1000, ("Allocated scratchpad buffer array at %p\n", hc->xhc_scratchpadarray));
423 for(temp = 0; temp<hc->xhc_scratchpads; temp++){
426 We are making a bold assumption that pagesize returned by host controller is the same as system pagesize...
428 memptr = AllocVecAligned(hc->xhc_pagesize, hc->xhc_pagesize);
429 if(memptr){
430 hc->xhc_scratchpadarray[temp] = (UQUAD) (0xDEADBEEF00000000 | (UQUAD) memptr);
431 /* CHECKME: Not really sure if the 32(or 64) bit address is stored correctly in the QUAD pointer list */
432 KPRINTF(1000, ("hc->xhc_scratchpadarray[%d] = %0lx:%0lx\n", temp, (IPTR) ((UQUAD)(hc->xhc_scratchpadarray[temp])>>32), (IPTR) hc->xhc_scratchpadarray[temp]));
433 }else{
434 for(temp = 0; temp<hc->xhc_scratchpads; temp++){
435 if(hc->xhc_scratchpadarray[temp]){
436 FreeVecAligned( (APTR) hc->xhc_scratchpadarray[temp] );
439 return FALSE;
443 }else{
445 Host controller does not use scratchpads (This is the case OnMyHW™)
447 hc->xhc_scratchpadarray = NULL;
450 DCBAA can't cross page boundary, make sure it doesn't. This all adds memory usage.
452 hc->xhc_dcbaa = AllocVecAligned( ((hc->xhc_maxslots + 1)*sizeof(UQUAD)), hc->xhc_pagesize);
453 if( !(hc->xhc_dcbaa) ){
454 KPRINTF(1000, ("Unable to allocate device context base array, failing!\n"));
455 return FALSE;
459 KPRINTF(1000, ("Device context base array at %p\n", hc->xhc_dcbaa));
461 opreg_writeq(XHCI_DCBAAP, (IPTR)hc->xhc_dcbaa );
463 /* FIXME: Allocate device context data structures and fill rest of the DCBAA array*/
464 /* Define the Command Ring Dequeue Pointer by programming the Command Ring Control Register */
466 /* Set Run/Stop(R/S), Interrupter Enable(INTE) and Host System Error Enable(HSEE) */
467 opreg_writel(XHCI_USBCMD, (XHCF_CMD_RS | XHCF_CMD_INTE | XHCF_CMD_HSEE) );
469 KPRINTF(1000, ("xhciInit returns TRUE...\n"));
470 return TRUE;
475 KPRINTF(1000, ("xhciInit returns FALSE...\n"));
476 return FALSE;
479 void xhciFree(struct PCIController *hc, struct PCIUnit *hu) {
481 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
482 while(hc->hc_Node.ln_Succ)
484 switch(hc->hc_HCIType)
486 case HCITYPE_XHCI:
488 KPRINTF(1000, ("Shutting down XHCI %08lx\n", hc));
489 xhciHaltHC(hc);
490 uhwDelayMS(50, hu);
491 SYNC;
492 KPRINTF(1000, ("Shutting down XHCI done.\n"));
493 break;
497 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
501 void xhciParseSupProtocol(struct PCIController *hc, IPTR extcap) {
503 ULONG temp1, temp2;
505 temp1 = READMEM32_LE(extcap);
506 KPRINTF(1000, ("Version %l.%l\n", XHCV_SPFD_RMAJOR(temp1), XHCV_SPFD_RMINOR(temp1) ));
508 temp2 = READMEM32_LE(extcap + XHCI_SPPORT);
509 // KPRINTF(1000, ("CPO %ld\n", XHCV_SPPORT_CPO(temp2) ));
510 // KPRINTF(1000, ("CPCNT %ld\n", XHCV_SPPORT_CPCNT(temp2) ));
511 // KPRINTF(1000, ("PD %ld\n", XHCV_SPPORT_PD(temp2) ));
512 // KPRINTF(1000, ("PSIC %ld\n", XHCV_SPPORT_PSIC(temp2) ));
515 FIXME:
516 -We might not get at all "USB2 Supported Protocol", in that case make a wild assumption on # USB2.0 ports
517 -Check if the name string is "USB " (=0x20425355)
518 -Map USB specifications to their respective ports (USB2.0/USB3.0)
521 if(XHCV_SPFD_RMAJOR(temp1) == 2) {
522 hc->xhc_NumPorts20 = ((XHCV_SPPORT_CPCNT(temp2) - XHCV_SPPORT_CPO(temp2) + 1));
524 if(XHCV_SPFD_RMAJOR(temp1) == 3) {
525 hc->xhc_NumPorts30 = ((XHCV_SPPORT_CPCNT(temp2) - XHCV_SPPORT_CPO(temp2) + 1));
530 Allocate aligned memory (call with ALIGNMENT = PAGESIZE for onpage memory, will result in PAGESIZE overhead memory usage)
532 APTR AllocVecAligned(ULONG bytesize, ULONG alignment) {
533 // KPRINTF(1000, ("AllocVecAligned %ld, %ld\n", bytesize, alignment ));
535 IPTR temp, *ret;
538 Allocate aligned memory by ourself as OS doesn't seem to give us any support for aligned allocations (ONPAGE,ALIGNMENT)
539 -We only support alignment of sizeof(IPTR) and up since we store the original ptr, sizeof(IPTR) is platform dependant
541 if(alignment<sizeof(IPTR)) {
542 alignment = sizeof(IPTR);
545 temp = (IPTR)AllocVec( bytesize+alignment, (MEMF_PUBLIC | MEMF_CLEAR) );
546 if(temp) {
547 // KPRINTF(1000, ("got memory @ %p with alignment %ld\n", temp, alignment ));
550 If by coincidence we get aligned memory, we still add the alignment size to the pointer and align it to the next possible aligned address
551 as we need memory below our allocation.
553 ret = (APTR)((IPTR)(temp+alignment) & ~(alignment-1));
554 // KPRINTF(1000, ("final memory @ %p\n", ret ));
557 Store our original memory pointer below our aligned memory (we have allocated memory there)
559 ret[-1] = temp;
560 return ret;
562 return NULL;
565 void FreeVecAligned(APTR memory) {
566 IPTR *ptr = memory;
567 // KPRINTF(1000, ("FreeVecAligned @ %p\n", ptr[-1] ));
568 FreeVec((APTR)ptr[-1]);
571 #endif