diff options
Diffstat (limited to 'drivers/gpu/pvr/deviceclass.c')
-rw-r--r-- | drivers/gpu/pvr/deviceclass.c | 1522 |
1 files changed, 1522 insertions, 0 deletions
diff --git a/drivers/gpu/pvr/deviceclass.c b/drivers/gpu/pvr/deviceclass.c new file mode 100644 index 00000000000..c5374e52382 --- /dev/null +++ b/drivers/gpu/pvr/deviceclass.c @@ -0,0 +1,1522 @@ +/********************************************************************** + * + * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful but, except + * as otherwise stated in writing, without any warranty; without even the + * implied warranty of merchantability or fitness for a particular purpose. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Imagination Technologies Ltd. <gpl-support@imgtec.com> + * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK + * + ******************************************************************************/ +#include <linux/module.h> + +#include "services_headers.h" +#include "buffer_manager.h" +#include "kernelbuffer.h" +#include "pvr_bridge_km.h" + +struct PVRSRV_DC_SRV2DISP_KMJTABLE; + +struct PVRSRV_DC_BUFFER { + struct PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; +}; + +struct PVRSRV_DC_SWAPCHAIN { + void *hExtSwapChain; + struct PVRSRV_QUEUE_INFO *psQueue; + struct PVRSRV_DC_BUFFER asBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS]; + u32 ui32BufferCount; + struct PVRSRV_DC_BUFFER *psLastFlipBuffer; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + void *hResItem; +}; + +struct PVRSRV_DISPLAYCLASS_INFO { + u32 ui32RefCount; + u32 ui32DeviceID; + void *hExtDevice; + struct PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable; + void *hDevMemContext; + struct PVRSRV_DC_BUFFER sSystemBuffer; +}; + +struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO { + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct RESMAN_ITEM *hResItem; +}; + +struct PVRSRV_BC_SRV2BUFFER_KMJTABLE; + +struct PVRSRV_BC_BUFFER { + struct PVRSRV_DEVICECLASS_BUFFER sDeviceClassBuffer; + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; +}; + +struct PVRSRV_BUFFERCLASS_INFO { + u32 ui32RefCount; + u32 ui32DeviceID; + void *hExtDevice; + struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable; + void *hDevMemContext; + + u32 ui32BufferCount; + struct PVRSRV_BC_BUFFER *psBuffer; + +}; + +struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO { + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + void *hResItem; +}; + +static struct PVRSRV_DISPLAYCLASS_INFO *DCDeviceHandleToDCInfo(void *hDeviceKM) +{ + struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; + + psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *) + hDeviceKM; + + return psDCPerContextInfo->psDCInfo; +} + +static struct PVRSRV_BUFFERCLASS_INFO *BCDeviceHandleToBCInfo(void *hDeviceKM) +{ + struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; + + psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *) + hDeviceKM; + + return psBCPerContextInfo->psBCInfo; +} + +enum PVRSRV_ERROR PVRSRVEnumerateDCKM(enum PVRSRV_DEVICE_CLASS DeviceClass, + u32 *pui32DevCount, u32 *pui32DevID) +{ + struct PVRSRV_DEVICE_NODE *psDeviceNode; + unsigned ui32DevCount = 0; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumerateDCKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + if ((psDeviceNode->sDevId.eDeviceClass == DeviceClass) && + (psDeviceNode->sDevId.eDeviceType == + PVRSRV_DEVICE_TYPE_EXT)) { + ui32DevCount++; + if (pui32DevID) { + *pui32DevID++ = + psDeviceNode->sDevId.ui32DeviceIndex; + } + } + psDeviceNode = psDeviceNode->psNext; + } + + if (pui32DevCount) { + *pui32DevCount = ui32DevCount; + } else if (pui32DevID == NULL) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumerateDCKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR PVRSRVRegisterDCDeviceKM( + struct PVRSRV_DC_SRV2DISP_KMJTABLE *psFuncTable, + u32 *pui32DeviceID) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo = NULL; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterDCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*psDCInfo), + (void **) &psDCInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterDCDeviceKM: Failed psDCInfo alloc"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psDCInfo, 0, sizeof(*psDCInfo)); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE), + (void **)&psDCInfo->psFuncTable, + NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterDCDeviceKM: Failed psFuncTable alloc"); + goto ErrorExit; + } + OSMemSet(psDCInfo->psFuncTable, 0, + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE)); + + *psDCInfo->psFuncTable = *psFuncTable; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), + (void **) &psDeviceNode, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterDCDeviceKM: Failed psDeviceNode alloc"); + goto ErrorExit; + } + OSMemSet(psDeviceNode, 0, sizeof(struct PVRSRV_DEVICE_NODE)); + + psDeviceNode->pvDevice = (void *) psDCInfo; + psDeviceNode->ui32pvDeviceSize = sizeof(*psDCInfo); + psDeviceNode->ui32RefCount = 1; + psDeviceNode->sDevId.eDeviceType = PVRSRV_DEVICE_TYPE_EXT; + psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_DISPLAY; + psDeviceNode->psSysData = psSysData; + + AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex); + psDCInfo->ui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; + if (pui32DeviceID) + *pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; + + SysRegisterExternalDevice(psDeviceNode); + + psDeviceNode->psNext = psSysData->psDeviceNodeList; + psSysData->psDeviceNodeList = psDeviceNode; + + return PVRSRV_OK; + +ErrorExit: + + if (psDCInfo->psFuncTable) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE), + psDCInfo->psFuncTable, NULL); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DISPLAYCLASS_INFO), + psDCInfo, NULL); + + return PVRSRV_ERROR_OUT_OF_MEMORY; +} + +static enum PVRSRV_ERROR PVRSRVRemoveDCDeviceKM(u32 ui32DevIndex) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE **ppsDeviceNode, *psDeviceNode; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveDCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + ppsDeviceNode = &psSysData->psDeviceNodeList; + while (*ppsDeviceNode) { + switch ((*ppsDeviceNode)->sDevId.eDeviceClass) { + case PVRSRV_DEVICE_CLASS_DISPLAY: + { + if ((*ppsDeviceNode)->sDevId.ui32DeviceIndex == + ui32DevIndex) + goto FoundDevice; + break; + } + default: + { + break; + } + } + ppsDeviceNode = &((*ppsDeviceNode)->psNext); + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveDCDeviceKM: requested device %d not present", + ui32DevIndex); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + psDeviceNode = *ppsDeviceNode; + + psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *)psDeviceNode->pvDevice; + + if (psDCInfo->ui32RefCount == 0) { + *ppsDeviceNode = psDeviceNode->psNext; + SysRemoveExternalDevice(psDeviceNode); + PVR_ASSERT(psDCInfo->ui32RefCount == 0); + FreeDeviceID(psSysData, ui32DevIndex); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SRV2DISP_KMJTABLE), + psDCInfo->psFuncTable, NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DISPLAYCLASS_INFO), psDCInfo, + NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), psDeviceNode, + NULL); + } else { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRemoveDCDeviceKM: " + "failed as %d Services DC API " + "connections are still open", + psDCInfo->ui32RefCount); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR PVRSRVRegisterBCDeviceKM( + struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *psFuncTable, + u32 *pui32DeviceID) +{ + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo = NULL; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterBCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*psBCInfo), + (void **) &psBCInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterBCDeviceKM: Failed psBCInfo alloc"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psBCInfo, 0, sizeof(*psBCInfo)); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE), + (void **) &psBCInfo->psFuncTable, + NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterBCDeviceKM: Failed psFuncTable alloc"); + goto ErrorExit; + } + OSMemSet(psBCInfo->psFuncTable, 0, + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE)); + + *psBCInfo->psFuncTable = *psFuncTable; + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), + (void **) &psDeviceNode, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRegisterBCDeviceKM: Failed psDeviceNode alloc"); + goto ErrorExit; + } + OSMemSet(psDeviceNode, 0, sizeof(struct PVRSRV_DEVICE_NODE)); + + psDeviceNode->pvDevice = (void *) psBCInfo; + psDeviceNode->ui32pvDeviceSize = sizeof(*psBCInfo); + psDeviceNode->ui32RefCount = 1; + psDeviceNode->sDevId.eDeviceType = PVRSRV_DEVICE_TYPE_EXT; + psDeviceNode->sDevId.eDeviceClass = PVRSRV_DEVICE_CLASS_BUFFER; + psDeviceNode->psSysData = psSysData; + + AllocateDeviceID(psSysData, &psDeviceNode->sDevId.ui32DeviceIndex); + psBCInfo->ui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; + if (pui32DeviceID) + *pui32DeviceID = psDeviceNode->sDevId.ui32DeviceIndex; + + psDeviceNode->psNext = psSysData->psDeviceNodeList; + psSysData->psDeviceNodeList = psDeviceNode; + + return PVRSRV_OK; + +ErrorExit: + + if (psBCInfo->psFuncTable) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE *), + psBCInfo->psFuncTable, NULL); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BUFFERCLASS_INFO), psBCInfo, NULL); + + return PVRSRV_ERROR_OUT_OF_MEMORY; +} + +static enum PVRSRV_ERROR PVRSRVRemoveBCDeviceKM(u32 ui32DevIndex) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE **ppsDevNode, *psDevNode; + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveBCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + ppsDevNode = &psSysData->psDeviceNodeList; + while (*ppsDevNode) { + switch ((*ppsDevNode)->sDevId.eDeviceClass) { + case PVRSRV_DEVICE_CLASS_BUFFER: + { + if ((*ppsDevNode)->sDevId.ui32DeviceIndex == + ui32DevIndex) + goto FoundDevice; + break; + } + default: + { + break; + } + } + ppsDevNode = &(*ppsDevNode)->psNext; + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVRemoveBCDeviceKM: requested device %d not present", + ui32DevIndex); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + psDevNode = *(ppsDevNode); + + psBCInfo = (struct PVRSRV_BUFFERCLASS_INFO *)psDevNode->pvDevice; + + if (psBCInfo->ui32RefCount == 0) { + *ppsDevNode = psDevNode->psNext; + FreeDeviceID(psSysData, ui32DevIndex); + psBCInfo = + (struct PVRSRV_BUFFERCLASS_INFO *)psDevNode->pvDevice; + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_SRV2BUFFER_KMJTABLE), + psBCInfo->psFuncTable, NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BUFFERCLASS_INFO), psBCInfo, + NULL); + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DEVICE_NODE), psDevNode, NULL); + } else { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRemoveBCDeviceKM: " + "failed as %d Services BC API " + "connections are still open", + psBCInfo->ui32RefCount); + return PVRSRV_ERROR_GENERIC; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVCloseDCDeviceKM(void *hDeviceKM, + IMG_BOOL bResManCallback) +{ + struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; + + PVR_UNREFERENCED_PARAMETER(bResManCallback); + + psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *) + hDeviceKM; + + ResManFreeResByPtr(psDCPerContextInfo->hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR CloseDCDeviceCallBack(void *pvParam, u32 ui32Param) +{ + struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + psDCPerContextInfo = (struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *) + pvParam; + psDCInfo = psDCPerContextInfo->psDCInfo; + + psDCInfo->ui32RefCount--; + if (psDCInfo->ui32RefCount == 0) { + struct PVRSRV_DC_SRV2DISP_KMJTABLE *jtbl; + + jtbl = psDCInfo->psFuncTable; + + jtbl->pfnCloseDCDevice(psDCInfo->hExtDevice); + + PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer.sDeviceClassBuffer. + psKernelSyncInfo); + + psDCInfo->hDevMemContext = NULL; + psDCInfo->hExtDevice = NULL; + + module_put(jtbl->owner); + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO), + psDCPerContextInfo, NULL); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVOpenDCDeviceKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + u32 ui32DeviceID, void *hDevCookie, + void **phDeviceKM) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DISPLAYCLASS_PERCONTEXT_INFO *psDCPerContextInfo; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + + if (!phDeviceKM || !hDevCookie) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenDCDeviceKM: Invalid params"); + return PVRSRV_ERROR_GENERIC; + } + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenDCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + if ((psDeviceNode->sDevId.eDeviceClass == + PVRSRV_DEVICE_CLASS_DISPLAY) && + (psDeviceNode->sDevId.ui32DeviceIndex == ui32DeviceID)) { + + psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *) + psDeviceNode->pvDevice; + goto FoundDevice; + } + psDeviceNode = psDeviceNode->psNext; + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenDCDeviceKM: no devnode matching index %d", + ui32DeviceID); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(*psDCPerContextInfo), + (void **)&psDCPerContextInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenDCDeviceKM: " + "Failed psDCPerContextInfo alloc"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psDCPerContextInfo, 0, sizeof(*psDCPerContextInfo)); + + if (psDCInfo->ui32RefCount++ == 0) { + enum PVRSRV_ERROR eError; + struct PVRSRV_DC_SRV2DISP_KMJTABLE *jtbl; + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie; + + jtbl = psDCInfo->psFuncTable; + if (!try_module_get(jtbl->owner)) { + PVR_DPF(PVR_DBG_ERROR, "%s: can't get DC module"); + return PVRSRV_ERROR_INVALID_DEVICE; + } + + psDCInfo->hDevMemContext = + (void *) psDeviceNode->sDevMemoryInfo.pBMKernelContext; + + eError = PVRSRVAllocSyncInfoKM(NULL, + (void *)psDeviceNode-> + sDevMemoryInfo.pBMKernelContext, + &psDCInfo->sSystemBuffer. + sDeviceClassBuffer. + psKernelSyncInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenDCDeviceKM: Failed sync info alloc"); + psDCInfo->ui32RefCount--; + module_put(jtbl->owner); + return eError; + } + + eError = jtbl->pfnOpenDCDevice(ui32DeviceID, + &psDCInfo->hExtDevice, + (struct PVRSRV_SYNC_DATA *)psDCInfo->sSystemBuffer. + sDeviceClassBuffer.psKernelSyncInfo-> + psSyncDataMemInfoKM->pvLinAddrKM); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenDCDeviceKM: " + "Failed to open external DC device"); + psDCInfo->ui32RefCount--; + module_put(jtbl->owner); + PVRSRVFreeSyncInfoKM(psDCInfo->sSystemBuffer. + sDeviceClassBuffer.psKernelSyncInfo); + return eError; + } + } + + psDCPerContextInfo->psDCInfo = psDCInfo; + psDCPerContextInfo->hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_DISPLAYCLASS_DEVICE, + psDCPerContextInfo, 0, CloseDCDeviceCallBack); + + *phDeviceKM = (void *) psDCPerContextInfo; + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVEnumDCFormatsKM(void *hDeviceKM, + u32 *pui32Count, + struct DISPLAY_FORMAT *psFormat) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + + if (!hDeviceKM || !pui32Count || !psFormat) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumDCFormatsKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + return psDCInfo->psFuncTable->pfnEnumDCFormats(psDCInfo->hExtDevice, + pui32Count, psFormat); +} + +enum PVRSRV_ERROR PVRSRVEnumDCDimsKM(void *hDeviceKM, + struct DISPLAY_FORMAT *psFormat, + u32 *pui32Count, struct DISPLAY_DIMS *psDim) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + + if (!hDeviceKM || !pui32Count || !psFormat) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVEnumDCDimsKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + return psDCInfo->psFuncTable->pfnEnumDCDims(psDCInfo->hExtDevice, + psFormat, pui32Count, psDim); +} + +enum PVRSRV_ERROR PVRSRVGetDCSystemBufferKM(void *hDeviceKM, void **phBuffer) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + void *hExtBuffer; + + if (!hDeviceKM || !phBuffer) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetDCSystemBufferKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + eError = + psDCInfo->psFuncTable->pfnGetDCSystemBuffer(psDCInfo->hExtDevice, + &hExtBuffer); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetDCSystemBufferKM: " + "Failed to get valid buffer handle from external driver"); + return eError; + } + + psDCInfo->sSystemBuffer.sDeviceClassBuffer.pfnGetBufferAddr = + psDCInfo->psFuncTable->pfnGetBufferAddr; + psDCInfo->sSystemBuffer.sDeviceClassBuffer.hDevMemContext = + psDCInfo->hDevMemContext; + psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtDevice = + psDCInfo->hExtDevice; + psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer = hExtBuffer; + + psDCInfo->sSystemBuffer.psDCInfo = psDCInfo; + + *phBuffer = (void *) &(psDCInfo->sSystemBuffer); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVGetDCInfoKM(void *hDeviceKM, + struct DISPLAY_INFO *psDisplayInfo) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + enum PVRSRV_ERROR eError; + + if (!hDeviceKM || !psDisplayInfo) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetDCInfoKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + eError = psDCInfo->psFuncTable->pfnGetDCInfo(psDCInfo->hExtDevice, + psDisplayInfo); + if (eError != PVRSRV_OK) + return eError; + + if (psDisplayInfo->ui32MaxSwapChainBuffers > + PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS) { + psDisplayInfo->ui32MaxSwapChainBuffers = + PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVDestroyDCSwapChainKM(void *hSwapChain) +{ + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVDestroyDCSwapChainKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psSwapChain = hSwapChain; + + ResManFreeResByPtr(psSwapChain->hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR DestroyDCSwapChainCallBack(void *pvParam, + u32 ui32Param) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain = pvParam; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo = psSwapChain->psDCInfo; + u32 i; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + PVRSRVDestroyCommandQueueKM(psSwapChain->psQueue); + + eError = + psDCInfo->psFuncTable->pfnDestroyDCSwapChain(psDCInfo->hExtDevice, + psSwapChain-> + hExtSwapChain); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "DestroyDCSwapChainCallBack: " + "Failed to destroy DC swap chain"); + return eError; + } + + for (i = 0; i < psSwapChain->ui32BufferCount; i++) + if (psSwapChain->asBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo) + PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, sizeof(struct PVRSRV_DC_SWAPCHAIN), + psSwapChain, NULL); + + return eError; +} + +enum PVRSRV_ERROR PVRSRVCreateDCSwapChainKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + void *hDeviceKM, u32 ui32Flags, + struct DISPLAY_SURF_ATTRIBUTES *psDstSurfAttrib, + struct DISPLAY_SURF_ATTRIBUTES *psSrcSurfAttrib, + u32 ui32BufferCount, u32 ui32OEMFlags, + void **phSwapChain, u32 *pui32SwapChainID) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain = NULL; + struct PVRSRV_SYNC_DATA *apsSyncData[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS]; + struct PVRSRV_QUEUE_INFO *psQueue = NULL; + enum PVRSRV_ERROR eError; + u32 i; + + if (!hDeviceKM || !psDstSurfAttrib || !psSrcSurfAttrib || + !phSwapChain || !pui32SwapChainID) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + if (ui32BufferCount > PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Too many buffers"); + return PVRSRV_ERROR_TOOMANYBUFFERS; + } + + if (ui32BufferCount < 2) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Too few buffers"); + return PVRSRV_ERROR_TOO_FEW_BUFFERS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SWAPCHAIN), + (void **) &psSwapChain, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Failed psSwapChain alloc"); + eError = PVRSRV_ERROR_OUT_OF_MEMORY; + goto ErrorExit; + } + OSMemSet(psSwapChain, 0, sizeof(struct PVRSRV_DC_SWAPCHAIN)); + + eError = PVRSRVCreateCommandQueueKM(1024, &psQueue); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVCreateDCSwapChainKM: Failed to create CmdQueue"); + goto ErrorExit; + } + + psSwapChain->psQueue = psQueue; + + for (i = 0; i < ui32BufferCount; i++) { + eError = PVRSRVAllocSyncInfoKM(NULL, + psDCInfo->hDevMemContext, + &psSwapChain->asBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateDCSwapChainKM: " + "Failed to alloc syninfo for psSwapChain"); + goto ErrorExit; + } + + psSwapChain->asBuffer[i].sDeviceClassBuffer.pfnGetBufferAddr = + psDCInfo->psFuncTable->pfnGetBufferAddr; + psSwapChain->asBuffer[i].sDeviceClassBuffer.hDevMemContext = + psDCInfo->hDevMemContext; + psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtDevice = + psDCInfo->hExtDevice; + + psSwapChain->asBuffer[i].psDCInfo = psDCInfo; + psSwapChain->asBuffer[i].psSwapChain = psSwapChain; + + apsSyncData[i] = + (struct PVRSRV_SYNC_DATA *)psSwapChain->asBuffer[i]. + sDeviceClassBuffer.psKernelSyncInfo-> + psSyncDataMemInfoKM->pvLinAddrKM; + } + + psSwapChain->ui32BufferCount = ui32BufferCount; + psSwapChain->psDCInfo = psDCInfo; + + eError = + psDCInfo->psFuncTable->pfnCreateDCSwapChain(psDCInfo->hExtDevice, + ui32Flags, + psDstSurfAttrib, + psSrcSurfAttrib, + ui32BufferCount, + apsSyncData, + ui32OEMFlags, + &psSwapChain->hExtSwapChain, + pui32SwapChainID); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVCreateDCSwapChainKM: " + "Failed to create 3rd party SwapChain"); + goto ErrorExit; + } + + *phSwapChain = (void *) psSwapChain; + + psSwapChain->hResItem = ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_DISPLAYCLASS_SWAPCHAIN, + psSwapChain, 0, + DestroyDCSwapChainCallBack); + + return eError; + +ErrorExit: + + for (i = 0; i < ui32BufferCount; i++) { + if (psSwapChain->asBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo) { + PVRSRVFreeSyncInfoKM(psSwapChain->asBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + } + } + + if (psQueue) + PVRSRVDestroyCommandQueueKM(psQueue); + + if (psSwapChain) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_DC_SWAPCHAIN), psSwapChain, + NULL); + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVSetDCDstRectKM(void *hDeviceKM, void *hSwapChain, + struct IMG_RECT *psRect) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCDstRectKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + return psDCInfo->psFuncTable->pfnSetDCDstRect(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, psRect); +} + +enum PVRSRV_ERROR PVRSRVSetDCSrcRectKM(void *hDeviceKM, void *hSwapChain, + struct IMG_RECT *psRect) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCSrcRectKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + return psDCInfo->psFuncTable->pfnSetDCSrcRect(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, psRect); +} + +enum PVRSRV_ERROR PVRSRVSetDCDstColourKeyKM(void *hDeviceKM, void *hSwapChain, + u32 ui32CKColour) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCDstColourKeyKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + return psDCInfo->psFuncTable->pfnSetDCDstColourKey(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, ui32CKColour); +} + +enum PVRSRV_ERROR PVRSRVSetDCSrcColourKeyKM(void *hDeviceKM, void *hSwapChain, + u32 ui32CKColour) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCSrcColourKeyKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + return psDCInfo->psFuncTable->pfnSetDCSrcColourKey(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, ui32CKColour); +} + +enum PVRSRV_ERROR PVRSRVGetDCBuffersKM(void *hDeviceKM, void *hSwapChain, + u32 *pui32BufferCount, void **phBuffer) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + void *ahExtBuffer[PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS]; + enum PVRSRV_ERROR eError; + u32 i; + + if (!hDeviceKM || !hSwapChain || !phBuffer) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetDCBuffersKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + eError = psDCInfo->psFuncTable->pfnGetDCBuffers(psDCInfo->hExtDevice, + psSwapChain->hExtSwapChain, + pui32BufferCount, ahExtBuffer); + + PVR_ASSERT(*pui32BufferCount <= PVRSRV_MAX_DC_SWAPCHAIN_BUFFERS); + + for (i = 0; i < *pui32BufferCount; i++) { + psSwapChain->asBuffer[i].sDeviceClassBuffer.hExtBuffer = + ahExtBuffer[i]; + phBuffer[i] = (void *)&psSwapChain->asBuffer[i]; + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVSwapToDCBufferKM(void *hDeviceKM, void *hBuffer, + u32 ui32SwapInterval, void *hPrivateTag, + u32 ui32ClipRectCount, + struct IMG_RECT *psClipRect) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_BUFFER *psBuffer; + struct PVRSRV_QUEUE_INFO *psQueue; + struct DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; + u32 i; + u32 ui32NumSrcSyncs = 1; + struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[2]; + struct PVRSRV_COMMAND *psCommand; + + if (!hDeviceKM || !hBuffer || !psClipRect) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCBufferKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psBuffer = (struct PVRSRV_DC_BUFFER *)hBuffer; + + psQueue = psBuffer->psSwapChain->psQueue; + + apsSrcSync[0] = psBuffer->sDeviceClassBuffer.psKernelSyncInfo; + if (psBuffer->psSwapChain->psLastFlipBuffer && + psBuffer != psBuffer->psSwapChain->psLastFlipBuffer) { + apsSrcSync[1] = + psBuffer->psSwapChain->psLastFlipBuffer->sDeviceClassBuffer. + psKernelSyncInfo; + ui32NumSrcSyncs++; + } + + eError = PVRSRVInsertCommandKM(psQueue, &psCommand, + psDCInfo->ui32DeviceID, DC_FLIP_COMMAND, + 0, NULL, ui32NumSrcSyncs, apsSrcSync, + sizeof(struct DISPLAYCLASS_FLIP_COMMAND) + + (sizeof(struct IMG_RECT) * + ui32ClipRectCount)); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCBufferKM: Failed to get space in queue"); + goto Exit; + } + + psFlipCmd = (struct DISPLAYCLASS_FLIP_COMMAND *)psCommand->pvData; + psFlipCmd->hExtDevice = psDCInfo->hExtDevice; + psFlipCmd->hExtSwapChain = psBuffer->psSwapChain->hExtSwapChain; + psFlipCmd->hExtBuffer = psBuffer->sDeviceClassBuffer.hExtBuffer; + psFlipCmd->hPrivateTag = hPrivateTag; + psFlipCmd->ui32ClipRectCount = ui32ClipRectCount; + psFlipCmd->psClipRect = + (struct IMG_RECT *)((u8 *) psFlipCmd + + sizeof(struct DISPLAYCLASS_FLIP_COMMAND)); + + for (i = 0; i < ui32ClipRectCount; i++) + psFlipCmd->psClipRect[i] = psClipRect[i]; + + psFlipCmd->ui32SwapInterval = ui32SwapInterval; + + eError = PVRSRVSubmitCommandKM(psQueue, psCommand); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCBufferKM: Failed to submit command"); + goto Exit; + } + + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if (PVRSRVProcessQueues(IMG_FALSE) != + PVRSRV_ERROR_PROCESSING_BLOCKED) { + goto ProcessedQueues; + } + OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT); + } + END_LOOP_UNTIL_TIMEOUT(); + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCBufferKM: Failed to process queues"); + + eError = PVRSRV_ERROR_GENERIC; + goto Exit; + +ProcessedQueues: + + psBuffer->psSwapChain->psLastFlipBuffer = psBuffer; + +Exit: + return eError; +} + +enum PVRSRV_ERROR PVRSRVSwapToDCSystemKM(void *hDeviceKM, void *hSwapChain) +{ + enum PVRSRV_ERROR eError; + struct PVRSRV_QUEUE_INFO *psQueue; + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DC_SWAPCHAIN *psSwapChain; + struct DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; + u32 ui32NumSrcSyncs = 1; + struct PVRSRV_KERNEL_SYNC_INFO *apsSrcSync[2]; + struct PVRSRV_COMMAND *psCommand; + + if (!hDeviceKM || !hSwapChain) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCSystemKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psDCInfo = DCDeviceHandleToDCInfo(hDeviceKM); + psSwapChain = (struct PVRSRV_DC_SWAPCHAIN *)hSwapChain; + + psQueue = psSwapChain->psQueue; + + apsSrcSync[0] = + psDCInfo->sSystemBuffer.sDeviceClassBuffer.psKernelSyncInfo; + if (psSwapChain->psLastFlipBuffer) { + if (apsSrcSync[0] != + psSwapChain->psLastFlipBuffer->sDeviceClassBuffer. + psKernelSyncInfo) { + apsSrcSync[1] = + psSwapChain->psLastFlipBuffer->sDeviceClassBuffer. + psKernelSyncInfo; + ui32NumSrcSyncs++; + } + } + + eError = PVRSRVInsertCommandKM(psQueue, &psCommand, + psDCInfo->ui32DeviceID, DC_FLIP_COMMAND, + 0, NULL, ui32NumSrcSyncs, apsSrcSync, + sizeof(struct DISPLAYCLASS_FLIP_COMMAND)); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCSystemKM: Failed to get space in queue"); + goto Exit; + } + + psFlipCmd = (struct DISPLAYCLASS_FLIP_COMMAND *)psCommand->pvData; + psFlipCmd->hExtDevice = psDCInfo->hExtDevice; + psFlipCmd->hExtSwapChain = psSwapChain->hExtSwapChain; + psFlipCmd->hExtBuffer = + psDCInfo->sSystemBuffer.sDeviceClassBuffer.hExtBuffer; + psFlipCmd->hPrivateTag = NULL; + psFlipCmd->ui32ClipRectCount = 0; + psFlipCmd->ui32SwapInterval = 1; + + eError = PVRSRVSubmitCommandKM(psQueue, psCommand); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCSystemKM: Failed to submit command"); + goto Exit; + } + + LOOP_UNTIL_TIMEOUT(MAX_HW_TIME_US) { + if (PVRSRVProcessQueues(IMG_FALSE) != + PVRSRV_ERROR_PROCESSING_BLOCKED) { + goto ProcessedQueues; + } + OSWaitus(MAX_HW_TIME_US / WAIT_TRY_COUNT); + } + END_LOOP_UNTIL_TIMEOUT(); + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSwapToDCSystemKM: Failed to process queues"); + eError = PVRSRV_ERROR_GENERIC; + goto Exit; + +ProcessedQueues: + + psSwapChain->psLastFlipBuffer = &psDCInfo->sSystemBuffer; + + eError = PVRSRV_OK; + +Exit: + return eError; +} + +static enum PVRSRV_ERROR PVRSRVRegisterSystemISRHandler( + IMG_BOOL (*pfnISRHandler)(void *), + void *pvISRHandlerData, + u32 ui32ISRSourceMask, + u32 ui32DeviceID) +{ + struct SYS_DATA *psSysData; + struct PVRSRV_DEVICE_NODE *psDevNode; + + PVR_UNREFERENCED_PARAMETER(ui32ISRSourceMask); + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterSystemISRHandler: " + "Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + psDevNode = psSysData->psDeviceNodeList; + while (psDevNode) { + if (psDevNode->sDevId.ui32DeviceIndex == ui32DeviceID) + break; + psDevNode = psDevNode->psNext; + } + + if (psDevNode == NULL) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVRegisterSystemISRHandler: " + "Failed to get psDevNode"); + PVR_DBG_BREAK; + return PVRSRV_ERROR_GENERIC; + } + + psDevNode->pvISRData = (void *) pvISRHandlerData; + + psDevNode->pfnDeviceISR = pfnISRHandler; + + return PVRSRV_OK; +} + +void PVRSRVSetDCState(u32 ui32State) +{ + struct PVRSRV_DISPLAYCLASS_INFO *psDCInfo; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVSetDCState: Failed to get SysData"); + return; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode != NULL) { + if (psDeviceNode->sDevId.eDeviceClass == + PVRSRV_DEVICE_CLASS_DISPLAY) { + psDCInfo = (struct PVRSRV_DISPLAYCLASS_INFO *) + psDeviceNode->pvDevice; + if (psDCInfo->psFuncTable->pfnSetDCState && + psDCInfo->hExtDevice) + psDCInfo->psFuncTable->pfnSetDCState( + psDCInfo->hExtDevice, + ui32State); + } + psDeviceNode = psDeviceNode->psNext; + } +} + +IMG_BOOL PVRGetDisplayClassJTable(struct PVRSRV_DC_DISP2SRV_KMJTABLE *psJTable) +{ + psJTable->ui32TableSize = sizeof(struct PVRSRV_DC_DISP2SRV_KMJTABLE); + psJTable->pfnPVRSRVRegisterDCDevice = PVRSRVRegisterDCDeviceKM; + psJTable->pfnPVRSRVRemoveDCDevice = PVRSRVRemoveDCDeviceKM; + psJTable->pfnPVRSRVOEMFunction = SysOEMFunction; + psJTable->pfnPVRSRVRegisterCmdProcList = PVRSRVRegisterCmdProcListKM; + psJTable->pfnPVRSRVRemoveCmdProcList = PVRSRVRemoveCmdProcListKM; + psJTable->pfnPVRSRVCmdComplete = PVRSRVCommandCompleteKM; + psJTable->pfnPVRSRVRegisterSystemISRHandler = + PVRSRVRegisterSystemISRHandler; + psJTable->pfnPVRSRVRegisterPowerDevice = PVRSRVRegisterPowerDevice; + + return IMG_TRUE; +} +EXPORT_SYMBOL(PVRGetDisplayClassJTable); + +enum PVRSRV_ERROR PVRSRVCloseBCDeviceKM(void *hDeviceKM, + IMG_BOOL bResManCallback) +{ + struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; + + PVR_UNREFERENCED_PARAMETER(bResManCallback); + + psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *) + hDeviceKM; + + ResManFreeResByPtr(psBCPerContextInfo->hResItem); + + return PVRSRV_OK; +} + +static enum PVRSRV_ERROR CloseBCDeviceCallBack(void *pvParam, u32 ui32Param) +{ + struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + + PVR_UNREFERENCED_PARAMETER(ui32Param); + + psBCPerContextInfo = (struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *) + pvParam; + psBCInfo = psBCPerContextInfo->psBCInfo; + + psBCInfo->ui32RefCount--; + if (psBCInfo->ui32RefCount == 0) { + u32 i; + + psBCInfo->psFuncTable->pfnCloseBCDevice(psBCInfo->hExtDevice); + + for (i = 0; i < psBCInfo->ui32BufferCount; i++) + if (psBCInfo->psBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo) + PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + + if (psBCInfo->psBuffer) + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_BUFFER), + psBCInfo->psBuffer, NULL); + } + + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO), + psBCPerContextInfo, NULL); + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVOpenBCDeviceKM( + struct PVRSRV_PER_PROCESS_DATA *psPerProc, + u32 ui32DeviceID, void *hDevCookie, + void **phDeviceKM) +{ + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + struct PVRSRV_BUFFERCLASS_PERCONTEXT_INFO *psBCPerContextInfo; + struct PVRSRV_DEVICE_NODE *psDeviceNode; + struct SYS_DATA *psSysData; + u32 i; + enum PVRSRV_ERROR eError; + + if (!phDeviceKM || !hDevCookie) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenBCDeviceKM: Invalid params"); + return PVRSRV_ERROR_GENERIC; + } + + if (SysAcquireData(&psSysData) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenBCDeviceKM: Failed to get SysData"); + return PVRSRV_ERROR_GENERIC; + } + + psDeviceNode = psSysData->psDeviceNodeList; + while (psDeviceNode) { + if ((psDeviceNode->sDevId.eDeviceClass == + PVRSRV_DEVICE_CLASS_BUFFER) && + (psDeviceNode->sDevId.ui32DeviceIndex == ui32DeviceID)) { + + psBCInfo = (struct PVRSRV_BUFFERCLASS_INFO *) + psDeviceNode->pvDevice; + goto FoundDevice; + } + psDeviceNode = psDeviceNode->psNext; + } + + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenBCDeviceKM: No devnode matching index %d", + ui32DeviceID); + + return PVRSRV_ERROR_GENERIC; + +FoundDevice: + + if (OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(*psBCPerContextInfo), + (void **)&psBCPerContextInfo, NULL) != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed psBCPerContextInfo alloc"); + return PVRSRV_ERROR_OUT_OF_MEMORY; + } + OSMemSet(psBCPerContextInfo, 0, sizeof(*psBCPerContextInfo)); + + if (psBCInfo->ui32RefCount++ == 0) { + struct BUFFER_INFO sBufferInfo; + + psDeviceNode = (struct PVRSRV_DEVICE_NODE *)hDevCookie; + + psBCInfo->hDevMemContext = + (void *) psDeviceNode->sDevMemoryInfo.pBMKernelContext; + + eError = + psBCInfo->psFuncTable->pfnOpenBCDevice(&psBCInfo-> + hExtDevice); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed to open external BC device"); + return eError; + } + + eError = + psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice, + &sBufferInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVOpenBCDeviceKM : Failed to get BC Info"); + return eError; + } + + psBCInfo->ui32BufferCount = sBufferInfo.ui32BufferCount; + + eError = OSAllocMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_BUFFER) * + sBufferInfo.ui32BufferCount, + (void **) &psBCInfo->psBuffer, + NULL); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed to allocate BC buffers"); + return eError; + } + OSMemSet(psBCInfo->psBuffer, 0, + sizeof(struct PVRSRV_BC_BUFFER) * + sBufferInfo.ui32BufferCount); + + for (i = 0; i < psBCInfo->ui32BufferCount; i++) { + + eError = PVRSRVAllocSyncInfoKM(NULL, + psBCInfo->hDevMemContext, + &psBCInfo->psBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed sync info alloc"); + goto ErrorExit; + } + + eError = psBCInfo->psFuncTable->pfnGetBCBuffer( + psBCInfo->hExtDevice, i, + psBCInfo->psBuffer[i].sDeviceClassBuffer. + psKernelSyncInfo-> + psSyncData, + &psBCInfo->psBuffer[i].sDeviceClassBuffer. + hExtBuffer); + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVOpenBCDeviceKM: " + "Failed to get BC buffers"); + goto ErrorExit; + } + + psBCInfo->psBuffer[i].sDeviceClassBuffer. + pfnGetBufferAddr = + psBCInfo->psFuncTable->pfnGetBufferAddr; + psBCInfo->psBuffer[i].sDeviceClassBuffer. + hDevMemContext = psBCInfo->hDevMemContext; + psBCInfo->psBuffer[i].sDeviceClassBuffer.hExtDevice = + psBCInfo->hExtDevice; + } + } + + psBCPerContextInfo->psBCInfo = psBCInfo; + psBCPerContextInfo->hResItem = + ResManRegisterRes(psPerProc->hResManContext, + RESMAN_TYPE_BUFFERCLASS_DEVICE, + psBCPerContextInfo, 0, CloseBCDeviceCallBack); + + *phDeviceKM = (void *)psBCPerContextInfo; + + return PVRSRV_OK; + +ErrorExit: + + for (i = 0; i < psBCInfo->ui32BufferCount; i++) { + if (psBCInfo->psBuffer[i].sDeviceClassBuffer.psKernelSyncInfo) { + PVRSRVFreeSyncInfoKM(psBCInfo->psBuffer[i]. + sDeviceClassBuffer. + psKernelSyncInfo); + } + } + + if (psBCInfo->psBuffer) { + OSFreeMem(PVRSRV_OS_PAGEABLE_HEAP, + sizeof(struct PVRSRV_BC_BUFFER), psBCInfo->psBuffer, + NULL); + } + + return eError; +} + +enum PVRSRV_ERROR PVRSRVGetBCInfoKM(void *hDeviceKM, + struct BUFFER_INFO *psBufferInfo) +{ + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + enum PVRSRV_ERROR eError; + + if (!hDeviceKM || !psBufferInfo) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetBCInfoKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psBCInfo = BCDeviceHandleToBCInfo(hDeviceKM); + + eError = + psBCInfo->psFuncTable->pfnGetBCInfo(psBCInfo->hExtDevice, + psBufferInfo); + + if (eError != PVRSRV_OK) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetBCInfoKM : Failed to get BC Info"); + return eError; + } + + return PVRSRV_OK; +} + +enum PVRSRV_ERROR PVRSRVGetBCBufferKM(void *hDeviceKM, u32 ui32BufferIndex, + void **phBuffer) +{ + struct PVRSRV_BUFFERCLASS_INFO *psBCInfo; + + if (!hDeviceKM || !phBuffer) { + PVR_DPF(PVR_DBG_ERROR, + "PVRSRVGetBCBufferKM: Invalid parameters"); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + psBCInfo = BCDeviceHandleToBCInfo(hDeviceKM); + + if (ui32BufferIndex < psBCInfo->ui32BufferCount) { + *phBuffer = (void *)&psBCInfo->psBuffer[ui32BufferIndex]; + } else { + PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetBCBufferKM: " + "Buffer index %d out of range (%d)", + ui32BufferIndex, psBCInfo->ui32BufferCount); + return PVRSRV_ERROR_INVALID_PARAMS; + } + + return PVRSRV_OK; +} + +IMG_BOOL PVRGetBufferClassJTable(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE *psJTable) +{ + psJTable->ui32TableSize = sizeof(struct PVRSRV_BC_BUFFER2SRV_KMJTABLE); + + psJTable->pfnPVRSRVRegisterBCDevice = PVRSRVRegisterBCDeviceKM; + psJTable->pfnPVRSRVRemoveBCDevice = PVRSRVRemoveBCDeviceKM; + + return IMG_TRUE; +} +EXPORT_SYMBOL(PVRGetBufferClassJTable); + |