gpu: pvr: support for events
[sgx.git] / pvr / module.c
1 /**********************************************************************
2  *
3  * Copyright(c) 2008 Imagination Technologies Ltd. All rights reserved.
4  *
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.
8  *
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.
13  *
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.
17  *
18  * The full GNU General Public License is included in this distribution in
19  * the file called "COPYING".
20  *
21  * Contact Information:
22  * Imagination Technologies Ltd. <gpl-support@imgtec.com>
23  * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
24  *
25  ******************************************************************************/
26
27 #include <linux/init.h>
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/version.h>
31 #include <linux/fs.h>
32 #include <linux/proc_fs.h>
33 #include <linux/miscdevice.h>
34
35 #include <linux/platform_device.h>
36
37 #include "img_defs.h"
38 #include "services.h"
39 #include "kerneldisplay.h"
40 #include "kernelbuffer.h"
41 #include "syscommon.h"
42 #include "pvrmmap.h"
43 #include "mutils.h"
44 #include "mm.h"
45 #include "mmap.h"
46 #include "pvr_debug.h"
47 #include "srvkm.h"
48 #include "perproc.h"
49 #include "handle.h"
50 #include "pvr_bridge_km.h"
51 #include "sgx_bridge_km.h"
52 #include "proc.h"
53 #include "pvrmodule.h"
54 #include "private_data.h"
55
56 #define DRVNAME         "pvrsrvkm"
57
58 #ifdef CONFIG_PVR_DEBUG_EXTRA
59 static int debug = DBGPRIV_WARNING;
60 #include <linux/moduleparam.h>
61 module_param(debug, int, 0);
62 #endif
63
64 static int pvr_open(struct inode unref__ * inode, struct file *filp)
65 {
66         struct PVRSRV_FILE_PRIVATE_DATA *priv;
67         void *block_alloc;
68         int ret = -ENOMEM;
69         enum PVRSRV_ERROR err;
70         u32 pid;
71
72         pvr_lock();
73
74         pid = OSGetCurrentProcessIDKM();
75
76         if (PVRSRVProcessConnect(pid) != PVRSRV_OK)
77                 goto err_unlock;
78
79         err = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
80                             sizeof(*priv),
81                             (void **)&priv, &block_alloc);
82
83         if (err != PVRSRV_OK)
84                 goto err_unlock;
85
86         priv->ui32OpenPID = pid;
87         priv->hBlockAlloc = block_alloc;
88         filp->private_data = priv;
89
90         INIT_LIST_HEAD(&priv->event_list);
91         init_waitqueue_head(&priv->event_wait);
92         priv->event_space = 4096; /* set aside 4k for event buffer */
93
94         ret = 0;
95 err_unlock:
96         pvr_unlock();
97
98         return ret;
99 }
100
101 static int pvr_release(struct inode unref__ * inode, struct file *filp)
102 {
103         struct PVRSRV_FILE_PRIVATE_DATA *priv;
104
105         pvr_lock();
106
107         priv = filp->private_data;
108
109         PVRSRVProcessDisconnect(priv->ui32OpenPID);
110
111         OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
112                   sizeof(*priv),
113                   priv, priv->hBlockAlloc);
114
115         pvr_unlock();
116
117         return 0;
118 }
119
120 static const struct file_operations pvr_fops = {
121         .owner          = THIS_MODULE,
122         .unlocked_ioctl = PVRSRV_BridgeDispatchKM,
123         .open           = pvr_open,
124         .release        = pvr_release,
125         .mmap           = PVRMMap,
126 };
127
128 static void pvr_shutdown(struct platform_device *pdev)
129 {
130         PVR_TRACE("pvr_shutdown(pdev=%p)", pdev);
131
132         (void)PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3);
133 }
134
135 static int pvr_suspend(struct platform_device *pdev, pm_message_t state)
136 {
137         PVR_TRACE("pvr_suspend(pdev=%p)", pdev);
138
139         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3) != PVRSRV_OK)
140                 return -EINVAL;
141         return 0;
142 }
143
144 static int pvr_resume(struct platform_device *pdev)
145 {
146         PVR_TRACE("pvr_resume(pdev=%p)", pdev);
147
148         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) != PVRSRV_OK)
149                 return -EINVAL;
150         return 0;
151 }
152
153 static struct miscdevice pvr_miscdevice = {
154         .minor = MISC_DYNAMIC_MINOR,
155         .name = DRVNAME,
156         .fops = &pvr_fops,
157 };
158
159 static int __devinit pvr_probe(struct platform_device *pdev)
160 {
161         struct SYS_DATA *sysdata;
162         int ret;
163
164         PVR_TRACE("pvr_probe(pdev=%p)", pdev);
165
166         if (SysAcquireData(&sysdata) != PVRSRV_OK &&
167             SysInitialise(pdev) != PVRSRV_OK) {
168                 ret = -ENODEV;
169                 goto err_exit;
170         }
171
172         ret = misc_register(&pvr_miscdevice);
173         if (ret < 0)
174                 goto err_exit;
175
176         return 0;
177
178 err_exit:
179         dev_err(&pdev->dev, "probe failed (%d)\n", ret);
180
181         return ret;
182 }
183
184 static int __devexit pvr_remove(struct platform_device *pdev)
185 {
186         struct SYS_DATA *sysdata;
187         int ret;
188
189         PVR_TRACE("pvr_remove(pdev=%p)", pdev);
190
191         ret = misc_deregister(&pvr_miscdevice);
192         if (ret < 0) {
193                 dev_err(&pdev->dev, "remove failed (%d)\n", ret);
194                 return ret;
195         }
196
197         if (SysAcquireData(&sysdata) == PVRSRV_OK)
198                 SysDeinitialise(sysdata);
199
200         return 0;
201 }
202
203
204 static struct platform_driver pvr_driver = {
205         .driver = {
206                    .name = DRVNAME,
207         },
208         .probe          = pvr_probe,
209         .remove         = __devexit_p(pvr_remove),
210         .suspend        = pvr_suspend,
211         .resume         = pvr_resume,
212         .shutdown       = pvr_shutdown,
213 };
214
215 static int __init pvr_init(void)
216 {
217         int error;
218
219         pvr_dbg_init();
220
221         PVR_TRACE("pvr_init");
222
223         pvr_init_lock();
224
225 #ifdef CONFIG_PVR_DEBUG_EXTRA
226         PVRDebugSetLevel(debug);
227 #endif
228
229         error = CreateProcEntries();
230         if (error < 0)
231                 goto err1;
232
233         error = -ENOMEM;
234         if (LinuxMMInit() != PVRSRV_OK)
235                 goto err2;
236
237         if (LinuxBridgeInit() != PVRSRV_OK)
238                 goto err3;
239
240         PVRMMapInit();
241
242         error = platform_driver_register(&pvr_driver);
243         if (error < 0)
244                 goto err4;
245
246         return 0;
247
248 err4:
249         PVRMMapCleanup();
250         LinuxBridgeDeInit();
251 err3:
252         LinuxMMCleanup();
253 err2:
254         RemoveProcEntries();
255 err1:
256         pr_err("%s: failed (%d)\n", __func__, error);
257
258         return error;
259 }
260
261 static void __exit pvr_cleanup(void)
262 {
263         struct SYS_DATA *sysdata;
264
265         PVR_TRACE("pvr_cleanup");
266
267         SysAcquireData(&sysdata);
268
269         platform_driver_unregister(&pvr_driver);
270
271         PVRMMapCleanup();
272         LinuxMMCleanup();
273         LinuxBridgeDeInit();
274         RemoveProcEntries();
275
276         PVR_TRACE("pvr_cleanup: unloading");
277
278         pvr_dbg_cleanup();
279 }
280
281 module_init(pvr_init);
282 module_exit(pvr_cleanup);
283
284 MODULE_SUPPORTED_DEVICE(DRVNAME);
285 MODULE_ALIAS("platform:" DRVNAME);
286