1 /**********************************************************************
3 * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful but, except
10 * as otherwise stated in writing, without any warranty; without even the
11 * implied warranty of merchantability or fitness for a particular purpose.
12 * See the GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 * The full GNU General Public License is included in this distribution in
19 * the file called "COPYING".
21 * Contact Information:
22 * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23 * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
25 ******************************************************************************/
27 #include <linux/version.h>
30 #include <asm/system.h>
32 #include <linux/slab.h>
33 #include <linux/vmalloc.h>
34 #include <linux/delay.h>
35 #include <linux/pci.h>
37 #include <linux/string.h>
38 #include <linux/sched.h>
39 #include <linux/interrupt.h>
40 #include <linux/hardirq.h>
41 #include <linux/timer.h>
42 #include <linux/capability.h>
43 #include <linux/sched.h>
44 #include <linux/uaccess.h>
46 #include "img_types.h"
47 #include "services_headers.h"
54 #include "pvr_bridge_km.h"
56 struct PVRSRV_LINUX_EVENT_OBJECT_LIST {
58 struct list_head sList;
62 struct PVRSRV_LINUX_EVENT_OBJECT {
64 u32 ui32TimeStampPrevious;
65 #if defined(CONFIG_PVR_DEBUG_EXTRA)
68 wait_queue_head_t sWait;
69 struct list_head sList;
71 struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList;
74 enum PVRSRV_ERROR LinuxEventObjectListCreate(void **phEventObjectList)
76 struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList;
79 (PVRSRV_OS_NON_PAGEABLE_HEAP,
80 sizeof(struct PVRSRV_LINUX_EVENT_OBJECT_LIST),
81 (void **) &psEvenObjectList, NULL) != PVRSRV_OK) {
82 PVR_DPF(PVR_DBG_ERROR, "LinuxEventObjectCreate: "
83 "failed to allocate memory for event list");
84 return PVRSRV_ERROR_OUT_OF_MEMORY;
87 INIT_LIST_HEAD(&psEvenObjectList->sList);
89 rwlock_init(&psEvenObjectList->sLock);
91 *phEventObjectList = (void **) psEvenObjectList;
96 enum PVRSRV_ERROR LinuxEventObjectListDestroy(void *hEventObjectList)
98 struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psEvenObjectList =
99 (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hEventObjectList;
101 if (psEvenObjectList) {
102 if (!list_empty(&psEvenObjectList->sList)) {
103 PVR_DPF(PVR_DBG_ERROR,
104 "LinuxEventObjectListDestroy: Event List is not empty");
105 return PVRSRV_ERROR_GENERIC;
107 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
108 sizeof(struct PVRSRV_LINUX_EVENT_OBJECT_LIST),
109 psEvenObjectList, NULL);
114 enum PVRSRV_ERROR LinuxEventObjectDelete(void *hOSEventObjectList,
115 void *hOSEventObject)
117 if (hOSEventObjectList)
118 if (hOSEventObject) {
119 struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject =
120 (struct PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject;
121 #if defined(CONFIG_PVR_DEBUG_EXTRA)
122 PVR_DPF(PVR_DBG_MESSAGE,
123 "LinuxEventObjectListDelete: Event object waits: %lu",
124 psLinuxEventObject->ui32Stats);
126 ResManFreeResByPtr(psLinuxEventObject->hResItem);
130 return PVRSRV_ERROR_GENERIC;
134 static enum PVRSRV_ERROR LinuxEventObjectDeleteCallback(void *pvParam,
137 struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject = pvParam;
138 struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList =
139 psLinuxEventObject->psLinuxEventObjectList;
141 PVR_UNREFERENCED_PARAMETER(ui32Param);
143 write_lock_bh(&psLinuxEventObjectList->sLock);
144 list_del(&psLinuxEventObject->sList);
145 write_unlock_bh(&psLinuxEventObjectList->sLock);
147 #if defined(CONFIG_PVR_DEBUG_EXTRA)
148 PVR_DPF(PVR_DBG_MESSAGE,
149 "LinuxEventObjectDeleteCallback: Event object waits: %lu",
150 psLinuxEventObject->ui32Stats);
153 OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
154 sizeof(struct PVRSRV_LINUX_EVENT_OBJECT), psLinuxEventObject,
160 enum PVRSRV_ERROR LinuxEventObjectAdd(void *hOSEventObjectList,
161 void **phOSEventObject)
163 struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
164 struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList =
165 (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hOSEventObjectList;
166 u32 ui32PID = OSGetCurrentProcessIDKM();
167 struct PVRSRV_PER_PROCESS_DATA *psPerProc;
169 psPerProc = PVRSRVPerProcessData(ui32PID);
170 if (psPerProc == NULL) {
171 PVR_DPF(PVR_DBG_ERROR,
172 "LinuxEventObjectAdd: Couldn't find per-process data");
173 return PVRSRV_ERROR_OUT_OF_MEMORY;
176 if (OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
177 sizeof(struct PVRSRV_LINUX_EVENT_OBJECT),
178 (void **) &psLinuxEventObject, NULL) != PVRSRV_OK) {
179 PVR_DPF(PVR_DBG_ERROR,
180 "LinuxEventObjectAdd: failed to allocate memory ");
181 return PVRSRV_ERROR_OUT_OF_MEMORY;
184 INIT_LIST_HEAD(&psLinuxEventObject->sList);
186 atomic_set(&psLinuxEventObject->sTimeStamp, 0);
187 psLinuxEventObject->ui32TimeStampPrevious = 0;
189 #if defined(CONFIG_PVR_DEBUG_EXTRA)
190 psLinuxEventObject->ui32Stats = 0;
192 init_waitqueue_head(&psLinuxEventObject->sWait);
194 psLinuxEventObject->psLinuxEventObjectList = psLinuxEventObjectList;
196 psLinuxEventObject->hResItem =
197 ResManRegisterRes(psPerProc->hResManContext,
198 RESMAN_TYPE_EVENT_OBJECT, psLinuxEventObject, 0,
199 &LinuxEventObjectDeleteCallback);
201 write_lock_bh(&psLinuxEventObjectList->sLock);
202 list_add(&psLinuxEventObject->sList, &psLinuxEventObjectList->sList);
203 write_unlock_bh(&psLinuxEventObjectList->sLock);
205 *phOSEventObject = psLinuxEventObject;
210 enum PVRSRV_ERROR LinuxEventObjectSignal(void *hOSEventObjectList)
212 struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject;
213 struct PVRSRV_LINUX_EVENT_OBJECT_LIST *psLinuxEventObjectList =
214 (struct PVRSRV_LINUX_EVENT_OBJECT_LIST *)hOSEventObjectList;
215 struct list_head *psListEntry, *psListEntryTemp, *psList;
216 psList = &psLinuxEventObjectList->sList;
218 list_for_each_safe(psListEntry, psListEntryTemp, psList) {
221 (struct PVRSRV_LINUX_EVENT_OBJECT *)list_entry(psListEntry,
222 struct PVRSRV_LINUX_EVENT_OBJECT,
225 atomic_inc(&psLinuxEventObject->sTimeStamp);
226 wake_up_interruptible(&psLinuxEventObject->sWait);
233 enum PVRSRV_ERROR LinuxEventObjectWait(void *hOSEventObject, u32 ui32MSTimeout)
238 struct PVRSRV_LINUX_EVENT_OBJECT *psLinuxEventObject =
239 (struct PVRSRV_LINUX_EVENT_OBJECT *)hOSEventObject;
241 u32 ui32TimeOutJiffies = msecs_to_jiffies(ui32MSTimeout);
244 prepare_to_wait(&psLinuxEventObject->sWait, &sWait,
246 ui32TimeStamp = atomic_read(&psLinuxEventObject->sTimeStamp);
248 if (psLinuxEventObject->ui32TimeStampPrevious != ui32TimeStamp)
254 (u32) schedule_timeout((s32) ui32TimeOutJiffies);
258 if (pvr_is_disabled()) {
259 ui32TimeOutJiffies = 1;
262 #if defined(CONFIG_PVR_DEBUG_EXTRA)
263 psLinuxEventObject->ui32Stats++;
266 } while (ui32TimeOutJiffies);
268 finish_wait(&psLinuxEventObject->sWait, &sWait);
270 psLinuxEventObject->ui32TimeStampPrevious = ui32TimeStamp;
272 return ui32TimeOutJiffies ? PVRSRV_OK : PVRSRV_ERROR_TIMEOUT;