Maemo patchset 20101501+0m5
[h-e-n] / drivers / gpu / pvr / handle.c
diff --git a/drivers/gpu/pvr/handle.c b/drivers/gpu/pvr/handle.c
new file mode 100644 (file)
index 0000000..e8093e4
--- /dev/null
@@ -0,0 +1,1259 @@
+/**********************************************************************
+ *
+ * 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 <stddef.h>
+
+#include "services_headers.h"
+#include "handle.h"
+
+#ifdef DEBUG
+#define        HANDLE_BLOCK_SIZE       1
+#else
+#define        HANDLE_BLOCK_SIZE       256
+#endif
+
+#define        HANDLE_HASH_TAB_INIT_SIZE       32
+
+#define        INDEX_IS_VALID(psBase, i) ((i) < (psBase)->ui32TotalHandCount)
+
+#define        INDEX_TO_HANDLE(psBase, idx) ((void *)((idx) + 1))
+#define        HANDLE_TO_INDEX(psBase, hand) ((u32)(hand) - 1)
+
+#define INDEX_TO_HANDLE_PTR(psBase, i) (((psBase)->psHandleArray) + (i))
+
+#define        HANDLE_TO_HANDLE_PTR(psBase, h)                                 \
+       (INDEX_TO_HANDLE_PTR(psBase, HANDLE_TO_INDEX(psBase, h)))
+
+#define        HANDLE_PTR_TO_INDEX(psBase, psHandle)                           \
+       ((psHandle) - ((psBase)->psHandleArray))
+
+#define        HANDLE_PTR_TO_HANDLE(psBase, psHandle)                          \
+       INDEX_TO_HANDLE(psBase, HANDLE_PTR_TO_INDEX(psBase, psHandle))
+
+#define        ROUND_UP_TO_MULTIPLE(a, b) ((((a) + (b) - 1) / (b)) * (b))
+
+#define        HANDLES_BATCHED(psBase) ((psBase)->ui32HandBatchSize != 0)
+
+#define        SET_FLAG(v, f)          ((void)((v) |= (f)))
+#define        CLEAR_FLAG(v, f)        ((void)((v) &= ~(f)))
+#define        TEST_FLAG(v, f)         ((IMG_BOOL)(((v) & (f)) != 0))
+
+#define        TEST_ALLOC_FLAG(psHandle, f) TEST_FLAG((psHandle)->eFlag, f)
+
+#define        SET_INTERNAL_FLAG(psHandle, f)                          \
+                SET_FLAG((psHandle)->eInternalFlag, f)
+#define        CLEAR_INTERNAL_FLAG(psHandle, f)                        \
+                CLEAR_FLAG((psHandle)->eInternalFlag, f)
+#define        TEST_INTERNAL_FLAG(psHandle, f)                         \
+                TEST_FLAG((psHandle)->eInternalFlag, f)
+
+#define        BATCHED_HANDLE(psHandle)                                \
+                TEST_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
+
+#define        SET_BATCHED_HANDLE(psHandle)                            \
+                SET_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
+
+#define        SET_UNBATCHED_HANDLE(psHandle)                          \
+                CLEAR_INTERNAL_FLAG(psHandle, INTERNAL_HANDLE_FLAG_BATCHED)
+
+#define        BATCHED_HANDLE_PARTIALLY_FREE(psHandle)                 \
+                TEST_INTERNAL_FLAG(psHandle,                   \
+                               INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE)
+
+#define SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle)            \
+                SET_INTERNAL_FLAG(psHandle,                    \
+                               INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE)
+
+struct sHandleList {
+       u32 ui32Prev;
+       u32 ui32Next;
+       void *hParent;
+};
+
+enum ePVRSRVInternalHandleFlag {
+       INTERNAL_HANDLE_FLAG_BATCHED = 0x01,
+       INTERNAL_HANDLE_FLAG_BATCHED_PARTIALLY_FREE = 0x02,
+};
+
+struct sHandle {
+       enum PVRSRV_HANDLE_TYPE eType;
+       void *pvData;
+       u32 ui32NextIndexPlusOne;
+       enum ePVRSRVInternalHandleFlag eInternalFlag;
+       enum PVRSRV_HANDLE_ALLOC_FLAG eFlag;
+       u32 ui32PID;
+       u32 ui32Index;
+       struct sHandleList sChildren;
+       struct sHandleList sSiblings;
+};
+
+struct PVRSRV_HANDLE_BASE {
+       void *hBaseBlockAlloc;
+       u32 ui32PID;
+       void *hHandBlockAlloc;
+       struct RESMAN_ITEM *psResManItem;
+       struct sHandle *psHandleArray;
+       struct HASH_TABLE *psHashTab;
+       u32 ui32FreeHandCount;
+       u32 ui32FirstFreeIndex;
+       u32 ui32TotalHandCount;
+       u32 ui32LastFreeIndexPlusOne;
+       u32 ui32HandBatchSize;
+       u32 ui32TotalHandCountPreBatch;
+       u32 ui32FirstBatchIndexPlusOne;
+       u32 ui32BatchHandAllocFailures;
+};
+
+enum eHandKey {
+       HAND_KEY_DATA = 0,
+       HAND_KEY_TYPE,
+       HAND_KEY_PARENT,
+       HAND_KEY_LEN
+};
+
+struct PVRSRV_HANDLE_BASE *gpsKernelHandleBase;
+
+typedef u32 HAND_KEY[HAND_KEY_LEN];
+
+static inline void HandleListInit(u32 ui32Index, struct sHandleList *psList,
+                           void *hParent)
+{
+       psList->ui32Next = ui32Index;
+       psList->ui32Prev = ui32Index;
+       psList->hParent = hParent;
+}
+
+static inline void InitParentList(struct PVRSRV_HANDLE_BASE *psBase,
+                           struct sHandle *psHandle)
+{
+       u32 ui32Parent = HANDLE_PTR_TO_INDEX(psBase, psHandle);
+
+       HandleListInit(ui32Parent, &psHandle->sChildren,
+                      INDEX_TO_HANDLE(psBase, ui32Parent));
+}
+
+static inline void InitChildEntry(struct PVRSRV_HANDLE_BASE *psBase,
+                           struct sHandle *psHandle)
+{
+       HandleListInit(HANDLE_PTR_TO_INDEX(psBase, psHandle),
+                      &psHandle->sSiblings, NULL);
+}
+
+static inline IMG_BOOL HandleListIsEmpty(u32 ui32Index,
+                                        struct sHandleList *psList)
+{
+       IMG_BOOL bIsEmpty;
+
+       bIsEmpty = (IMG_BOOL) (psList->ui32Next == ui32Index);
+
+#ifdef DEBUG
+       {
+               IMG_BOOL bIsEmpty2;
+
+               bIsEmpty2 = (IMG_BOOL) (psList->ui32Prev == ui32Index);
+               PVR_ASSERT(bIsEmpty == bIsEmpty2);
+       }
+#endif
+
+       return bIsEmpty;
+}
+
+#ifdef DEBUG
+static inline IMG_BOOL NoChildren(struct PVRSRV_HANDLE_BASE *psBase,
+                                 struct sHandle *psHandle)
+{
+       PVR_ASSERT(psHandle->sChildren.hParent ==
+                  HANDLE_PTR_TO_HANDLE(psBase, psHandle));
+
+       return HandleListIsEmpty(HANDLE_PTR_TO_INDEX(psBase, psHandle),
+                                &psHandle->sChildren);
+}
+
+static inline IMG_BOOL NoParent(struct PVRSRV_HANDLE_BASE *psBase,
+                               struct sHandle *psHandle)
+{
+       if (HandleListIsEmpty
+           (HANDLE_PTR_TO_INDEX(psBase, psHandle), &psHandle->sSiblings)) {
+               PVR_ASSERT(psHandle->sSiblings.hParent == NULL);
+
+               return IMG_TRUE;
+       } else {
+               PVR_ASSERT(psHandle->sSiblings.hParent != NULL);
+       }
+       return IMG_FALSE;
+}
+#endif
+static inline void *ParentHandle(struct sHandle *psHandle)
+{
+       return psHandle->sSiblings.hParent;
+}
+
+#define        LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, i, p, po, eo)    \
+               ((struct sHandleList *)                         \
+               ((char *)(INDEX_TO_HANDLE_PTR(psBase, i)) +     \
+                        (((i) == (p)) ? (po) : (eo))))
+
+static inline void HandleListInsertBefore(struct PVRSRV_HANDLE_BASE *psBase,
+                                   u32 ui32InsIndex,
+                                   struct sHandleList *psIns,
+                                   size_t uiParentOffset,
+                                   u32 ui32EntryIndex,
+                                   struct sHandleList *psEntry,
+                                   size_t uiEntryOffset,
+                                   u32 ui32ParentIndex)
+{
+       struct sHandleList *psPrevIns =
+           LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psIns->ui32Prev,
+                                          ui32ParentIndex, uiParentOffset,
+                                          uiEntryOffset);
+
+       PVR_ASSERT(psEntry->hParent == NULL);
+       PVR_ASSERT(ui32InsIndex == psPrevIns->ui32Next);
+       PVR_ASSERT(LIST_PTR_FROM_INDEX_AND_OFFSET
+                  (psBase, ui32ParentIndex, ui32ParentIndex, uiParentOffset,
+                   uiParentOffset)->hParent == INDEX_TO_HANDLE(psBase,
+                                                       ui32ParentIndex));
+
+       psEntry->ui32Prev = psIns->ui32Prev;
+       psIns->ui32Prev = ui32EntryIndex;
+       psEntry->ui32Next = ui32InsIndex;
+       psPrevIns->ui32Next = ui32EntryIndex;
+
+       psEntry->hParent = INDEX_TO_HANDLE(psBase, ui32ParentIndex);
+}
+
+static inline void AdoptChild(struct PVRSRV_HANDLE_BASE *psBase,
+                             struct sHandle *psParent, struct sHandle *psChild)
+{
+       u32 ui32Parent =
+           HANDLE_TO_INDEX(psBase, psParent->sChildren.hParent);
+
+       PVR_ASSERT(ui32Parent ==
+                  (u32) HANDLE_PTR_TO_INDEX(psBase, psParent));
+
+       HandleListInsertBefore(psBase, ui32Parent, &psParent->sChildren,
+                              offsetof(struct sHandle, sChildren),
+                              HANDLE_PTR_TO_INDEX(psBase, psChild),
+                              &psChild->sSiblings, offsetof(struct sHandle,
+                                                            sSiblings),
+                              ui32Parent);
+
+}
+
+static inline void HandleListRemove(struct PVRSRV_HANDLE_BASE *psBase,
+                             u32 ui32EntryIndex, struct sHandleList *psEntry,
+                             size_t uiEntryOffset, size_t uiParentOffset)
+{
+       if (!HandleListIsEmpty(ui32EntryIndex, psEntry)) {
+               struct sHandleList *psPrev =
+                   LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Prev,
+                                                  HANDLE_TO_INDEX(psBase,
+                                                                  psEntry->
+                                                                  hParent),
+                                                  uiParentOffset,
+                                                  uiEntryOffset);
+               struct sHandleList *psNext =
+                   LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, psEntry->ui32Next,
+                                                  HANDLE_TO_INDEX(psBase,
+                                                                  psEntry->
+                                                                  hParent),
+                                                  uiParentOffset,
+                                                  uiEntryOffset);
+
+               PVR_ASSERT(psEntry->hParent != NULL);
+
+               psPrev->ui32Next = psEntry->ui32Next;
+               psNext->ui32Prev = psEntry->ui32Prev;
+
+               HandleListInit(ui32EntryIndex, psEntry, NULL);
+       }
+}
+
+static inline void UnlinkFromParent(struct PVRSRV_HANDLE_BASE *psBase,
+                             struct sHandle *psHandle)
+{
+       HandleListRemove(psBase, HANDLE_PTR_TO_INDEX(psBase, psHandle),
+                        &psHandle->sSiblings, offsetof(struct sHandle,
+                                                       sSiblings),
+                        offsetof(struct sHandle, sChildren));
+}
+
+static inline enum PVRSRV_ERROR HandleListIterate(
+                                  struct PVRSRV_HANDLE_BASE *psBase,
+                                  struct sHandleList *psHead,
+                                  size_t uiParentOffset,
+                                  size_t uiEntryOffset,
+                                  enum PVRSRV_ERROR(*pfnIterFunc)
+                                               (struct PVRSRV_HANDLE_BASE *,
+                                                struct sHandle *))
+{
+       u32 ui32Index;
+       u32 ui32Parent = HANDLE_TO_INDEX(psBase, psHead->hParent);
+
+       PVR_ASSERT(psHead->hParent != NULL);
+
+       for (ui32Index = psHead->ui32Next; ui32Index != ui32Parent;) {
+               struct sHandle *psHandle =
+                   INDEX_TO_HANDLE_PTR(psBase, ui32Index);
+               struct sHandleList *psEntry =
+                   LIST_PTR_FROM_INDEX_AND_OFFSET(psBase, ui32Index,
+                                                  ui32Parent, uiParentOffset,
+                                                  uiEntryOffset);
+               enum PVRSRV_ERROR eError;
+
+               PVR_ASSERT(psEntry->hParent == psHead->hParent);
+
+               ui32Index = psEntry->ui32Next;
+
+               eError = (*pfnIterFunc) (psBase, psHandle);
+               if (eError != PVRSRV_OK)
+                       return eError;
+       }
+
+       return PVRSRV_OK;
+}
+
+static inline enum PVRSRV_ERROR IterateOverChildren(
+                               struct PVRSRV_HANDLE_BASE *psBase,
+                               struct sHandle *psParent,
+                               enum PVRSRV_ERROR(*pfnIterFunc)
+                               (struct PVRSRV_HANDLE_BASE *, struct sHandle *))
+{
+       return HandleListIterate(psBase, &psParent->sChildren,
+                                offsetof(struct sHandle, sChildren),
+                                offsetof(struct sHandle, sSiblings),
+                                pfnIterFunc);
+}
+
+static inline enum PVRSRV_ERROR GetHandleStructure(
+                                   struct PVRSRV_HANDLE_BASE *psBase,
+                                   struct sHandle **ppsHandle,
+                                   void *hHandle,
+                                   enum PVRSRV_HANDLE_TYPE eType)
+{
+       u32 ui32Index = HANDLE_TO_INDEX(psBase, hHandle);
+       struct sHandle *psHandle;
+
+       if (!INDEX_IS_VALID(psBase, ui32Index)) {
+               PVR_DPF(PVR_DBG_ERROR, "GetHandleStructure: "
+                        "Handle index out of range (%u >= %u)",
+                        ui32Index, psBase->ui32TotalHandCount);
+               return PVRSRV_ERROR_GENERIC;
+       }
+
+       psHandle = INDEX_TO_HANDLE_PTR(psBase, ui32Index);
+       if (psHandle->eType == PVRSRV_HANDLE_TYPE_NONE) {
+               PVR_DPF(PVR_DBG_ERROR, "GetHandleStructure: "
+                        "Handle not allocated (index: %u)", ui32Index);
+               return PVRSRV_ERROR_GENERIC;
+       }
+
+       if (eType != PVRSRV_HANDLE_TYPE_NONE && eType != psHandle->eType) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "GetHandleStructure: Handle type mismatch (%d != %d)",
+                        eType, psHandle->eType);
+               return PVRSRV_ERROR_GENERIC;
+       }
+
+       PVR_ASSERT(psBase->ui32PID == psHandle->ui32PID);
+
+       *ppsHandle = psHandle;
+
+       return PVRSRV_OK;
+}
+
+static inline void *ParentIfPrivate(struct sHandle *psHandle)
+{
+       return TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ?
+               ParentHandle(psHandle) : NULL;
+}
+
+static inline void InitKey(HAND_KEY aKey, struct PVRSRV_HANDLE_BASE *psBase,
+                    void *pvData, enum PVRSRV_HANDLE_TYPE eType,
+                    void *hParent)
+{
+       PVR_UNREFERENCED_PARAMETER(psBase);
+
+       aKey[HAND_KEY_DATA] = (u32) pvData;
+       aKey[HAND_KEY_TYPE] = (u32) eType;
+       aKey[HAND_KEY_PARENT] = (u32) hParent;
+}
+
+static void FreeHandleArray(struct PVRSRV_HANDLE_BASE *psBase)
+{
+       enum PVRSRV_ERROR eError = PVRSRV_OK;
+
+       if (psBase->psHandleArray != NULL) {
+               OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                          psBase->ui32TotalHandCount *
+                          sizeof(struct sHandle),
+                          psBase->psHandleArray,
+                          psBase->hHandBlockAlloc);
+
+               psBase->psHandleArray = NULL;
+       }
+}
+
+static enum PVRSRV_ERROR FreeHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                              struct sHandle *psHandle)
+{
+       HAND_KEY aKey;
+       u32 ui32Index = HANDLE_PTR_TO_INDEX(psBase, psHandle);
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(psBase->ui32PID == psHandle->ui32PID);
+
+       InitKey(aKey, psBase, psHandle->pvData, psHandle->eType,
+               ParentIfPrivate(psHandle));
+
+       if (!TEST_ALLOC_FLAG(psHandle, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)
+           && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) {
+               void *hHandle;
+               hHandle =
+                   (void *) HASH_Remove_Extended(psBase->psHashTab, aKey);
+
+               PVR_ASSERT(hHandle != NULL);
+               PVR_ASSERT(hHandle == INDEX_TO_HANDLE(psBase, ui32Index));
+               PVR_UNREFERENCED_PARAMETER(hHandle);
+       }
+
+       UnlinkFromParent(psBase, psHandle);
+
+       eError = IterateOverChildren(psBase, psHandle, FreeHandle);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "FreeHandle: Error whilst freeing subhandles (%d)",
+                        eError);
+               return eError;
+       }
+
+       psHandle->eType = PVRSRV_HANDLE_TYPE_NONE;
+
+       if (BATCHED_HANDLE(psHandle)
+           && !BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) {
+               SET_BATCHED_HANDLE_PARTIALLY_FREE(psHandle);
+
+               return PVRSRV_OK;
+       }
+
+       if (psBase->ui32FreeHandCount == 0) {
+               PVR_ASSERT(psBase->ui32FirstFreeIndex == 0);
+               PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0);
+
+               psBase->ui32FirstFreeIndex = ui32Index;
+       } else {
+
+               PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0);
+               PVR_ASSERT(INDEX_TO_HANDLE_PTR
+                          (psBase,
+                           psBase->ui32LastFreeIndexPlusOne -
+                           1)->ui32NextIndexPlusOne == 0);
+
+               INDEX_TO_HANDLE_PTR(psBase,
+                                   psBase->ui32LastFreeIndexPlusOne -
+                                   1)->ui32NextIndexPlusOne = ui32Index + 1;
+       }
+
+       PVR_ASSERT(psHandle->ui32NextIndexPlusOne == 0);
+
+       psBase->ui32LastFreeIndexPlusOne = ui32Index + 1;
+
+       psBase->ui32FreeHandCount++;
+
+       return PVRSRV_OK;
+}
+
+static enum PVRSRV_ERROR FreeAllHandles(struct PVRSRV_HANDLE_BASE *psBase)
+{
+       u32 i;
+       enum PVRSRV_ERROR eError = PVRSRV_OK;
+
+       if (psBase->ui32FreeHandCount == psBase->ui32TotalHandCount)
+               return eError;
+
+       for (i = 0; i < psBase->ui32TotalHandCount; i++) {
+               struct sHandle *psHandle;
+
+               psHandle = INDEX_TO_HANDLE_PTR(psBase, i);
+
+               if (psHandle->eType != PVRSRV_HANDLE_TYPE_NONE) {
+                       eError = FreeHandle(psBase, psHandle);
+                       if (eError != PVRSRV_OK) {
+                               PVR_DPF(PVR_DBG_ERROR,
+                                      "FreeAllHandles: FreeHandle failed (%d)",
+                                       eError);
+                               break;
+                       }
+
+                       if (psBase->ui32FreeHandCount ==
+                           psBase->ui32TotalHandCount)
+                               break;
+               }
+       }
+
+       return eError;
+}
+
+static enum PVRSRV_ERROR FreeHandleBase(struct PVRSRV_HANDLE_BASE *psBase)
+{
+       enum PVRSRV_ERROR eError;
+
+       if (HANDLES_BATCHED(psBase)) {
+               PVR_DPF(PVR_DBG_WARNING,
+                       "FreeHandleBase: Uncommitted/Unreleased handle batch");
+               PVRSRVReleaseHandleBatch(psBase);
+       }
+
+       eError = FreeAllHandles(psBase);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "FreeHandleBase: Couldn't free handles (%d)", eError);
+               return eError;
+       }
+
+       FreeHandleArray(psBase);
+
+       if (psBase->psHashTab != NULL)
+
+               HASH_Delete(psBase->psHashTab);
+
+       OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                          sizeof(*psBase), psBase, psBase->hBaseBlockAlloc);
+
+       return PVRSRV_OK;
+}
+
+static inline void *FindHandle(struct PVRSRV_HANDLE_BASE *psBase, void *pvData,
+                         enum PVRSRV_HANDLE_TYPE eType, void *hParent)
+{
+       HAND_KEY aKey;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       InitKey(aKey, psBase, pvData, eType, hParent);
+
+       return (void *)HASH_Retrieve_Extended(psBase->psHashTab, aKey);
+}
+
+static enum PVRSRV_ERROR IncreaseHandleArraySize(
+                                           struct PVRSRV_HANDLE_BASE *psBase,
+                                           u32 ui32Delta)
+{
+       struct sHandle *psNewHandleArray;
+       void *hNewHandBlockAlloc;
+       enum PVRSRV_ERROR eError;
+       struct sHandle *psHandle;
+       u32 ui32DeltaRounded =
+           ROUND_UP_TO_MULTIPLE(ui32Delta, HANDLE_BLOCK_SIZE);
+       u32 ui32NewTotalHandCount =
+           psBase->ui32TotalHandCount + ui32DeltaRounded;
+       ;
+
+       eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                           ui32NewTotalHandCount * sizeof(struct sHandle),
+                           (void **) &psNewHandleArray,
+                           &hNewHandBlockAlloc);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "IncreaseHandleArraySize: "
+                               "Couldn't allocate new handle array (%d)",
+                        eError);
+               return eError;
+       }
+
+       if (psBase->psHandleArray != NULL)
+               OSMemCopy(psNewHandleArray,
+                         psBase->psHandleArray,
+                         psBase->ui32TotalHandCount * sizeof(struct sHandle));
+
+       for (psHandle = psNewHandleArray + psBase->ui32TotalHandCount;
+            psHandle < psNewHandleArray + ui32NewTotalHandCount; psHandle++) {
+               psHandle->eType = PVRSRV_HANDLE_TYPE_NONE;
+               psHandle->ui32NextIndexPlusOne = 0;
+       }
+
+       FreeHandleArray(psBase);
+
+       psBase->psHandleArray = psNewHandleArray;
+       psBase->hHandBlockAlloc = hNewHandBlockAlloc;
+
+       psBase->ui32FreeHandCount += ui32DeltaRounded;
+
+       if (psBase->ui32FirstFreeIndex == 0) {
+               PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne == 0);
+
+               psBase->ui32FirstFreeIndex = psBase->ui32TotalHandCount;
+       } else {
+               PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne != 0);
+                   PVR_ASSERT(INDEX_TO_HANDLE_PTR
+                              (psBase,
+                               psBase->ui32LastFreeIndexPlusOne -
+                               1)->ui32NextIndexPlusOne == 0);
+
+               INDEX_TO_HANDLE_PTR(psBase,
+                                   psBase->ui32LastFreeIndexPlusOne -
+                                   1)->ui32NextIndexPlusOne =
+                   psBase->ui32TotalHandCount + 1;
+
+       }
+       psBase->ui32LastFreeIndexPlusOne = ui32NewTotalHandCount;
+
+       psBase->ui32TotalHandCount = ui32NewTotalHandCount;
+
+       return PVRSRV_OK;
+}
+
+static enum PVRSRV_ERROR EnsureFreeHandles(struct PVRSRV_HANDLE_BASE *psBase,
+                                     u32 ui32Free)
+{
+       enum PVRSRV_ERROR eError;
+
+       if (ui32Free > psBase->ui32FreeHandCount) {
+               u32 ui32FreeHandDelta =
+                   ui32Free - psBase->ui32FreeHandCount;
+               eError = IncreaseHandleArraySize(psBase, ui32FreeHandDelta);
+               if (eError != PVRSRV_OK) {
+                       PVR_DPF(PVR_DBG_ERROR, "EnsureFreeHandles: "
+                              "Couldn't allocate %u handles "
+                              "to ensure %u free handles "
+                              "(IncreaseHandleArraySize failed with error %d)",
+                               ui32FreeHandDelta, ui32Free, eError);
+
+                       return eError;
+               }
+       }
+
+       return PVRSRV_OK;
+}
+
+static enum PVRSRV_ERROR AllocHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                               void **phHandle, void *pvData,
+                               enum PVRSRV_HANDLE_TYPE eType,
+                               enum PVRSRV_HANDLE_ALLOC_FLAG eFlag,
+                               void *hParent)
+{
+       u32 ui32NewIndex;
+       struct sHandle *psNewHandle;
+       void *hHandle;
+       HAND_KEY aKey;
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       PVR_ASSERT(psBase->psHashTab != NULL);
+
+       if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) {
+
+               PVR_ASSERT(FindHandle(psBase, pvData, eType, hParent) ==
+                          NULL);
+       }
+
+       if (psBase->ui32FreeHandCount == 0 && HANDLES_BATCHED(psBase)) {
+               PVR_DPF(PVR_DBG_WARNING, "AllocHandle: "
+                       "Handle batch size (%u) was too small, "
+                       "allocating additional space",
+                        psBase->ui32HandBatchSize);
+       }
+
+       eError = EnsureFreeHandles(psBase, 1);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "AllocHandle: EnsureFreeHandles failed (%d)", eError);
+               return eError;
+       }
+       PVR_ASSERT(psBase->ui32FreeHandCount != 0);
+
+           ui32NewIndex = psBase->ui32FirstFreeIndex;
+
+       psNewHandle = INDEX_TO_HANDLE_PTR(psBase, ui32NewIndex);
+
+       hHandle = INDEX_TO_HANDLE(psBase, ui32NewIndex);
+
+       if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) {
+
+               InitKey(aKey, psBase, pvData, eType, hParent);
+
+               if (!HASH_Insert_Extended
+                   (psBase->psHashTab, aKey, (u32) hHandle)) {
+                       PVR_DPF(PVR_DBG_ERROR, "AllocHandle: "
+                               "Couldn't add handle to hash table");
+
+                       return PVRSRV_ERROR_GENERIC;
+               }
+       }
+
+       psBase->ui32FreeHandCount--;
+
+       if (psBase->ui32FreeHandCount == 0) {
+               PVR_ASSERT(psBase->ui32FirstFreeIndex == ui32NewIndex);
+               PVR_ASSERT(psBase->ui32LastFreeIndexPlusOne ==
+                          (ui32NewIndex + 1));
+
+               psBase->ui32LastFreeIndexPlusOne = 0;
+               psBase->ui32FirstFreeIndex = 0;
+       } else {
+
+               psBase->ui32FirstFreeIndex =
+                   (psNewHandle->ui32NextIndexPlusOne ==
+                    0) ? ui32NewIndex + 1 : psNewHandle->ui32NextIndexPlusOne -
+                   1;
+       }
+
+       psNewHandle->eType = eType;
+       psNewHandle->pvData = pvData;
+       psNewHandle->eInternalFlag = 0;
+       psNewHandle->eFlag = eFlag;
+       psNewHandle->ui32PID = psBase->ui32PID;
+       psNewHandle->ui32Index = ui32NewIndex;
+
+       InitParentList(psBase, psNewHandle);
+       PVR_ASSERT(NoChildren(psBase, psNewHandle));
+
+       InitChildEntry(psBase, psNewHandle);
+       PVR_ASSERT(NoParent(psBase, psNewHandle));
+
+       if (HANDLES_BATCHED(psBase)) {
+
+               psNewHandle->ui32NextIndexPlusOne =
+                   psBase->ui32FirstBatchIndexPlusOne;
+
+               psBase->ui32FirstBatchIndexPlusOne = ui32NewIndex + 1;
+
+               SET_BATCHED_HANDLE(psNewHandle);
+       } else {
+               psNewHandle->ui32NextIndexPlusOne = 0;
+       }
+
+       *phHandle = hHandle;
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVAllocHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                              void **phHandle, void *pvData,
+                              enum PVRSRV_HANDLE_TYPE eType,
+                              enum PVRSRV_HANDLE_ALLOC_FLAG eFlag)
+{
+       void *hHandle;
+       enum PVRSRV_ERROR eError;
+
+       *phHandle = NULL;
+
+       if (HANDLES_BATCHED(psBase))
+
+               psBase->ui32BatchHandAllocFailures++;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) {
+
+               hHandle = FindHandle(psBase, pvData, eType, NULL);
+               if (hHandle != NULL) {
+                       struct sHandle *psHandle;
+
+                       eError =
+                           GetHandleStructure(psBase, &psHandle, hHandle,
+                                              eType);
+                       if (eError != PVRSRV_OK) {
+                               PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocHandle: "
+                                         "Lookup of existing handle failed");
+                               return eError;
+                       }
+
+                       if (TEST_FLAG
+                           (psHandle->eFlag & eFlag,
+                            PVRSRV_HANDLE_ALLOC_FLAG_SHARED)) {
+                               *phHandle = hHandle;
+                               eError = PVRSRV_OK;
+                               goto exit_ok;
+                       }
+                       return PVRSRV_ERROR_GENERIC;
+               }
+       }
+
+       eError = AllocHandle(psBase, phHandle, pvData, eType, eFlag, NULL);
+
+exit_ok:
+       if (HANDLES_BATCHED(psBase) && (eError == PVRSRV_OK))
+               psBase->ui32BatchHandAllocFailures--;
+
+       return eError;
+}
+
+enum PVRSRV_ERROR PVRSRVAllocSubHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                                 void **phHandle, void *pvData,
+                                 enum PVRSRV_HANDLE_TYPE eType,
+                                 enum PVRSRV_HANDLE_ALLOC_FLAG eFlag,
+                                 void *hParent)
+{
+       struct sHandle *psPHand;
+       struct sHandle *psCHand;
+       enum PVRSRV_ERROR eError;
+       void *hParentKey;
+       void *hHandle;
+
+       *phHandle = NULL;
+
+       if (HANDLES_BATCHED(psBase))
+
+               psBase->ui32BatchHandAllocFailures++;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       hParentKey = TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_PRIVATE) ?
+           hParent : NULL;
+
+       eError =
+           GetHandleStructure(psBase, &psPHand, hParent,
+                              PVRSRV_HANDLE_TYPE_NONE);
+       if (eError != PVRSRV_OK)
+               return PVRSRV_ERROR_GENERIC;
+
+       if (!TEST_FLAG(eFlag, PVRSRV_HANDLE_ALLOC_FLAG_MULTI)) {
+
+               hHandle = FindHandle(psBase, pvData, eType, hParentKey);
+               if (hHandle != NULL) {
+                       struct sHandle *psCHandle;
+                       enum PVRSRV_ERROR eErr;
+
+                       eErr =
+                           GetHandleStructure(psBase, &psCHandle, hHandle,
+                                              eType);
+                       if (eErr != PVRSRV_OK) {
+                               PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocSubHandle: "
+                                       "Lookup of existing handle failed");
+                               return eErr;
+                       }
+
+                       PVR_ASSERT(hParentKey != NULL
+                                  &&
+                                  ParentHandle(HANDLE_TO_HANDLE_PTR
+                                               (psBase, hHandle)) == hParent);
+
+                       if (TEST_FLAG
+                           (psCHandle->eFlag & eFlag,
+                            PVRSRV_HANDLE_ALLOC_FLAG_SHARED)
+                           &&
+                           ParentHandle(HANDLE_TO_HANDLE_PTR(psBase, hHandle))
+                           == hParent) {
+                               *phHandle = hHandle;
+                               goto exit_ok;
+                       }
+                       return PVRSRV_ERROR_GENERIC;
+               }
+       }
+
+       eError =
+           AllocHandle(psBase, &hHandle, pvData, eType, eFlag, hParentKey);
+       if (eError != PVRSRV_OK)
+               return eError;
+
+       psPHand = HANDLE_TO_HANDLE_PTR(psBase, hParent);
+
+       psCHand = HANDLE_TO_HANDLE_PTR(psBase, hHandle);
+
+       AdoptChild(psBase, psPHand, psCHand);
+
+       *phHandle = hHandle;
+
+exit_ok:
+       if (HANDLES_BATCHED(psBase))
+               psBase->ui32BatchHandAllocFailures--;
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVFindHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                             void **phHandle, void *pvData,
+                             enum PVRSRV_HANDLE_TYPE eType)
+{
+       void *hHandle;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       hHandle = (void *) FindHandle(psBase, pvData, eType, NULL);
+       if (hHandle == NULL) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "PVRSRVFindHandle: couldn't find handle");
+               return PVRSRV_ERROR_GENERIC;
+       }
+
+       *phHandle = hHandle;
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVLookupHandleAnyType(struct PVRSRV_HANDLE_BASE *psBase,
+                                      void **ppvData,
+                                      enum PVRSRV_HANDLE_TYPE *peType,
+                                      void *hHandle)
+{
+       struct sHandle *psHandle;
+       enum PVRSRV_ERROR eError;
+
+       eError =
+           GetHandleStructure(psBase, &psHandle, hHandle,
+                              PVRSRV_HANDLE_TYPE_NONE);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupHandleAnyType: "
+                                       "Error looking up handle (%d)",
+                                       eError);
+               return eError;
+       }
+
+       *ppvData = psHandle->pvData;
+       *peType = psHandle->eType;
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVLookupHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                               void **ppvData, void *hHandle,
+                               enum PVRSRV_HANDLE_TYPE eType)
+{
+       struct sHandle *psHandle;
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "PVRSRVLookupHandle: Error looking up handle (%d)",
+                        eError);
+               return eError;
+       }
+
+       *ppvData = psHandle->pvData;
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVLookupSubHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                                  void **ppvData, void *hHandle,
+                                  enum PVRSRV_HANDLE_TYPE eType,
+                                  void *hAncestor)
+{
+       struct sHandle *psPHand;
+       struct sHandle *psCHand;
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       eError = GetHandleStructure(psBase, &psCHand, hHandle, eType);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupSubHandle: "
+                       "Error looking up subhandle (%d)",
+                        eError);
+               return eError;
+       }
+
+       for (psPHand = psCHand; ParentHandle(psPHand) != hAncestor;) {
+               eError =
+                   GetHandleStructure(psBase, &psPHand, ParentHandle(psPHand),
+                                      PVRSRV_HANDLE_TYPE_NONE);
+               if (eError != PVRSRV_OK) {
+                       PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupSubHandle: "
+                               "Subhandle doesn't belong to given ancestor");
+                       return PVRSRV_ERROR_GENERIC;
+               }
+       }
+
+       *ppvData = psCHand->pvData;
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVGetParentHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                                  void **phParent, void *hHandle,
+                                  enum PVRSRV_HANDLE_TYPE eType)
+{
+       struct sHandle *psHandle;
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVGetParentHandle: "
+                                       "Error looking up subhandle (%d)",
+                        eError);
+               return eError;
+       }
+
+       *phParent = ParentHandle(psHandle);
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVLookupAndReleaseHandle(
+                               struct PVRSRV_HANDLE_BASE *psBase,
+                               void **ppvData, void *hHandle,
+                               enum PVRSRV_HANDLE_TYPE eType)
+{
+       struct sHandle *psHandle;
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVLookupAndReleaseHandle: "
+                       "Error looking up handle (%d)",
+                        eError);
+               return eError;
+       }
+
+       *ppvData = psHandle->pvData;
+
+       eError = FreeHandle(psBase, psHandle);
+
+       return eError;
+}
+
+enum PVRSRV_ERROR PVRSRVReleaseHandle(struct PVRSRV_HANDLE_BASE *psBase,
+                                void *hHandle, enum PVRSRV_HANDLE_TYPE eType)
+{
+       struct sHandle *psHandle;
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(eType != PVRSRV_HANDLE_TYPE_NONE);
+
+       eError = GetHandleStructure(psBase, &psHandle, hHandle, eType);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR,
+                        "PVRSRVReleaseHandle: Error looking up handle (%d)",
+                        eError);
+               return eError;
+       }
+
+       eError = FreeHandle(psBase, psHandle);
+
+       return eError;
+}
+
+enum PVRSRV_ERROR PVRSRVNewHandleBatch(struct PVRSRV_HANDLE_BASE *psBase,
+                                 u32 ui32BatchSize)
+{
+       enum PVRSRV_ERROR eError;
+
+       if (HANDLES_BATCHED(psBase)) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVNewHandleBatch: "
+                       "There is a handle batch already in use (size %u)",
+                        psBase->ui32HandBatchSize);
+               return PVRSRV_ERROR_GENERIC;
+       }
+
+       if (ui32BatchSize == 0) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVNewHandleBatch: "
+                       "Invalid batch size (%u)", ui32BatchSize);
+               return PVRSRV_ERROR_INVALID_PARAMS;
+       }
+
+       eError = EnsureFreeHandles(psBase, ui32BatchSize);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVNewHandleBatch: "
+                        "EnsureFreeHandles failed (error %d)", eError);
+               return eError;
+       }
+
+       psBase->ui32HandBatchSize = ui32BatchSize;
+       psBase->ui32TotalHandCountPreBatch = psBase->ui32TotalHandCount;
+
+       PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0);
+       PVR_ASSERT(psBase->ui32FirstBatchIndexPlusOne == 0);
+       PVR_ASSERT(HANDLES_BATCHED(psBase));
+
+       return PVRSRV_OK;
+}
+
+static enum PVRSRV_ERROR PVRSRVHandleBatchCommitOrRelease(
+                       struct PVRSRV_HANDLE_BASE *psBase, IMG_BOOL bCommit)
+{
+       u32 ui32IndexPlusOne;
+       IMG_BOOL bCommitBatch = bCommit;
+
+       if (!HANDLES_BATCHED(psBase)) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVHandleBatchCommitOrRelease: "
+                                       "There is no handle batch");
+               return PVRSRV_ERROR_INVALID_PARAMS;
+
+       }
+
+       if (psBase->ui32BatchHandAllocFailures != 0) {
+               if (bCommit)
+                       PVR_DPF(PVR_DBG_ERROR,
+                               "PVRSRVHandleBatchCommitOrRelease: "
+                               "Attempting to commit batch "
+                               "with handle allocation failures.");
+               bCommitBatch = IMG_FALSE;
+       }
+
+       PVR_ASSERT(psBase->ui32BatchHandAllocFailures == 0 || !bCommit);
+
+       ui32IndexPlusOne = psBase->ui32FirstBatchIndexPlusOne;
+       while (ui32IndexPlusOne != 0) {
+               struct sHandle *psHandle =
+                   INDEX_TO_HANDLE_PTR(psBase, ui32IndexPlusOne - 1);
+               u32 ui32NextIndexPlusOne =
+                   psHandle->ui32NextIndexPlusOne;
+               PVR_ASSERT(BATCHED_HANDLE(psHandle));
+
+               psHandle->ui32NextIndexPlusOne = 0;
+
+               if (!bCommitBatch || BATCHED_HANDLE_PARTIALLY_FREE(psHandle)) {
+                       enum PVRSRV_ERROR eError;
+
+                       if (!BATCHED_HANDLE_PARTIALLY_FREE(psHandle))
+                               SET_UNBATCHED_HANDLE(psHandle);
+
+                       eError = FreeHandle(psBase, psHandle);
+                       if (eError != PVRSRV_OK)
+                               PVR_DPF(PVR_DBG_ERROR,
+                                        "PVRSRVHandleBatchCommitOrRelease: "
+                                        "Error freeing handle (%d)", eError);
+                       PVR_ASSERT(eError == PVRSRV_OK);
+               } else {
+                       SET_UNBATCHED_HANDLE(psHandle);
+               }
+
+               ui32IndexPlusOne = ui32NextIndexPlusOne;
+       }
+
+#ifdef DEBUG
+       if (psBase->ui32TotalHandCountPreBatch != psBase->ui32TotalHandCount) {
+               u32 ui32Delta =
+                   psBase->ui32TotalHandCount -
+                   psBase->ui32TotalHandCountPreBatch;
+
+               PVR_ASSERT(psBase->ui32TotalHandCount >
+                          psBase->ui32TotalHandCountPreBatch);
+
+               PVR_DPF(PVR_DBG_WARNING,
+                        "PVRSRVHandleBatchCommitOrRelease: "
+                        "The batch size was too small.  "
+                        "Batch size was %u, but needs to be %u",
+                        psBase->ui32HandBatchSize,
+                        psBase->ui32HandBatchSize + ui32Delta);
+
+       }
+#endif
+
+       psBase->ui32HandBatchSize = 0;
+       psBase->ui32FirstBatchIndexPlusOne = 0;
+       psBase->ui32TotalHandCountPreBatch = 0;
+       psBase->ui32BatchHandAllocFailures = 0;
+
+       if (psBase->ui32BatchHandAllocFailures != 0 && bCommit) {
+               PVR_ASSERT(!bCommitBatch);
+
+               return PVRSRV_ERROR_GENERIC;
+       }
+
+       return PVRSRV_OK;
+}
+
+enum PVRSRV_ERROR PVRSRVCommitHandleBatch(struct PVRSRV_HANDLE_BASE *psBase)
+{
+       return PVRSRVHandleBatchCommitOrRelease(psBase, IMG_TRUE);
+}
+
+void PVRSRVReleaseHandleBatch(struct PVRSRV_HANDLE_BASE *psBase)
+{
+       (void)PVRSRVHandleBatchCommitOrRelease(psBase, IMG_FALSE);
+}
+
+enum PVRSRV_ERROR PVRSRVAllocHandleBase(struct PVRSRV_HANDLE_BASE **ppsBase,
+                                  u32 ui32PID)
+{
+       struct PVRSRV_HANDLE_BASE *psBase;
+       void *hBlockAlloc;
+       enum PVRSRV_ERROR eError;
+
+       eError = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+                           sizeof(*psBase),
+                           (void **) &psBase, &hBlockAlloc);
+       if (eError != PVRSRV_OK) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocHandleBase: "
+                        "Couldn't allocate handle base (%d)",
+                        eError);
+               return eError;
+       }
+       OSMemSet(psBase, 0, sizeof(*psBase));
+
+       psBase->psHashTab =
+           HASH_Create_Extended(HANDLE_HASH_TAB_INIT_SIZE, sizeof(HAND_KEY),
+                                HASH_Func_Default, HASH_Key_Comp_Default);
+       if (psBase->psHashTab == NULL) {
+               PVR_DPF(PVR_DBG_ERROR, "PVRSRVAllocHandleBase: "
+                        "Couldn't create data pointer hash table\n");
+               goto failure;
+       }
+
+       psBase->hBaseBlockAlloc = hBlockAlloc;
+       psBase->ui32PID = ui32PID;
+
+       *ppsBase = psBase;
+
+       return PVRSRV_OK;
+failure:
+       (void)PVRSRVFreeHandleBase(psBase);
+       return PVRSRV_ERROR_GENERIC;
+}
+
+enum PVRSRV_ERROR PVRSRVFreeHandleBase(struct PVRSRV_HANDLE_BASE *psBase)
+{
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(psBase != gpsKernelHandleBase);
+
+       eError = FreeHandleBase(psBase);
+
+       return eError;
+}
+
+enum PVRSRV_ERROR PVRSRVHandleInit(void)
+{
+       enum PVRSRV_ERROR eError;
+
+       PVR_ASSERT(gpsKernelHandleBase == NULL);
+
+       eError = PVRSRVAllocHandleBase(&gpsKernelHandleBase, KERNEL_ID);
+
+       return eError;
+}
+
+enum PVRSRV_ERROR PVRSRVHandleDeInit(void)
+{
+       enum PVRSRV_ERROR eError = PVRSRV_OK;
+
+       if (gpsKernelHandleBase != NULL) {
+               eError = FreeHandleBase(gpsKernelHandleBase);
+               if (eError == PVRSRV_OK)
+                       gpsKernelHandleBase = NULL;
+       }
+
+       return eError;
+}