[android-sdk/device-ti-proprietary-open.git] / jacinto6 / sgx_src / eurasia_km / services4 / srvkm / common / pvrsrv.c
1 /*************************************************************************/ /*!
2 @Title core services functions
3 @Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved
4 @Description Main APIs for core services functions
5 @License Dual MIT/GPLv2
7 The contents of this file are subject to the MIT license as set out below.
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
19 Alternatively, the contents of this file may be used under the terms of
20 the GNU General Public License Version 2 ("GPL") in which case the provisions
21 of GPL are applicable instead of those above.
23 If you wish to allow use of your version of this file only under the terms of
24 GPL, and not to allow others to use your version of this file under the terms
25 of the MIT license, indicate your decision by deleting the provisions above
26 and replace them with the notice and other provisions required by GPL as set
27 out in the file called "GPL-COPYING" included in this distribution. If you do
28 not delete the provisions above, a recipient may use your version of this file
29 under the terms of either the MIT license or GPL.
31 This License is also included in this distribution in the file called
32 "MIT-COPYING".
34 EXCEPT AS OTHERWISE STATED IN A NEGOTIATED AGREEMENT: (A) THE SOFTWARE IS
35 PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
36 BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37 PURPOSE AND NONINFRINGEMENT; AND (B) IN NO EVENT SHALL THE AUTHORS OR
38 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
39 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41 */ /**************************************************************************/
43 #include "services_headers.h"
44 #include "buffer_manager.h"
45 #include "pvr_bridge_km.h"
46 #include "handle.h"
47 #include "perproc.h"
48 #include "pdump_km.h"
49 #include "deviceid.h"
50 #include "ra.h"
51 #if defined(TTRACE)
52 #include "ttrace.h"
53 #endif
54 #include "perfkm.h"
55 #include "devicemem.h"
57 #include "pvrversion.h"
59 #include "lists.h"
61 IMG_UINT32 g_ui32InitFlags;
62 IMG_UINT32 g_iDrmFd = -1;
64 /* mark which parts of Services were initialised */
65 #define INIT_DATA_ENABLE_PDUMPINIT 0x1U
66 #define INIT_DATA_ENABLE_TTRACE 0x2U
67 #define INIT_DATA_ENABLE_DEVMEM 0x4U
69 /*!
70 ******************************************************************************
72 @Function AllocateDeviceID
74 @Description
76 allocates a device id from the pool of valid ids
78 @input psSysData : system data
80 @input pui32DevID : device id to return
82 @Return device id
84 ******************************************************************************/
85 PVRSRV_ERROR AllocateDeviceID(SYS_DATA *psSysData, IMG_UINT32 *pui32DevID)
86 {
87 SYS_DEVICE_ID* psDeviceWalker;
88 SYS_DEVICE_ID* psDeviceEnd;
90 psDeviceWalker = &psSysData->sDeviceID[0];
91 psDeviceEnd = psDeviceWalker + psSysData->ui32NumDevices;
93 /* find a free ID */
94 while (psDeviceWalker < psDeviceEnd)
95 {
96 if (!psDeviceWalker->bInUse)
97 {
98 psDeviceWalker->bInUse = IMG_TRUE;
99 *pui32DevID = psDeviceWalker->uiID;
100 return PVRSRV_OK;
101 }
102 psDeviceWalker++;
103 }
105 PVR_DPF((PVR_DBG_ERROR,"AllocateDeviceID: No free and valid device IDs available!"));
107 /* Should never get here: sDeviceID[] may have been setup too small */
108 PVR_ASSERT(psDeviceWalker < psDeviceEnd);
110 return PVRSRV_ERROR_NO_FREE_DEVICEIDS_AVALIABLE;
111 }
114 /*!
115 ******************************************************************************
117 @Function FreeDeviceID
119 @Description
121 frees a device id from the pool of valid ids
123 @input psSysData : system data
125 @input ui32DevID : device id to free
127 @Return device id
129 ******************************************************************************/
130 PVRSRV_ERROR FreeDeviceID(SYS_DATA *psSysData, IMG_UINT32 ui32DevID)
131 {
132 SYS_DEVICE_ID* psDeviceWalker;
133 SYS_DEVICE_ID* psDeviceEnd;
135 psDeviceWalker = &psSysData->sDeviceID[0];
136 psDeviceEnd = psDeviceWalker + psSysData->ui32NumDevices;
138 /* find the ID to free */
139 while (psDeviceWalker < psDeviceEnd)
140 {
141 /* if matching id and in use, free */
142 if (
143 (psDeviceWalker->uiID == ui32DevID) &&
144 (psDeviceWalker->bInUse)
145 )
146 {
147 psDeviceWalker->bInUse = IMG_FALSE;
148 return PVRSRV_OK;
149 }
150 psDeviceWalker++;
151 }
153 PVR_DPF((PVR_DBG_ERROR,"FreeDeviceID: no matching dev ID that is in use!"));
155 /* should never get here */
156 PVR_ASSERT(psDeviceWalker < psDeviceEnd);
158 return PVRSRV_ERROR_INVALID_DEVICEID;
159 }
160 /*!
161 ******************************************************************************
163 @Function PVRSRVCompatCheckKM
165 @Description UM/KM ddk branch Compatibility check function
167 @input psUserModeDDKDetails: User mode DDK version
169 @output In case of incompatibility, returns PVRSRV_ERROR_DDK_VERSION_MISMATCH
171 @Return PVRSRV_ERROR
173 ******************************************************************************/
174 IMG_VOID IMG_CALLCONV PVRSRVCompatCheckKM(PVRSRV_BRIDGE_IN_COMPAT_CHECK *psUserModeDDKDetails, PVRSRV_BRIDGE_RETURN *psRetOUT)
175 {
177 if(psUserModeDDKDetails->ui32DDKVersion != ((PVRVERSION_MAJ << 16) | (PVRVERSION_MIN << 8))
178 || (psUserModeDDKDetails->ui32DDKBuild != PVRVERSION_BUILD))
179 {
180 psRetOUT->eError = PVRSRV_ERROR_DDK_VERSION_MISMATCH;
181 PVR_LOG(("(FAIL) UM-KM DDK Mismatch UM-(%d) KM-(%d).",
182 psUserModeDDKDetails->ui32DDKBuild, PVRVERSION_BUILD));
183 }
184 else
185 {
186 psRetOUT->eError = PVRSRV_OK;
187 PVR_LOG(("UM DDK-(%d) and KM DDK-(%d) match. [ OK ]",
188 psUserModeDDKDetails->ui32DDKBuild ,PVRVERSION_BUILD));
189 }
190 }
192 /*!
193 ******************************************************************************
195 @Function ReadHWReg
197 @Description
199 register access function
201 @input pvLinRegBaseAddr : lin addr of register block base
203 @input ui32Offset : byte offset from register base
205 @Return register value
207 ******************************************************************************/
208 #ifndef ReadHWReg
209 IMG_EXPORT
210 IMG_UINT32 ReadHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset)
211 {
212 return *(volatile IMG_UINT32*)((IMG_UINTPTR_T)pvLinRegBaseAddr+ui32Offset);
213 }
214 #endif
217 /*!
218 ******************************************************************************
220 @Function WriteHWReg
222 @Description
224 register access function
226 @input pvLinRegBaseAddr : lin addr of register block base
228 @input ui32Offset : byte offset from register base
230 @input ui32Value : value to write to register
232 @Return register value : original reg. value
234 ******************************************************************************/
235 #ifndef WriteHWReg
236 IMG_EXPORT
237 IMG_VOID WriteHWReg(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Offset, IMG_UINT32 ui32Value)
238 {
239 PVR_DPF((PVR_DBG_MESSAGE,"WriteHWReg Base:%p, Offset: %x, Value %x",
240 pvLinRegBaseAddr,ui32Offset,ui32Value));
242 *(IMG_UINT32*)((IMG_UINTPTR_T)pvLinRegBaseAddr+ui32Offset) = ui32Value;
243 }
244 #endif
247 /*!
248 ******************************************************************************
250 @Function WriteHWRegs
252 @Description
254 register access function
256 @input pvLinRegBaseAddr : lin addr of register block base
258 @input ui32Count : register count
260 @input psHWRegs : address/value register list
262 @Return none
264 ******************************************************************************/
265 #ifndef WriteHWRegs
266 IMG_EXPORT
267 IMG_VOID WriteHWRegs(IMG_PVOID pvLinRegBaseAddr, IMG_UINT32 ui32Count, PVRSRV_HWREG *psHWRegs)
268 {
269 while (ui32Count)
270 {
271 WriteHWReg (pvLinRegBaseAddr, psHWRegs->ui32RegAddr, psHWRegs->ui32RegVal);
272 psHWRegs++;
273 ui32Count--;
274 }
275 }
276 #endif
278 /*!
279 ******************************************************************************
280 @Function PVRSRVEnumerateDCKM_ForEachVaCb
282 @Description
284 Enumerates the device node (if is of the same class as given).
286 @Input psDeviceNode - The device node to be enumerated
287 va - variable arguments list, with:
288 pui32DevCount - The device count pointer (to be increased)
289 ppui32DevID - The pointer to the device IDs pointer (to be updated and increased)
290 ******************************************************************************/
291 static IMG_VOID PVRSRVEnumerateDevicesKM_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va)
292 {
293 IMG_UINT *pui32DevCount;
294 PVRSRV_DEVICE_IDENTIFIER **ppsDevIdList;
296 pui32DevCount = va_arg(va, IMG_UINT*);
297 ppsDevIdList = va_arg(va, PVRSRV_DEVICE_IDENTIFIER**);
299 if (psDeviceNode->sDevId.eDeviceType != PVRSRV_DEVICE_TYPE_EXT)
300 {
301 *(*ppsDevIdList) = psDeviceNode->sDevId;
302 (*ppsDevIdList)++;
303 (*pui32DevCount)++;
304 }
305 }
309 /*!
310 ******************************************************************************
312 @Function PVRSRVEnumerateDevicesKM
314 @Description
315 This function will enumerate all the devices supported by the
316 PowerVR services within the target system.
317 The function returns a list of the device ID strcutres stored either in
318 the services or constructed in the user mode glue component in certain
319 environments. The number of devices in the list is also returned.
321 In a binary layered component which does not support dynamic runtime selection,
322 the glue code should compile to return the supported devices statically,
323 e.g. multiple instances of the same device if multiple devices are supported,
324 or the target combination of MBX and display device.
326 In the case of an environment (for instance) where one MBX1 may connect to two
327 display devices this code would enumerate all three devices and even
328 non-dynamic MBX1 selection code should retain the facility to parse the list
329 to find the index of the MBX device
331 @output pui32NumDevices : On success, contains the number of devices present
332 in the system
334 @output psDevIdList : Pointer to called supplied buffer to receive the
335 list of PVRSRV_DEVICE_IDENTIFIER
337 @return PVRSRV_ERROR : PVRSRV_NO_ERROR
339 ******************************************************************************/
340 IMG_EXPORT
341 PVRSRV_ERROR IMG_CALLCONV PVRSRVEnumerateDevicesKM(IMG_UINT32 *pui32NumDevices,
342 PVRSRV_DEVICE_IDENTIFIER *psDevIdList)
343 {
344 SYS_DATA *psSysData;
345 /* PVRSRV_DEVICE_NODE *psDeviceNode; */
346 IMG_UINT32 i;
348 if (!pui32NumDevices || !psDevIdList)
349 {
350 PVR_DPF((PVR_DBG_ERROR,"PVRSRVEnumerateDevicesKM: Invalid params"));
351 return PVRSRV_ERROR_INVALID_PARAMS;
352 }
354 SysAcquireData(&psSysData);
356 /*
357 setup input buffer to be `empty'
358 */
359 for (i=0; i<PVRSRV_MAX_DEVICES; i++)
360 {
361 psDevIdList[i].eDeviceType = PVRSRV_DEVICE_TYPE_UNKNOWN;
362 }
364 /* and zero device count */
365 *pui32NumDevices = 0;
367 /*
368 Search through the device list for services managed devices
369 return id info for each device and the number of devices
370 available
371 */
372 List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList,
373 &PVRSRVEnumerateDevicesKM_ForEachVaCb,
374 pui32NumDevices,
375 &psDevIdList);
378 return PVRSRV_OK;
379 }
382 /*!
383 ******************************************************************************
385 @Function PVRSRVInit
387 @Description Initialise services
389 @Input psSysData : sysdata structure
391 @Return PVRSRV_ERROR :
393 ******************************************************************************/
394 PVRSRV_ERROR IMG_CALLCONV PVRSRVInit(PSYS_DATA psSysData)
395 {
396 PVRSRV_ERROR eError;
398 /* Initialise Resource Manager */
399 eError = ResManInit();
400 if (eError != PVRSRV_OK)
401 {
402 goto Error;
403 }
405 eError = PVRSRVPerProcessDataInit();
406 if(eError != PVRSRV_OK)
407 {
408 goto Error;
409 }
411 /* Initialise handles */
412 eError = PVRSRVHandleInit();
413 if(eError != PVRSRV_OK)
414 {
415 goto Error;
416 }
418 /* Initialise Power Manager Lock */
419 eError = OSCreateResource(&psSysData->sPowerStateChangeResource);
420 if (eError != PVRSRV_OK)
421 {
422 goto Error;
423 }
425 /* Initialise system power state */
426 psSysData->eCurrentPowerState = PVRSRV_SYS_POWER_STATE_D0;
427 psSysData->eFailedPowerState = PVRSRV_SYS_POWER_STATE_Unspecified;
429 /* Create an event object */
430 if((eError = OSAllocMem( PVRSRV_PAGEABLE_SELECT,
431 sizeof(PVRSRV_EVENTOBJECT) ,
432 (IMG_VOID **)&psSysData->psGlobalEventObject, 0,
433 "Event Object")) != PVRSRV_OK)
434 {
436 goto Error;
437 }
439 if((eError = OSEventObjectCreateKM("PVRSRV_GLOBAL_EVENTOBJECT", psSysData->psGlobalEventObject)) != PVRSRV_OK)
440 {
441 goto Error;
442 }
444 /* Store OS high res timer fallbacks, the system is free to overide these */
445 psSysData->pfnHighResTimerCreate = OSFuncHighResTimerCreate;
446 psSysData->pfnHighResTimerGetus = OSFuncHighResTimerGetus;
447 psSysData->pfnHighResTimerDestroy = OSFuncHighResTimerDestroy;
449 #if defined(TTRACE)
450 eError = PVRSRVTimeTraceInit();
451 if (eError != PVRSRV_OK)
452 goto Error;
453 g_ui32InitFlags |= INIT_DATA_ENABLE_TTRACE;
454 #endif
456 #if defined(PDUMP)
457 /* Initialise pdump */
458 PDUMPINIT();
459 g_ui32InitFlags |= INIT_DATA_ENABLE_PDUMPINIT;
460 #endif
462 #if defined(SUPPORT_ION) || defined(SUPPORT_DRM_GEM)
463 eError = PVRSRVInitDeviceMem();
464 if (eError != PVRSRV_OK)
465 goto Error;
466 g_ui32InitFlags |= INIT_DATA_ENABLE_DEVMEM;
467 #endif
469 PERFINIT();
470 return eError;
472 Error:
473 PVRSRVDeInit(psSysData);
474 return eError;
475 }
479 /*!
480 ******************************************************************************
482 @Function PVRSRVDeInit
484 @Description De-Initialise services
486 @Input psSysData : sysdata structure
488 @Return PVRSRV_ERROR :
490 ******************************************************************************/
491 IMG_VOID IMG_CALLCONV PVRSRVDeInit(PSYS_DATA psSysData)
492 {
493 PVRSRV_ERROR eError;
495 PVR_UNREFERENCED_PARAMETER(psSysData);
497 if (psSysData == IMG_NULL)
498 {
499 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeInit: PVRSRVHandleDeInit failed - invalid param"));
500 return;
501 }
503 PERFDEINIT();
506 #if defined(SUPPORT_ION) || defined(SUPPORT_DRM_GEM)
507 if ((g_ui32InitFlags & INIT_DATA_ENABLE_DEVMEM) > 0)
508 {
509 PVRSRVDeInitDeviceMem();
510 }
511 #endif
513 #if defined(MEM_TRACK_INFO_DEBUG)
514 /* Free the list of memory operations */
515 PVRSRVFreeMemOps();
516 #endif
518 #if defined(TTRACE)
519 /* deinitialise ttrace */
520 if ((g_ui32InitFlags & INIT_DATA_ENABLE_TTRACE) > 0)
521 {
522 PVRSRVTimeTraceDeinit();
523 }
524 #endif
526 #if defined(PDUMP)
527 /* deinitialise pdump */
528 if( (g_ui32InitFlags & INIT_DATA_ENABLE_PDUMPINIT) > 0)
529 {
530 PDUMPDEINIT();
531 }
532 #endif
534 /* destroy event object */
535 if(psSysData->psGlobalEventObject)
536 {
537 OSEventObjectDestroyKM(psSysData->psGlobalEventObject);
538 OSFreeMem( PVRSRV_PAGEABLE_SELECT,
539 sizeof(PVRSRV_EVENTOBJECT),
540 psSysData->psGlobalEventObject,
541 0);
542 psSysData->psGlobalEventObject = IMG_NULL;
543 }
545 eError = PVRSRVHandleDeInit();
546 if (eError != PVRSRV_OK)
547 {
548 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeInit: PVRSRVHandleDeInit failed"));
549 }
551 eError = PVRSRVPerProcessDataDeInit();
552 if (eError != PVRSRV_OK)
553 {
554 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeInit: PVRSRVPerProcessDataDeInit failed"));
555 }
557 ResManDeInit();
558 }
561 /*!
562 ******************************************************************************
564 @Function PVRSRVRegisterDevice
566 @Description
568 registers a device with the system
570 @Input psSysData : sysdata structure
572 @Input pfnRegisterDevice : device registration function
574 @Input ui32SOCInterruptBit : SoC interrupt bit for this device
576 @Output pui32DeviceIndex : unique device key (for case of multiple identical devices)
578 @Return PVRSRV_ERROR :
580 ******************************************************************************/
581 PVRSRV_ERROR IMG_CALLCONV PVRSRVRegisterDevice(PSYS_DATA psSysData,
582 PVRSRV_ERROR (*pfnRegisterDevice)(PVRSRV_DEVICE_NODE*),
583 IMG_UINT32 ui32SOCInterruptBit,
584 IMG_UINT32 *pui32DeviceIndex)
585 {
586 PVRSRV_ERROR eError;
587 PVRSRV_DEVICE_NODE *psDeviceNode;
589 /* Allocate device node */
590 if(OSAllocMem( PVRSRV_OS_NON_PAGEABLE_HEAP,
591 sizeof(PVRSRV_DEVICE_NODE),
592 (IMG_VOID **)&psDeviceNode, IMG_NULL,
593 "Device Node") != PVRSRV_OK)
594 {
595 PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDevice : Failed to alloc memory for psDeviceNode"));
596 return (PVRSRV_ERROR_OUT_OF_MEMORY);
597 }
598 OSMemSet (psDeviceNode, 0, sizeof(PVRSRV_DEVICE_NODE));
600 eError = pfnRegisterDevice(psDeviceNode);
601 if (eError != PVRSRV_OK)
602 {
603 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
604 sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL);
605 /*not nulling pointer, out of scope*/
606 PVR_DPF((PVR_DBG_ERROR,"PVRSRVRegisterDevice : Failed to register device"));
607 return (PVRSRV_ERROR_DEVICE_REGISTER_FAILED);
608 }
610 /*
611 make the refcount 1 and test on this to initialise device
612 at acquiredevinfo. On release if refcount is 1, deinitialise
613 and when refcount is 0 (sysdata de-alloc) deallocate the device
614 structures
615 */
616 psDeviceNode->ui32RefCount = 1;
617 psDeviceNode->psSysData = psSysData;
618 psDeviceNode->ui32SOCInterruptBit = ui32SOCInterruptBit;
620 /* all devices need a unique identifier */
621 AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex);
623 /* and finally insert the device into the dev-list */
624 List_PVRSRV_DEVICE_NODE_Insert(&psSysData->psDeviceNodeList, psDeviceNode);
626 /* and copy back index */
627 *pui32DeviceIndex = psDeviceNode->sDevId.ui32DeviceIndex;
629 return PVRSRV_OK;
630 }
633 /*!
634 ******************************************************************************
636 @Function PVRSRVInitialiseDevice
638 @Description
640 initialises device by index
642 @Input ui32DevIndex : Index to the required device
644 @Return PVRSRV_ERROR :
646 ******************************************************************************/
647 PVRSRV_ERROR IMG_CALLCONV PVRSRVInitialiseDevice (IMG_UINT32 ui32DevIndex)
648 {
649 PVRSRV_DEVICE_NODE *psDeviceNode;
650 SYS_DATA *psSysData;
651 PVRSRV_ERROR eError;
653 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVInitialiseDevice"));
655 SysAcquireData(&psSysData);
657 /* Find device in the list */
658 psDeviceNode = (PVRSRV_DEVICE_NODE*)
659 List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
660 &MatchDeviceKM_AnyVaCb,
661 ui32DevIndex,
662 IMG_TRUE);
663 if(!psDeviceNode)
664 {
665 /* Devinfo not in the list */
666 PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: requested device is not present"));
667 return PVRSRV_ERROR_INIT_FAILURE;
668 }
669 /*
670 FoundDevice:
671 */
673 PVR_ASSERT (psDeviceNode->ui32RefCount > 0);
675 /*
676 Create the device's resource manager context.
677 */
678 eError = PVRSRVResManConnect(IMG_NULL, &psDeviceNode->hResManContext);
679 if (eError != PVRSRV_OK)
680 {
681 PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: Failed PVRSRVResManConnect call"));
682 return eError;
683 }
685 /* Initialise the device */
686 if(psDeviceNode->pfnInitDevice != IMG_NULL)
687 {
688 eError = psDeviceNode->pfnInitDevice(psDeviceNode);
689 if (eError != PVRSRV_OK)
690 {
691 PVR_DPF((PVR_DBG_ERROR,"PVRSRVInitialiseDevice: Failed InitDevice call"));
692 return eError;
693 }
694 }
696 return PVRSRV_OK;
697 }
700 static PVRSRV_ERROR PVRSRVFinaliseSystem_SetPowerState_AnyCb(PVRSRV_DEVICE_NODE *psDeviceNode)
701 {
702 PVRSRV_ERROR eError;
704 eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE);
705 if (eError != PVRSRV_OK)
706 {
707 PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVPowerLock call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex));
708 return eError;
709 }
711 eError = PVRSRVSetDevicePowerStateKM(psDeviceNode->sDevId.ui32DeviceIndex,
712 PVRSRV_DEV_POWER_STATE_DEFAULT);
713 PVRSRVPowerUnlock(KERNEL_ID);
714 if (eError != PVRSRV_OK)
715 {
716 PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVSetDevicePowerStateKM call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex));
717 }
718 return eError;
719 }
721 /*wraps the PVRSRVDevInitCompatCheck call and prints a debugging message if failed*/
722 static PVRSRV_ERROR PVRSRVFinaliseSystem_CompatCheck_AnyCb(PVRSRV_DEVICE_NODE *psDeviceNode)
723 {
724 PVRSRV_ERROR eError;
725 eError = PVRSRVDevInitCompatCheck(psDeviceNode);
726 if (eError != PVRSRV_OK)
727 {
728 PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: Failed PVRSRVDevInitCompatCheck call (device index: %d)", psDeviceNode->sDevId.ui32DeviceIndex));
729 }
730 return eError;
731 }
734 /*!
735 ******************************************************************************
737 @Function PVRSRVFinaliseSystem
739 @Description
741 Final part of system initialisation.
743 @Input ui32DevIndex : Index to the required device
745 @Return PVRSRV_ERROR :
747 ******************************************************************************/
748 PVRSRV_ERROR IMG_CALLCONV PVRSRVFinaliseSystem(IMG_BOOL bInitSuccessful)
749 {
750 /* PVRSRV_DEVICE_NODE *psDeviceNode;*/
751 SYS_DATA *psSysData;
752 PVRSRV_ERROR eError;
754 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVFinaliseSystem"));
756 SysAcquireData(&psSysData);
758 if (bInitSuccessful)
759 {
760 eError = SysFinalise();
761 if (eError != PVRSRV_OK)
762 {
763 PVR_DPF((PVR_DBG_ERROR,"PVRSRVFinaliseSystem: SysFinalise failed (%d)", eError));
764 return eError;
765 }
767 /* Place all devices into their default power state. */
768 eError = List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any(psSysData->psDeviceNodeList,
769 &PVRSRVFinaliseSystem_SetPowerState_AnyCb);
770 if (eError != PVRSRV_OK)
771 {
772 return eError;
773 }
775 /* Verify microkernel compatibility for devices */
776 eError = List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any(psSysData->psDeviceNodeList,
777 &PVRSRVFinaliseSystem_CompatCheck_AnyCb);
778 if (eError != PVRSRV_OK)
779 {
780 return eError;
781 }
782 }
784 /* Some platforms call this too early in the boot phase. */
785 PDUMPENDINITPHASE();
787 return PVRSRV_OK;
788 }
791 PVRSRV_ERROR PVRSRVDevInitCompatCheck(PVRSRV_DEVICE_NODE *psDeviceNode)
792 {
793 /* Only check devices which specify a compatibility check callback */
794 if (psDeviceNode->pfnInitDeviceCompatCheck)
795 return psDeviceNode->pfnInitDeviceCompatCheck(psDeviceNode);
796 else
797 return PVRSRV_OK;
798 }
800 /*!
801 ******************************************************************************
803 @Function PVRSRVAcquireDeviceDataKM
805 @Description
807 Matchs a device given a device type and a device index.
809 @input psDeviceNode :The device node to be matched.
811 @Input va : Variable argument list with:
812 eDeviceType : Required device type. If type is unknown use ui32DevIndex
813 to locate device data
815 ui32DevIndex : Index to the required device obtained from the
816 PVRSRVEnumerateDevice function
818 @Return PVRSRV_ERROR :
820 ******************************************************************************/
821 static IMG_VOID * PVRSRVAcquireDeviceDataKM_Match_AnyVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va)
822 {
823 PVRSRV_DEVICE_TYPE eDeviceType;
824 IMG_UINT32 ui32DevIndex;
826 eDeviceType = va_arg(va, PVRSRV_DEVICE_TYPE);
827 ui32DevIndex = va_arg(va, IMG_UINT32);
829 if ((eDeviceType != PVRSRV_DEVICE_TYPE_UNKNOWN &&
830 psDeviceNode->sDevId.eDeviceType == eDeviceType) ||
831 (eDeviceType == PVRSRV_DEVICE_TYPE_UNKNOWN &&
832 psDeviceNode->sDevId.ui32DeviceIndex == ui32DevIndex))
833 {
834 return psDeviceNode;
835 }
836 else
837 {
838 return IMG_NULL;
839 }
840 }
842 /*!
843 ******************************************************************************
845 @Function PVRSRVAcquireDeviceDataKM
847 @Description
849 Returns device information
851 @Input ui32DevIndex : Index to the required device obtained from the
852 PVRSRVEnumerateDevice function
854 @Input eDeviceType : Required device type. If type is unknown use ui32DevIndex
855 to locate device data
857 @Output *phDevCookie : Dev Cookie
860 @Return PVRSRV_ERROR :
862 ******************************************************************************/
863 IMG_EXPORT
864 PVRSRV_ERROR IMG_CALLCONV PVRSRVAcquireDeviceDataKM (IMG_UINT32 ui32DevIndex,
865 PVRSRV_DEVICE_TYPE eDeviceType,
866 IMG_HANDLE *phDevCookie)
867 {
868 PVRSRV_DEVICE_NODE *psDeviceNode;
869 SYS_DATA *psSysData;
871 PVR_DPF((PVR_DBG_MESSAGE, "PVRSRVAcquireDeviceDataKM"));
873 SysAcquireData(&psSysData);
875 /* Find device in the list */
876 psDeviceNode = List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
877 &PVRSRVAcquireDeviceDataKM_Match_AnyVaCb,
878 eDeviceType,
879 ui32DevIndex);
882 if (!psDeviceNode)
883 {
884 /* device can't be found in the list so it isn't in the system */
885 PVR_DPF((PVR_DBG_ERROR,"PVRSRVAcquireDeviceDataKM: requested device is not present"));
886 return PVRSRV_ERROR_INIT_FAILURE;
887 }
889 /*FoundDevice:*/
891 PVR_ASSERT (psDeviceNode->ui32RefCount > 0);
893 /* return the dev cookie? */
894 if (phDevCookie)
895 {
896 *phDevCookie = (IMG_HANDLE)psDeviceNode;
897 }
899 return PVRSRV_OK;
900 }
903 /*!
904 ******************************************************************************
906 @Function PVRSRVDeinitialiseDevice
908 @Description
910 This De-inits device
912 @Input ui32DevIndex : Index to the required device
914 @Return PVRSRV_ERROR :
916 ******************************************************************************/
917 PVRSRV_ERROR IMG_CALLCONV PVRSRVDeinitialiseDevice(IMG_UINT32 ui32DevIndex)
918 {
919 PVRSRV_DEVICE_NODE *psDeviceNode;
920 SYS_DATA *psSysData;
921 PVRSRV_ERROR eError;
923 SysAcquireData(&psSysData);
925 psDeviceNode = (PVRSRV_DEVICE_NODE*)
926 List_PVRSRV_DEVICE_NODE_Any_va(psSysData->psDeviceNodeList,
927 &MatchDeviceKM_AnyVaCb,
928 ui32DevIndex,
929 IMG_TRUE);
931 if (!psDeviceNode)
932 {
933 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: requested device %d is not present", ui32DevIndex));
934 return PVRSRV_ERROR_DEVICEID_NOT_FOUND;
935 }
937 eError = PVRSRVPowerLock(KERNEL_ID, IMG_FALSE);
938 if (eError != PVRSRV_OK)
939 {
940 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed PVRSRVPowerLock call"));
941 return eError;
942 }
944 /*
945 Power down the device if necessary.
946 */
947 eError = PVRSRVSetDevicePowerStateKM(ui32DevIndex,
948 PVRSRV_DEV_POWER_STATE_OFF);
949 PVRSRVPowerUnlock(KERNEL_ID);
950 if (eError != PVRSRV_OK)
951 {
952 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed PVRSRVSetDevicePowerStateKM call"));
953 return eError;
954 }
956 /*
957 Free the dissociated device memory.
958 */
959 eError = ResManFreeResByCriteria(psDeviceNode->hResManContext,
960 RESMAN_CRITERIA_RESTYPE,
961 RESMAN_TYPE_DEVICEMEM_ALLOCATION,
962 IMG_NULL, 0);
963 if (eError != PVRSRV_OK)
964 {
965 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed ResManFreeResByCriteria call"));
966 return eError;
967 }
969 /*
970 De-init the device.
971 */
972 if(psDeviceNode->pfnDeInitDevice != IMG_NULL)
973 {
974 eError = psDeviceNode->pfnDeInitDevice(psDeviceNode);
975 if (eError != PVRSRV_OK)
976 {
977 PVR_DPF((PVR_DBG_ERROR,"PVRSRVDeinitialiseDevice: Failed DeInitDevice call"));
978 return eError;
979 }
980 }
982 /*
983 Close the device's resource manager context.
984 */
985 PVRSRVResManDisconnect(psDeviceNode->hResManContext, IMG_TRUE);
986 psDeviceNode->hResManContext = IMG_NULL;
988 /* remove node from list */
989 List_PVRSRV_DEVICE_NODE_Remove(psDeviceNode);
991 /* deallocate id and memory */
992 (IMG_VOID)FreeDeviceID(psSysData, ui32DevIndex);
993 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
994 sizeof(PVRSRV_DEVICE_NODE), psDeviceNode, IMG_NULL);
995 /*not nulling pointer, out of scope*/
997 return (PVRSRV_OK);
998 }
1001 IMG_EXPORT
1002 PVRSRV_ERROR IMG_CALLCONV PollForValueKM (volatile IMG_UINT32* pui32LinMemAddr,
1003 IMG_UINT32 ui32Value,
1004 IMG_UINT32 ui32Mask,
1005 IMG_UINT32 ui32Timeoutus,
1006 IMG_UINT32 ui32PollPeriodus,
1007 IMG_BOOL bAllowPreemption)
1008 {
1009 #if defined (EMULATOR)
1010 {
1011 PVR_UNREFERENCED_PARAMETER(bAllowPreemption);
1012 #if !defined(__linux__)
1013 PVR_UNREFERENCED_PARAMETER(ui32PollPeriodus);
1014 #endif
1016 /* For the Emulator we want the system to stop when a lock-up is detected so the state can be analysed.
1017 * Also the Emulator is much slower than real silicon so timeouts are not valid.
1018 */
1019 do
1020 {
1021 if((*pui32LinMemAddr & ui32Mask) == ui32Value)
1022 {
1023 return PVRSRV_OK;
1024 }
1026 #if defined(__linux__)
1027 OSWaitus(ui32PollPeriodus);
1028 #else
1029 OSReleaseThreadQuanta();
1030 #endif
1032 } while (ui32Timeoutus); /* Endless loop only for the Emulator */
1033 }
1034 #else
1035 {
1036 IMG_UINT32 ui32ActualValue = 0xFFFFFFFFU; /* Initialiser only required to prevent incorrect warning */
1038 if (bAllowPreemption)
1039 {
1040 PVR_ASSERT(ui32PollPeriodus >= 1000);
1041 }
1043 /* PRQA S 3415,4109 1 */ /* macro format critical - leave alone */
1044 LOOP_UNTIL_TIMEOUT(ui32Timeoutus)
1045 {
1046 ui32ActualValue = (*pui32LinMemAddr & ui32Mask);
1047 if(ui32ActualValue == ui32Value)
1048 {
1049 return PVRSRV_OK;
1050 }
1052 if (bAllowPreemption)
1053 {
1054 OSSleepms(ui32PollPeriodus / 1000);
1055 }
1056 else
1057 {
1058 OSWaitus(ui32PollPeriodus);
1059 }
1060 } END_LOOP_UNTIL_TIMEOUT();
1062 PVR_DPF((PVR_DBG_ERROR,"PollForValueKM: Timeout. Expected 0x%x but found 0x%x (mask 0x%x).",
1063 ui32Value, ui32ActualValue, ui32Mask));
1064 }
1065 #endif /* #if defined (EMULATOR) */
1067 return PVRSRV_ERROR_TIMEOUT;
1068 }
1071 /*Level 3 of the loop nesting*/
1072 static IMG_VOID PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb(BM_HEAP *psBMHeap, va_list va)
1073 {
1074 IMG_CHAR **ppszStr;
1075 IMG_UINT32 *pui32StrLen;
1076 IMG_UINT32 ui32Mode;
1077 PVRSRV_ERROR (*pfnGetStats)(RA_ARENA *, IMG_CHAR **, IMG_UINT32 *);
1079 ppszStr = va_arg(va, IMG_CHAR**);
1080 pui32StrLen = va_arg(va, IMG_UINT32*);
1081 ui32Mode = va_arg(va, IMG_UINT32);
1083 /* Would be better to pass fn pointer in the variable args list
1084 * but MS C compiler complains with error C2066: In ANSI C,
1085 * it is not legal to cast between a function pointer and a data pointer.
1086 */
1087 switch(ui32Mode)
1088 {
1089 case PVRSRV_MISC_INFO_MEMSTATS_PRESENT:
1090 pfnGetStats = &RA_GetStats;
1091 break;
1092 case PVRSRV_MISC_INFO_FREEMEM_PRESENT:
1093 pfnGetStats = &RA_GetStatsFreeMem;
1094 break;
1095 default:
1096 return;
1097 }
1099 if(psBMHeap->pImportArena)
1100 {
1101 pfnGetStats(psBMHeap->pImportArena,
1102 ppszStr,
1103 pui32StrLen);
1104 }
1106 if(psBMHeap->pVMArena)
1107 {
1108 pfnGetStats(psBMHeap->pVMArena,
1109 ppszStr,
1110 pui32StrLen);
1111 }
1112 }
1114 /*Level 2 of the loop nesting*/
1115 static PVRSRV_ERROR PVRSRVGetMiscInfoKM_BMContext_AnyVaCb(BM_CONTEXT *psBMContext, va_list va)
1116 {
1118 IMG_UINT32 *pui32StrLen;
1119 IMG_INT32 *pi32Count;
1120 IMG_CHAR **ppszStr;
1121 IMG_UINT32 ui32Mode;
1123 pui32StrLen = va_arg(va, IMG_UINT32*);
1124 pi32Count = va_arg(va, IMG_INT32*);
1125 ppszStr = va_arg(va, IMG_CHAR**);
1126 ui32Mode = va_arg(va, IMG_UINT32);
1128 CHECK_SPACE(*pui32StrLen);
1129 *pi32Count = OSSNPrintf(*ppszStr, 100, "\nApplication Context (hDevMemContext) %p:\n",
1130 (IMG_HANDLE)psBMContext);
1131 UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen);
1133 List_BM_HEAP_ForEach_va(psBMContext->psBMHeap,
1134 &PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb,
1135 ppszStr,
1136 pui32StrLen,
1137 ui32Mode);
1138 return PVRSRV_OK;
1139 }
1142 /*level 1 of the loop nesting*/
1143 static PVRSRV_ERROR PVRSRVGetMiscInfoKM_Device_AnyVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va)
1144 {
1145 IMG_UINT32 *pui32StrLen;
1146 IMG_INT32 *pi32Count;
1147 IMG_CHAR **ppszStr;
1148 IMG_UINT32 ui32Mode;
1150 pui32StrLen = va_arg(va, IMG_UINT32*);
1151 pi32Count = va_arg(va, IMG_INT32*);
1152 ppszStr = va_arg(va, IMG_CHAR**);
1153 ui32Mode = va_arg(va, IMG_UINT32);
1155 CHECK_SPACE(*pui32StrLen);
1156 *pi32Count = OSSNPrintf(*ppszStr, 100, "\n\nDevice Type %d:\n", psDeviceNode->sDevId.eDeviceType);
1157 UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen);
1159 /* kernel context: */
1160 if(psDeviceNode->sDevMemoryInfo.pBMKernelContext)
1161 {
1162 CHECK_SPACE(*pui32StrLen);
1163 *pi32Count = OSSNPrintf(*ppszStr, 100, "\nKernel Context:\n");
1164 UPDATE_SPACE(*ppszStr, *pi32Count, *pui32StrLen);
1166 List_BM_HEAP_ForEach_va(psDeviceNode->sDevMemoryInfo.pBMKernelContext->psBMHeap,
1167 &PVRSRVGetMiscInfoKM_RA_GetStats_ForEachVaCb,
1168 ppszStr,
1169 pui32StrLen,
1170 ui32Mode);
1171 }
1173 /* double loop app contexts:heaps */
1174 return List_BM_CONTEXT_PVRSRV_ERROR_Any_va(psDeviceNode->sDevMemoryInfo.pBMContext,
1175 &PVRSRVGetMiscInfoKM_BMContext_AnyVaCb,
1176 pui32StrLen,
1177 pi32Count,
1178 ppszStr,
1179 ui32Mode);
1180 }
1183 /*!
1184 ******************************************************************************
1186 @Function PVRSRVGetMiscInfoKM
1188 @Description
1189 Retrieves misc. info.
1191 @Output PVRSRV_MISC_INFO
1193 @Return PVRSRV_ERROR :
1195 ******************************************************************************/
1196 IMG_EXPORT
1197 PVRSRV_ERROR IMG_CALLCONV PVRSRVGetMiscInfoKM(PVRSRV_MISC_INFO *psMiscInfo)
1198 {
1199 SYS_DATA *psSysData;
1201 if(!psMiscInfo)
1202 {
1203 PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid parameters"));
1204 return PVRSRV_ERROR_INVALID_PARAMS;
1205 }
1207 psMiscInfo->ui32StatePresent = 0;
1209 /* do a basic check for uninitialised request flag */
1210 if(psMiscInfo->ui32StateRequest & ~(PVRSRV_MISC_INFO_TIMER_PRESENT
1211 |PVRSRV_MISC_INFO_CLOCKGATE_PRESENT
1212 |PVRSRV_MISC_INFO_MEMSTATS_PRESENT
1213 |PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT
1214 |PVRSRV_MISC_INFO_DDKVERSION_PRESENT
1215 |PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT
1216 |PVRSRV_MISC_INFO_RESET_PRESENT
1217 |PVRSRV_MISC_INFO_FREEMEM_PRESENT
1218 |PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT
1219 |PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT
1220 |PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT
1221 |PVRSRV_MISC_INFO_GET_DRM_FD_PRESENT
1222 |PVRSRV_MISC_INFO_SET_DRM_FD_PRESENT))
1223 {
1224 PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: invalid state request flags"));
1225 return PVRSRV_ERROR_INVALID_PARAMS;
1226 }
1228 SysAcquireData(&psSysData);
1230 /* return SOC Timer registers */
1231 if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_TIMER_PRESENT) != 0UL) &&
1232 (psSysData->pvSOCTimerRegisterKM != IMG_NULL))
1233 {
1234 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_TIMER_PRESENT;
1235 psMiscInfo->pvSOCTimerRegisterKM = psSysData->pvSOCTimerRegisterKM;
1236 psMiscInfo->hSOCTimerRegisterOSMemHandle = psSysData->hSOCTimerRegisterOSMemHandle;
1237 }
1238 else
1239 {
1240 psMiscInfo->pvSOCTimerRegisterKM = IMG_NULL;
1241 psMiscInfo->hSOCTimerRegisterOSMemHandle = IMG_NULL;
1242 }
1244 /* return SOC Clock Gating registers */
1245 if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CLOCKGATE_PRESENT) != 0UL) &&
1246 (psSysData->pvSOCClockGateRegsBase != IMG_NULL))
1247 {
1248 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CLOCKGATE_PRESENT;
1249 psMiscInfo->pvSOCClockGateRegs = psSysData->pvSOCClockGateRegsBase;
1250 psMiscInfo->ui32SOCClockGateRegsSize = psSysData->ui32SOCClockGateRegsSize;
1251 }
1253 /* memory stats */
1254 if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) != 0UL) &&
1255 (psMiscInfo->pszMemoryStr != IMG_NULL))
1256 {
1257 RA_ARENA **ppArena;
1258 /* BM_HEAP *psBMHeap;
1259 BM_CONTEXT *psBMContext;
1260 PVRSRV_DEVICE_NODE *psDeviceNode;*/
1261 IMG_CHAR *pszStr;
1262 IMG_UINT32 ui32StrLen;
1263 IMG_INT32 i32Count;
1265 pszStr = psMiscInfo->pszMemoryStr;
1266 ui32StrLen = psMiscInfo->ui32MemoryStrLen;
1268 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_MEMSTATS_PRESENT;
1270 /* Local backing stores */
1271 ppArena = &psSysData->apsLocalDevMemArena[0];
1272 while(*ppArena)
1273 {
1274 CHECK_SPACE(ui32StrLen);
1275 i32Count = OSSNPrintf(pszStr, 100, "\nLocal Backing Store:\n");
1276 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1278 RA_GetStats(*ppArena,
1279 &pszStr,
1280 &ui32StrLen);
1281 /* advance through the array */
1282 ppArena++;
1283 }
1285 /* per device */
1286 /* psDeviceNode = psSysData->psDeviceNodeList;*/
1288 /*triple loop; devices:contexts:heaps*/
1289 List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
1290 &PVRSRVGetMiscInfoKM_Device_AnyVaCb,
1291 &ui32StrLen,
1292 &i32Count,
1293 &pszStr,
1294 PVRSRV_MISC_INFO_MEMSTATS_PRESENT);
1296 /* attach a new line and string terminate */
1297 i32Count = OSSNPrintf(pszStr, 100, "\n");
1298 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1299 }
1301 /* Lean version of mem stats: only show free mem on each RA */
1302 if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FREEMEM_PRESENT) != 0)
1303 && psMiscInfo->pszMemoryStr)
1304 {
1305 IMG_CHAR *pszStr;
1306 IMG_UINT32 ui32StrLen;
1307 IMG_INT32 i32Count;
1309 pszStr = psMiscInfo->pszMemoryStr;
1310 ui32StrLen = psMiscInfo->ui32MemoryStrLen;
1312 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FREEMEM_PRESENT;
1314 /* triple loop over devices:contexts:heaps */
1315 List_PVRSRV_DEVICE_NODE_PVRSRV_ERROR_Any_va(psSysData->psDeviceNodeList,
1316 &PVRSRVGetMiscInfoKM_Device_AnyVaCb,
1317 &ui32StrLen,
1318 &i32Count,
1319 &pszStr,
1320 PVRSRV_MISC_INFO_FREEMEM_PRESENT);
1322 i32Count = OSSNPrintf(pszStr, 100, "\n");
1323 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1324 }
1326 if(((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT) != 0UL) &&
1327 (psSysData->psGlobalEventObject != IMG_NULL))
1328 {
1329 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GLOBALEVENTOBJECT_PRESENT;
1330 psMiscInfo->sGlobalEventObject = *psSysData->psGlobalEventObject;
1331 }
1333 /* DDK version and memstats not supported in same call to GetMiscInfo */
1335 if (((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_DDKVERSION_PRESENT) != 0UL)
1336 && ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_MEMSTATS_PRESENT) == 0UL)
1337 && (psMiscInfo->pszMemoryStr != IMG_NULL))
1338 {
1339 IMG_CHAR *pszStr;
1340 IMG_UINT32 ui32StrLen;
1341 IMG_UINT32 ui32LenStrPerNum = 12; /* string length per UI32: 10 digits + '.' + '\0' = 12 bytes */
1342 IMG_INT32 i32Count;
1343 IMG_INT i;
1344 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_DDKVERSION_PRESENT;
1346 /* construct DDK string */
1347 psMiscInfo->aui32DDKVersion[0] = PVRVERSION_MAJ;
1348 psMiscInfo->aui32DDKVersion[1] = PVRVERSION_MIN;
1349 psMiscInfo->aui32DDKVersion[2] = PVRVERSION_BUILD_HI;
1350 psMiscInfo->aui32DDKVersion[3] = PVRVERSION_BUILD_LO;
1352 pszStr = psMiscInfo->pszMemoryStr;
1353 ui32StrLen = psMiscInfo->ui32MemoryStrLen;
1355 for (i=0; i<4; i++)
1356 {
1357 if (ui32StrLen < ui32LenStrPerNum)
1358 {
1359 return PVRSRV_ERROR_INVALID_PARAMS;
1360 }
1362 i32Count = OSSNPrintf(pszStr, ui32LenStrPerNum, "%u", psMiscInfo->aui32DDKVersion[i]);
1363 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1364 if (i != 3)
1365 {
1366 i32Count = OSSNPrintf(pszStr, 2, ".");
1367 UPDATE_SPACE(pszStr, i32Count, ui32StrLen);
1368 }
1369 }
1370 }
1372 if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT) != 0UL)
1373 {
1374 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_CPUCACHEOP_PRESENT;
1376 if(psMiscInfo->sCacheOpCtl.bDeferOp)
1377 {
1378 /* For now, assume deferred ops are "full" cache ops,
1379 * and we don't need (or expect) a meminfo.
1380 */
1381 psSysData->ePendingCacheOpType = psMiscInfo->sCacheOpCtl.eCacheOpType;
1382 }
1383 else
1384 {
1385 PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
1386 PVRSRV_PER_PROCESS_DATA *psPerProc;
1388 if(!psMiscInfo->sCacheOpCtl.u.psKernelMemInfo)
1389 {
1390 PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
1391 "Ignoring non-deferred cache op with no meminfo"));
1392 return PVRSRV_ERROR_INVALID_PARAMS;
1393 }
1395 if(psSysData->ePendingCacheOpType != PVRSRV_MISC_INFO_CPUCACHEOP_NONE)
1396 {
1397 PVR_DPF((PVR_DBG_WARNING, "PVRSRVGetMiscInfoKM: "
1398 "Deferred cache op is pending. It is unlikely you want "
1399 "to combine deferred cache ops with immediate ones"));
1400 }
1402 psPerProc = PVRSRVFindPerProcessData();
1404 if(PVRSRVLookupHandle(psPerProc->psHandleBase,
1405 (IMG_PVOID *)&psKernelMemInfo,
1406 psMiscInfo->sCacheOpCtl.u.psKernelMemInfo,
1407 PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
1408 {
1409 PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: "
1410 "Can't find kernel meminfo"));
1411 return PVRSRV_ERROR_INVALID_PARAMS;
1412 }
1414 if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_FLUSH)
1415 {
1416 if(!OSFlushCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
1417 0,
1418 psMiscInfo->sCacheOpCtl.pvBaseVAddr,
1419 psMiscInfo->sCacheOpCtl.ui32Length))
1420 {
1421 return PVRSRV_ERROR_CACHEOP_FAILED;
1422 }
1423 }
1424 else if(psMiscInfo->sCacheOpCtl.eCacheOpType == PVRSRV_MISC_INFO_CPUCACHEOP_CLEAN)
1425 {
1426 if(psMiscInfo->sCacheOpCtl.ui32Length!=0)
1427 {
1428 if(!OSCleanCPUCacheRangeKM(psKernelMemInfo->sMemBlk.hOSMemHandle,
1429 0,
1430 psMiscInfo->sCacheOpCtl.pvBaseVAddr,
1431 psMiscInfo->sCacheOpCtl.ui32Length))
1432 {
1433 return PVRSRV_ERROR_CACHEOP_FAILED;
1434 }
1435 }
1436 }
1437 }
1438 }
1440 if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT) != 0UL)
1441 {
1442 PVRSRV_KERNEL_MEM_INFO *psKernelMemInfo;
1443 PVRSRV_PER_PROCESS_DATA *psPerProc;
1445 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_REF_COUNT_PRESENT;
1447 psPerProc = PVRSRVFindPerProcessData();
1449 if(PVRSRVLookupHandle(psPerProc->psHandleBase,
1450 (IMG_PVOID *)&psKernelMemInfo,
1451 psMiscInfo->sGetRefCountCtl.u.psKernelMemInfo,
1452 PVRSRV_HANDLE_TYPE_MEM_INFO) != PVRSRV_OK)
1453 {
1454 PVR_DPF((PVR_DBG_ERROR, "PVRSRVGetMiscInfoKM: "
1455 "Can't find kernel meminfo"));
1456 return PVRSRV_ERROR_INVALID_PARAMS;
1457 }
1459 psMiscInfo->sGetRefCountCtl.ui32RefCount = psKernelMemInfo->ui32RefCount;
1460 }
1462 if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT) != 0UL)
1463 {
1464 psMiscInfo->ui32PageSize = HOST_PAGESIZE();
1465 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_PAGE_SIZE_PRESENT;
1466 }
1468 #if defined(PVRSRV_RESET_ON_HWTIMEOUT)
1469 if((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_RESET_PRESENT) != 0UL)
1470 {
1471 PVR_LOG(("User requested OS reset"));
1472 OSPanic();
1473 }
1474 #endif /* #if defined(PVRSRV_RESET_ON_HWTIMEOUT) */
1476 #if defined(SUPPORT_PVRSRV_DEVICE_CLASS)
1477 if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT) != 0UL)
1478 {
1479 PVRSRVProcessQueues(IMG_TRUE);
1480 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_FORCE_SWAP_TO_SYSTEM_PRESENT;
1481 }
1482 #endif /* defined(SUPPORT_PVRSRV_DEVICE_CLASS) */
1483 if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_GET_DRM_FD_PRESENT) != 0UL)
1484 {
1485 PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: GetDrmFD: %d", g_iDrmFd));
1486 psMiscInfo->iDrmFd = g_iDrmFd;
1487 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_GET_DRM_FD_PRESENT;
1488 }
1489 if ((psMiscInfo->ui32StateRequest & PVRSRV_MISC_INFO_SET_DRM_FD_PRESENT) != 0UL)
1490 {
1491 g_iDrmFd = psMiscInfo->iDrmFd;
1492 PVR_DPF((PVR_DBG_ERROR,"PVRSRVGetMiscInfoKM: SetDrmFD: %d", g_iDrmFd));
1493 psMiscInfo->ui32StatePresent |= PVRSRV_MISC_INFO_SET_DRM_FD_PRESENT;
1494 }
1496 return PVRSRV_OK;
1497 }
1500 /*!
1501 ******************************************************************************
1503 @Function PVRSRVDeviceLISR
1505 @Description
1506 OS-independent Device Low-level Interrupt Service Routine
1508 @Input psDeviceNode
1510 @Return IMG_BOOL : Whether any interrupts were serviced
1512 ******************************************************************************/
1513 IMG_BOOL IMG_CALLCONV PVRSRVDeviceLISR(PVRSRV_DEVICE_NODE *psDeviceNode)
1514 {
1515 SYS_DATA *psSysData;
1516 IMG_BOOL bStatus = IMG_FALSE;
1517 IMG_UINT32 ui32InterruptSource;
1519 if(!psDeviceNode)
1520 {
1521 PVR_DPF((PVR_DBG_ERROR, "PVRSRVDeviceLISR: Invalid params\n"));
1522 goto out;
1523 }
1524 psSysData = psDeviceNode->psSysData;
1526 /* query the SOC/system to see whether this device was the source of the interrupt */
1527 ui32InterruptSource = SysGetInterruptSource(psSysData, psDeviceNode);
1528 if(ui32InterruptSource & psDeviceNode->ui32SOCInterruptBit)
1529 {
1530 if(psDeviceNode->pfnDeviceISR != IMG_NULL)
1531 {
1532 bStatus = (*psDeviceNode->pfnDeviceISR)(psDeviceNode->pvISRData);
1533 }
1535 SysClearInterrupts(psSysData, psDeviceNode->ui32SOCInterruptBit);
1536 }
1538 out:
1539 return bStatus;
1540 }
1542 static IMG_VOID PVRSRVSystemLISR_ForEachVaCb(PVRSRV_DEVICE_NODE *psDeviceNode, va_list va)
1543 {
1545 IMG_BOOL *pbStatus;
1546 IMG_UINT32 *pui32InterruptSource;
1547 IMG_UINT32 *pui32ClearInterrupts;
1549 pbStatus = va_arg(va, IMG_BOOL*);
1550 pui32InterruptSource = va_arg(va, IMG_UINT32*);
1551 pui32ClearInterrupts = va_arg(va, IMG_UINT32*);
1554 if(psDeviceNode->pfnDeviceISR != IMG_NULL)
1555 {
1556 if(*pui32InterruptSource & psDeviceNode->ui32SOCInterruptBit)
1557 {
1558 if((*psDeviceNode->pfnDeviceISR)(psDeviceNode->pvISRData))
1559 {
1560 /* Record if serviced any interrupts. */
1561 *pbStatus = IMG_TRUE;
1562 }
1563 /* Combine the SOC clear bits. */
1564 *pui32ClearInterrupts |= psDeviceNode->ui32SOCInterruptBit;
1565 }
1566 }
1567 }
1569 /*!
1570 ******************************************************************************
1572 @Function PVRSRVSystemLISR
1574 @Description
1575 OS-independent System Low-level Interrupt Service Routine
1577 @Input pvSysData
1579 @Return IMG_BOOL : Whether any interrupts were serviced
1581 ******************************************************************************/
1582 IMG_BOOL IMG_CALLCONV PVRSRVSystemLISR(IMG_VOID *pvSysData)
1583 {
1584 SYS_DATA *psSysData = pvSysData;
1585 IMG_BOOL bStatus = IMG_FALSE;
1586 IMG_UINT32 ui32InterruptSource;
1587 IMG_UINT32 ui32ClearInterrupts = 0;
1588 /* PVRSRV_DEVICE_NODE *psDeviceNode;*/
1590 if(!psSysData)
1591 {
1592 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSystemLISR: Invalid params\n"));
1593 /* goto out; */
1594 }
1595 else
1596 {
1597 /* query SOC for source of interrupts */
1598 ui32InterruptSource = SysGetInterruptSource(psSysData, IMG_NULL);
1600 /* only proceed if PVR interrupts */
1601 if(ui32InterruptSource)
1602 {
1603 /* traverse the devices' ISR handlers */
1604 List_PVRSRV_DEVICE_NODE_ForEach_va(psSysData->psDeviceNodeList,
1605 &PVRSRVSystemLISR_ForEachVaCb,
1606 &bStatus,
1607 &ui32InterruptSource,
1608 &ui32ClearInterrupts);
1610 SysClearInterrupts(psSysData, ui32ClearInterrupts);
1611 }
1612 /*out:*/
1613 }
1614 return bStatus;
1615 }
1618 static IMG_VOID PVRSRVMISR_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode)
1619 {
1620 if(psDeviceNode->pfnDeviceMISR != IMG_NULL)
1621 {
1622 (*psDeviceNode->pfnDeviceMISR)(psDeviceNode->pvISRData);
1623 }
1624 }
1626 /*!
1627 ******************************************************************************
1629 @Function PVRSRVMISR
1631 @Input pvSysData
1633 @Description
1634 OS-independent Medium-level Interrupt Service Routine
1636 ******************************************************************************/
1637 IMG_VOID IMG_CALLCONV PVRSRVMISR(IMG_VOID *pvSysData)
1638 {
1639 SYS_DATA *psSysData = pvSysData;
1640 /* PVRSRV_DEVICE_NODE *psDeviceNode; */
1642 if(!psSysData)
1643 {
1644 PVR_DPF((PVR_DBG_ERROR, "PVRSRVMISR: Invalid params\n"));
1645 return;
1646 }
1648 /* Traverse the devices' MISR handlers. */
1649 List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList,
1650 &PVRSRVMISR_ForEachCb);
1652 #if defined(SUPPORT_PVRSRV_DEVICE_CLASS)
1653 /* Process the queues. */
1654 if (PVRSRVProcessQueues(IMG_FALSE) == PVRSRV_ERROR_PROCESSING_BLOCKED)
1655 {
1656 PVRSRVProcessQueues(IMG_FALSE);
1657 }
1658 #endif /* defined(SUPPORT_PVRSRV_DEVICE_CLASS) */
1660 /* signal global event object */
1661 if (psSysData->psGlobalEventObject)
1662 {
1663 IMG_HANDLE hOSEventKM = psSysData->psGlobalEventObject->hOSEventKM;
1664 if(hOSEventKM)
1665 {
1666 OSEventObjectSignalKM(hOSEventKM);
1667 }
1668 }
1669 }
1672 /*!
1673 ******************************************************************************
1675 @Function PVRSRVProcessConnect
1677 @Description Inform services that a process has connected.
1679 @Input ui32PID - process ID
1681 @Return PVRSRV_ERROR
1683 ******************************************************************************/
1684 IMG_EXPORT
1685 PVRSRV_ERROR IMG_CALLCONV PVRSRVProcessConnect(IMG_UINT32 ui32PID, IMG_UINT32 ui32Flags)
1686 {
1687 return PVRSRVPerProcessDataConnect(ui32PID, ui32Flags);
1688 }
1691 /*!
1692 ******************************************************************************
1694 @Function PVRSRVProcessDisconnect
1696 @Description Inform services that a process has disconnected.
1698 @Input ui32PID - process ID
1700 @Return IMG_VOID
1702 ******************************************************************************/
1703 IMG_EXPORT
1704 IMG_VOID IMG_CALLCONV PVRSRVProcessDisconnect(IMG_UINT32 ui32PID)
1705 {
1706 PVRSRVPerProcessDataDisconnect(ui32PID);
1707 }
1710 /*!
1711 ******************************************************************************
1713 @Function PVRSRVSaveRestoreLiveSegments
1715 @Input pArena - the arena the segment was originally allocated from.
1716 pbyBuffer - the system memory buffer set to null to get the size needed.
1717 puiBufSize - size of system memory buffer.
1718 bSave - IMG_TRUE if a save is required
1720 @Description
1721 Function to save or restore Resources Live segments
1723 ******************************************************************************/
1724 PVRSRV_ERROR IMG_CALLCONV PVRSRVSaveRestoreLiveSegments(IMG_HANDLE hArena, IMG_PBYTE pbyBuffer,
1725 IMG_SIZE_T *puiBufSize, IMG_BOOL bSave)
1726 {
1727 IMG_SIZE_T uiBytesSaved = 0;
1728 IMG_PVOID pvLocalMemCPUVAddr;
1729 RA_SEGMENT_DETAILS sSegDetails;
1731 if (hArena == IMG_NULL)
1732 {
1733 return (PVRSRV_ERROR_INVALID_PARAMS);
1734 }
1736 sSegDetails.uiSize = 0;
1737 sSegDetails.sCpuPhyAddr.uiAddr = 0;
1738 sSegDetails.hSegment = 0;
1740 /* walk the arena segments and write live one to the buffer */
1741 while (RA_GetNextLiveSegment(hArena, &sSegDetails))
1742 {
1743 if (pbyBuffer == IMG_NULL)
1744 {
1745 /* calc buffer required */
1746 uiBytesSaved += sizeof(sSegDetails.uiSize) + sSegDetails.uiSize;
1747 }
1748 else
1749 {
1750 if ((uiBytesSaved + sizeof(sSegDetails.uiSize) + sSegDetails.uiSize) > *puiBufSize)
1751 {
1752 return (PVRSRV_ERROR_OUT_OF_MEMORY);
1753 }
1755 PVR_DPF((
1756 PVR_DBG_MESSAGE,
1757 "PVRSRVSaveRestoreLiveSegments: Base " CPUPADDR_FMT " size %" SIZE_T_FMT_LEN "x",
1758 sSegDetails.sCpuPhyAddr.uiAddr,
1759 sSegDetails.uiSize));
1761 /* Map the device's local memory area onto the host. */
1762 pvLocalMemCPUVAddr = OSMapPhysToLin(sSegDetails.sCpuPhyAddr,
1763 sSegDetails.uiSize,
1764 PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
1765 IMG_NULL);
1766 if (pvLocalMemCPUVAddr == IMG_NULL)
1767 {
1768 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSaveRestoreLiveSegments: Failed to map local memory to host"));
1769 return (PVRSRV_ERROR_OUT_OF_MEMORY);
1770 }
1772 if (bSave)
1773 {
1774 /* write segment size then segment data */
1775 OSMemCopy(pbyBuffer, &sSegDetails.uiSize, sizeof(sSegDetails.uiSize));
1776 pbyBuffer += sizeof(sSegDetails.uiSize);
1778 OSMemCopy(pbyBuffer, pvLocalMemCPUVAddr, sSegDetails.uiSize);
1779 pbyBuffer += sSegDetails.uiSize;
1780 }
1781 else
1782 {
1783 IMG_UINT32 uiSize;
1784 /* reag segment size and validate */
1785 OSMemCopy(&uiSize, pbyBuffer, sizeof(sSegDetails.uiSize));
1787 if (uiSize != sSegDetails.uiSize)
1788 {
1789 PVR_DPF((PVR_DBG_ERROR, "PVRSRVSaveRestoreLiveSegments: Segment size error"));
1790 }
1791 else
1792 {
1793 pbyBuffer += sizeof(sSegDetails.uiSize);
1795 OSMemCopy(pvLocalMemCPUVAddr, pbyBuffer, sSegDetails.uiSize);
1796 pbyBuffer += sSegDetails.uiSize;
1797 }
1798 }
1801 uiBytesSaved += sizeof(sSegDetails.uiSize) + sSegDetails.uiSize;
1803 OSUnMapPhysToLin(pvLocalMemCPUVAddr,
1804 sSegDetails.uiSize,
1805 PVRSRV_HAP_KERNEL_ONLY|PVRSRV_HAP_UNCACHED,
1806 IMG_NULL);
1807 }
1808 }
1810 if (pbyBuffer == IMG_NULL)
1811 {
1812 *puiBufSize = uiBytesSaved;
1813 }
1815 return (PVRSRV_OK);
1816 }
1819 /*!
1820 ******************************************************************************
1822 @Function PVRSRVGetErrorStringKM
1824 @Description Returns a text string relating to the PVRSRV_ERROR enum.
1826 @Note case statement used rather than an indexed arrary to ensure text is
1827 synchronised with the correct enum
1829 @Input eError : PVRSRV_ERROR enum
1831 @Return const IMG_CHAR * : Text string
1833 @Note Must be kept in sync with servicesext.h
1835 ******************************************************************************/
1837 IMG_EXPORT
1838 const IMG_CHAR *PVRSRVGetErrorStringKM(PVRSRV_ERROR eError)
1839 {
1840 /* PRQA S 5087 1 */ /* include file required here */
1841 #include "pvrsrv_errors.h"
1842 }
1844 static IMG_VOID PVRSRVCommandCompleteCallbacks_ForEachCb(PVRSRV_DEVICE_NODE *psDeviceNode)
1845 {
1846 if(psDeviceNode->pfnDeviceCommandComplete != IMG_NULL)
1847 {
1848 /* Call the device's callback function. */
1849 (*psDeviceNode->pfnDeviceCommandComplete)(psDeviceNode);
1850 }
1851 }
1853 /*!
1854 ******************************************************************************
1856 @Function PVRSRVScheduleDeviceCallbacks
1858 @Description Schedule all device callbacks
1860 @Return IMG_VOID
1862 ******************************************************************************/
1863 IMG_VOID PVRSRVScheduleDeviceCallbacks(IMG_VOID)
1864 {
1865 SYS_DATA *psSysData;
1866 /* PVRSRV_DEVICE_NODE *psDeviceNode;*/
1868 SysAcquireData(&psSysData);
1870 /*for all the device, invoke the callback function*/
1871 List_PVRSRV_DEVICE_NODE_ForEach(psSysData->psDeviceNodeList,
1872 &PVRSRVCommandCompleteCallbacks_ForEachCb);
1873 }
1875 /*!
1876 ******************************************************************************
1878 @Function PVRSRVScheduleDevices
1880 @Description Schedules all Services-Managed Devices to check their pending
1881 command queues. The intention is that ScheduleDevices be called by the
1882 3rd party BC driver after it has finished writing new data to its output
1883 texture.
1885 @Return IMG_VOID
1887 ******************************************************************************/
1888 IMG_EXPORT
1889 IMG_VOID PVRSRVScheduleDevicesKM(IMG_VOID)
1890 {
1891 PVRSRVScheduleDeviceCallbacks();
1892 }
1894 /*****************************************************************************
1895 End of file (pvrsrv.c)
1896 *****************************************************************************/