fixes for bc_cat
[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 #include "pvr_events.h"
56
57 #ifdef CONFIG_DEBUG_FS
58 #include "pvr_debugfs.h"
59 #endif
60
61 #define DRVNAME         "pvrsrvkm"
62
63 #ifdef CONFIG_PVR_DEBUG_EXTRA
64 static int debug = DBGPRIV_WARNING;
65 #include <linux/moduleparam.h>
66 module_param(debug, int, 0);
67 #endif
68
69 static int pvr_open(struct inode unref__ * inode, struct file *filp)
70 {
71         struct PVRSRV_FILE_PRIVATE_DATA *priv;
72         void *block_alloc;
73         int ret = -ENOMEM;
74         enum PVRSRV_ERROR err;
75         u32 pid;
76
77         pvr_lock();
78
79         if (pvr_is_disabled()) {
80                 ret = -ENODEV;
81                 goto err_unlock;
82         }
83
84         pid = OSGetCurrentProcessIDKM();
85
86         if (PVRSRVProcessConnect(pid) != PVRSRV_OK)
87                 goto err_unlock;
88
89         err = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
90                             sizeof(*priv),
91                             (void **)&priv, &block_alloc);
92
93         if (err != PVRSRV_OK)
94                 goto err_unlock;
95
96         priv->ui32OpenPID = pid;
97         priv->hBlockAlloc = block_alloc;
98         priv->proc = PVRSRVPerProcessData(pid);
99         filp->private_data = priv;
100
101         INIT_LIST_HEAD(&priv->event_list);
102         init_waitqueue_head(&priv->event_wait);
103         priv->event_space = 4096; /* set aside 4k for event buffer */
104
105         ret = 0;
106 err_unlock:
107         pvr_unlock();
108
109         return ret;
110 }
111
112 static int pvr_release(struct inode unref__ * inode, struct file *filp)
113 {
114         struct PVRSRV_FILE_PRIVATE_DATA *priv;
115
116         pvr_lock();
117
118         priv = filp->private_data;
119
120         pvr_release_events(priv);
121
122         PVRSRVProcessDisconnect(priv->ui32OpenPID);
123
124         OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
125                   sizeof(*priv),
126                   priv, priv->hBlockAlloc);
127
128         pvr_unlock();
129
130         return 0;
131 }
132
133 static const struct file_operations pvr_fops = {
134         .owner          = THIS_MODULE,
135         .unlocked_ioctl = PVRSRV_BridgeDispatchKM,
136         .open           = pvr_open,
137         .release        = pvr_release,
138         .mmap           = PVRMMap,
139         .poll           = pvr_poll,
140         .read           = pvr_read,
141 };
142
143 static void pvr_shutdown(struct platform_device *pdev)
144 {
145         PVR_TRACE("pvr_shutdown(pdev=%p)", pdev);
146
147         (void)PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3);
148 }
149
150 static int pvr_suspend(struct platform_device *pdev, pm_message_t state)
151 {
152         PVR_TRACE("pvr_suspend(pdev=%p)", pdev);
153
154         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3) != PVRSRV_OK)
155                 return -EINVAL;
156         return 0;
157 }
158
159 static int pvr_resume(struct platform_device *pdev)
160 {
161         PVR_TRACE("pvr_resume(pdev=%p)", pdev);
162
163         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) != PVRSRV_OK)
164                 return -EINVAL;
165         return 0;
166 }
167
168 static struct miscdevice pvr_miscdevice = {
169         .minor = MISC_DYNAMIC_MINOR,
170         .name = DRVNAME,
171         .fops = &pvr_fops,
172 };
173
174 static int __devinit pvr_probe(struct platform_device *pdev)
175 {
176         struct SYS_DATA *sysdata;
177         int ret;
178
179         PVR_TRACE("pvr_probe(pdev=%p)", pdev);
180
181         if (SysAcquireData(&sysdata) != PVRSRV_OK &&
182             SysInitialise(pdev) != PVRSRV_OK) {
183                 ret = -ENODEV;
184                 goto err_exit;
185         }
186
187         ret = misc_register(&pvr_miscdevice);
188         if (ret < 0)
189                 goto err_exit;
190
191         return 0;
192
193 err_exit:
194         dev_err(&pdev->dev, "probe failed (%d)\n", ret);
195
196         return ret;
197 }
198
199 static int __devexit pvr_remove(struct platform_device *pdev)
200 {
201         struct SYS_DATA *sysdata;
202         int ret;
203
204         PVR_TRACE("pvr_remove(pdev=%p)", pdev);
205
206         ret = misc_deregister(&pvr_miscdevice);
207         if (ret < 0) {
208                 dev_err(&pdev->dev, "remove failed (%d)\n", ret);
209                 return ret;
210         }
211
212         if (SysAcquireData(&sysdata) == PVRSRV_OK)
213                 SysDeinitialise(sysdata);
214
215         return 0;
216 }
217
218
219 static struct platform_driver pvr_driver = {
220         .driver = {
221                    .name = DRVNAME,
222         },
223         .probe          = pvr_probe,
224         .remove         = __devexit_p(pvr_remove),
225         .suspend        = pvr_suspend,
226         .resume         = pvr_resume,
227         .shutdown       = pvr_shutdown,
228 };
229
230 static void pvr_dummy_release(struct device *dev)
231 {
232 }
233
234 static struct sgx_platform_data pvr_pdata;
235
236 static struct platform_device pvr_device = {
237         .name           = DRVNAME,
238         .id             = -1,
239         .dev            = {
240                 .platform_data  = &pvr_pdata,
241                 .release        = pvr_dummy_release,
242         }
243 };
244
245 static int __init pvr_init(void)
246 {
247         int error;
248
249         pvr_dbg_init();
250
251         PVR_TRACE("pvr_init");
252
253 #ifdef CONFIG_PVR_DEBUG_EXTRA
254         PVRDebugSetLevel(debug);
255 #endif
256
257 #ifdef CONFIG_DEBUG_FS
258         pvr_debugfs_init();
259 #endif
260
261         error = CreateProcEntries();
262         if (error < 0)
263                 goto err1;
264
265         error = -ENOMEM;
266         if (LinuxMMInit() != PVRSRV_OK)
267                 goto err2;
268
269         if (LinuxBridgeInit() != PVRSRV_OK)
270                 goto err3;
271
272         PVRMMapInit();
273
274         error = platform_driver_register(&pvr_driver);
275         if (error < 0)
276                 goto err4;
277
278         pvr_pdata.fclock_max = 200000000;
279         error = platform_device_register(&pvr_device);
280         if (error < 0)
281                 goto err5;
282
283         pvr_init_events();
284
285         return 0;
286
287 err5:
288         platform_driver_unregister(&pvr_driver);
289 err4:
290         PVRMMapCleanup();
291         LinuxBridgeDeInit();
292 err3:
293         LinuxMMCleanup();
294 err2:
295         RemoveProcEntries();
296 err1:
297         pr_err("%s: failed (%d)\n", __func__, error);
298
299         return error;
300 }
301
302 static void __exit pvr_cleanup(void)
303 {
304         PVR_TRACE("pvr_cleanup");
305
306         pvr_exit_events();
307
308         platform_driver_unregister(&pvr_driver);
309         platform_device_unregister(&pvr_device);
310
311         PVRMMapCleanup();
312         LinuxMMCleanup();
313         LinuxBridgeDeInit();
314         RemoveProcEntries();
315
316         PVR_TRACE("pvr_cleanup: unloading");
317
318 #ifdef CONFIG_DEBUG_FS
319         pvr_debugfs_cleanup();
320 #endif
321         pvr_dbg_cleanup();
322 }
323
324 module_init(pvr_init);
325 module_exit(pvr_cleanup);
326
327 MODULE_SUPPORTED_DEVICE(DRVNAME);
328 MODULE_ALIAS("platform:" DRVNAME);
329