1.3.13.1607/3_00_00_08+flat+Lindent
[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 #ifndef AUTOCONF_INCLUDED
28 #include <linux/config.h>
29 #endif
30
31 #include <linux/init.h>
32 #include <linux/kernel.h>
33 #include <linux/module.h>
34 #include <linux/version.h>
35 #include <linux/fs.h>
36 #include <linux/proc_fs.h>
37
38 #if defined(LDM_PLATFORM)
39 #include <linux/platform_device.h>
40 #endif
41
42 #if defined(LDM_PCI)
43 #include <linux/pci.h>
44 #endif
45
46 #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
47 #include <asm/uaccess.h>
48 #endif
49
50 #include "img_defs.h"
51 #include "services.h"
52 #include "kerneldisplay.h"
53 #include "kernelbuffer.h"
54 #include "syscommon.h"
55 #include "pvrmmap.h"
56 #include "mm.h"
57 #include "mmap.h"
58 #include "mutex.h"
59 #include "pvr_debug.h"
60 #include "srvkm.h"
61 #include "perproc.h"
62 #include "handle.h"
63 #include "pvr_bridge_km.h"
64 #include "proc.h"
65 #include "pvrmodule.h"
66
67 #define DRVNAME         "pvrsrvkm"
68 #define DEVNAME         "pvrsrvkm"
69
70 MODULE_SUPPORTED_DEVICE(DEVNAME);
71 #ifdef DEBUG
72 static int debug = DBGPRIV_WARNING;
73 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
74 #include <linux/moduleparam.h>
75 module_param(debug, int, 0);
76 #else
77 MODULE_PARM(debug, "i");
78 MODULE_PARM_DESC(debug, "Sets the level of debug output (default=0x4)");
79 #endif
80 #endif
81
82 void PVRDebugSetLevel(IMG_UINT32 uDebugLevel);
83
84 extern IMG_BOOL PVRGetDisplayClassJTable(PVRSRV_DC_DISP2SRV_KMJTABLE *
85                                          psJTable);
86 extern IMG_BOOL PVRGetBufferClassJTable(PVRSRV_BC_BUFFER2SRV_KMJTABLE *
87                                         psJTable);
88 EXPORT_SYMBOL(PVRGetDisplayClassJTable);
89 EXPORT_SYMBOL(PVRGetBufferClassJTable);
90
91 static int AssignedMajorNumber;
92
93 extern int PVRSRV_BridgeDispatchKM(struct inode *inode, struct file *file,
94                                    unsigned int cmd, unsigned long arg);
95 static int PVRSRVOpen(struct inode *pInode, struct file *pFile);
96 static int PVRSRVRelease(struct inode *pInode, struct file *pFile);
97
98 PVRSRV_LINUX_MUTEX gPVRSRVLock;
99
100 static struct file_operations pvrsrv_fops = {
101 owner:  THIS_MODULE,
102 ioctl:  PVRSRV_BridgeDispatchKM,
103 open:   PVRSRVOpen,
104 release:PVRSRVRelease,
105 mmap:   PVRMMap,
106 };
107
108 #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
109 static IMG_UINT32 gPVRPowerLevel;
110 #endif
111
112 #if defined(LDM_PLATFORM) || defined(LDM_PCI)
113
114 #if defined(LDM_PLATFORM)
115 #define LDM_DEV struct platform_device
116 #define LDM_DRV struct platform_driver
117 #if defined(LDM_PCI)
118 #undef  LDM_PCI
119 #endif
120 #endif
121
122 #if defined(LDM_PCI)
123 #define LDM_DEV struct pci_dev
124 #define LDM_DRV struct pci_driver
125 #endif
126
127 #if defined(LDM_PLATFORM)
128 static int PVRSRVDriverRemove(LDM_DEV * device);
129 static int PVRSRVDriverProbe(LDM_DEV * device);
130 #endif
131 #if defined(LDM_PCI)
132 static void PVRSRVDriverRemove(LDM_DEV * device);
133 static int PVRSRVDriverProbe(LDM_DEV * device, const struct pci_device_id *id);
134 #endif
135 static int PVRSRVDriverSuspend(LDM_DEV * device, pm_message_t state);
136 static void PVRSRVDriverShutdown(LDM_DEV * device);
137 static int PVRSRVDriverResume(LDM_DEV * device);
138
139 #if defined(LDM_PCI)
140 struct pci_device_id powervr_id_table[] __devinitdata = {
141         {PCI_DEVICE(SYS_SGX_DEV_VENDOR_ID, SYS_SGX_DEV_DEVICE_ID)},
142         {0}
143 };
144
145 MODULE_DEVICE_TABLE(pci, powervr_id_table);
146 #endif
147
148 static LDM_DRV powervr_driver = {
149 #if defined(LDM_PLATFORM)
150         .driver = {
151                    .name = DRVNAME,
152                    },
153 #endif
154 #if defined(LDM_PCI)
155         .name = DRVNAME,
156         .id_table = powervr_id_table,
157 #endif
158         .probe = PVRSRVDriverProbe,
159 #if defined(LDM_PLATFORM)
160         .remove = PVRSRVDriverRemove,
161 #endif
162 #if defined(LDM_PCI)
163         .remove = __devexit_p(PVRSRVDriverRemove),
164 #endif
165         .suspend = PVRSRVDriverSuspend,
166         .resume = PVRSRVDriverResume,
167         .shutdown = PVRSRVDriverShutdown,
168 };
169
170 LDM_DEV *gpsPVRLDMDev;
171
172 #if defined(LDM_PLATFORM)
173 static void PVRSRVDeviceRelease(struct device *device);
174
175 static struct platform_device powervr_device = {
176         .name = DEVNAME,
177         .id = -1,
178         .dev = {
179                 .release = PVRSRVDeviceRelease}
180 };
181 #endif
182
183 #if defined(LDM_PLATFORM)
184 static int PVRSRVDriverProbe(LDM_DEV * pDevice)
185 #endif
186 #if defined(LDM_PCI)
187 static int __devinit PVRSRVDriverProbe(LDM_DEV * pDevice,
188                                        const struct pci_device_id *id)
189 #endif
190 {
191         SYS_DATA *psSysData;
192
193         PVR_TRACE(("PVRSRVDriverProbe(pDevice=%p)", pDevice));
194
195 #if 0
196
197         if (PerDeviceSysInitialise((IMG_PVOID) pDevice) != PVRSRV_OK) {
198                 return -EINVAL;
199         }
200 #endif
201
202         if (SysAcquireData(&psSysData) != PVRSRV_OK) {
203                 gpsPVRLDMDev = pDevice;
204
205                 if (SysInitialise() != PVRSRV_OK) {
206                         return -ENODEV;
207                 }
208         }
209
210         return 0;
211 }
212
213 #if defined (LDM_PLATFORM)
214 static int PVRSRVDriverRemove(LDM_DEV * pDevice)
215 #endif
216 #if defined(LDM_PCI)
217 static void __devexit PVRSRVDriverRemove(LDM_DEV * pDevice)
218 #endif
219 {
220         SYS_DATA *psSysData;
221
222         PVR_TRACE(("PVRSRVDriverRemove(pDevice=%p)", pDevice));
223
224         if (SysAcquireData(&psSysData) == PVRSRV_OK) {
225 #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
226                 if (gPVRPowerLevel != 0) {
227                         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) ==
228                             PVRSRV_OK) {
229                                 gPVRPowerLevel = 0;
230                         }
231                 }
232 #endif
233                 SysDeinitialise(psSysData);
234
235                 gpsPVRLDMDev = IMG_NULL;
236         }
237 #if 0
238         if (PerDeviceSysDeInitialise((IMG_PVOID) pDevice) != PVRSRV_OK) {
239                 return -EINVAL;
240         }
241 #endif
242
243 #if defined (LDM_PLATFORM)
244         return 0;
245 #endif
246 #if defined (LDM_PCI)
247         return;
248 #endif
249 }
250
251 static void PVRSRVDriverShutdown(LDM_DEV * pDevice)
252 {
253         PVR_TRACE(("PVRSRVDriverShutdown(pDevice=%p)", pDevice));
254
255         (void)PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3);
256 }
257
258 static int PVRSRVDriverSuspend(LDM_DEV * pDevice, pm_message_t state)
259 {
260 #if !(defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL))
261         PVR_TRACE(("PVRSRVDriverSuspend(pDevice=%p)", pDevice));
262
263         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3) != PVRSRV_OK) {
264                 return -EINVAL;
265         }
266 #endif
267         return 0;
268 }
269
270 static int PVRSRVDriverResume(LDM_DEV * pDevice)
271 {
272 #if !(defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL))
273         PVR_TRACE(("PVRSRVDriverResume(pDevice=%p)", pDevice));
274
275         if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) != PVRSRV_OK) {
276                 return -EINVAL;
277         }
278 #endif
279         return 0;
280 }
281
282 #if defined(LDM_PLATFORM)
283 static void PVRSRVDeviceRelease(struct device *pDevice)
284 {
285         PVR_DPF((PVR_DBG_WARNING, "PVRSRVDeviceRelease(pDevice=%p)", pDevice));
286 }
287 #endif
288 #endif
289
290 #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
291 int PVRProcSetPowerLevel(struct file *file, const char *buffer,
292                          unsigned long count, void *data)
293 {
294         char data_buffer[2];
295         IMG_UINT32 PVRPowerLevel;
296
297         if (count != sizeof(data_buffer)) {
298                 return -EINVAL;
299         } else {
300                 if (copy_from_user(data_buffer, buffer, count))
301                         return -EINVAL;
302                 if (data_buffer[count - 1] != '\n')
303                         return -EINVAL;
304                 PVRPowerLevel = data_buffer[0] - '0';
305                 if (PVRPowerLevel != gPVRPowerLevel) {
306                         if (PVRPowerLevel != 0) {
307                                 if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3)
308                                     != PVRSRV_OK) {
309                                         return -EINVAL;
310                                 }
311                         } else {
312                                 if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0)
313                                     != PVRSRV_OK) {
314                                         return -EINVAL;
315                                 }
316                         }
317
318                         gPVRPowerLevel = PVRPowerLevel;
319                 }
320         }
321         return (count);
322 }
323
324 int PVRProcGetPowerLevel(char *page, char **start, off_t off, int count,
325                          int *eof, void *data)
326 {
327         if (off == 0) {
328                 *start = (char *)1;
329                 return printAppend(page, count, 0, "%lu\n", gPVRPowerLevel);
330         }
331         *eof = 1;
332         return 0;
333 }
334 #endif
335
336 static int PVRSRVOpen(struct inode unref__ * pInode,
337                       struct file unref__ * pFile)
338 {
339         int Ret = 0;
340
341         LinuxLockMutex(&gPVRSRVLock);
342
343         if (PVRSRVProcessConnect(OSGetCurrentProcessIDKM()) != PVRSRV_OK) {
344                 Ret = -ENOMEM;
345         }
346
347         LinuxUnLockMutex(&gPVRSRVLock);
348
349         return Ret;
350 }
351
352 static int PVRSRVRelease(struct inode unref__ * pInode,
353                          struct file unref__ * pFile)
354 {
355         int Ret = 0;
356
357         LinuxLockMutex(&gPVRSRVLock);
358
359         PVRSRVProcessDisconnect(OSGetCurrentProcessIDKM());
360
361         LinuxUnLockMutex(&gPVRSRVLock);
362
363         return Ret;
364 }
365
366 static int __init PVRCore_Init(void)
367 {
368         int error;
369 #if !(defined(LDM_PLATFORM) || defined(LDM_PCI))
370         PVRSRV_ERROR eError;
371 #endif
372
373         PVR_TRACE(("PVRCore_Init"));
374
375         AssignedMajorNumber = register_chrdev(0, DEVNAME, &pvrsrv_fops);
376
377         if (AssignedMajorNumber <= 0) {
378                 PVR_DPF((PVR_DBG_ERROR,
379                          "PVRCore_Init: unable to get major number"));
380
381                 return -EBUSY;
382         }
383
384         PVR_TRACE(("PVRCore_Init: major device %d", AssignedMajorNumber));
385
386         if (CreateProcEntries()) {
387                 unregister_chrdev(AssignedMajorNumber, DRVNAME);
388
389                 return -ENOMEM;
390         }
391
392         LinuxInitMutex(&gPVRSRVLock);
393
394 #ifdef DEBUG
395         PVRDebugSetLevel(debug);
396 #endif
397
398         if (LinuxMMInit() != PVRSRV_OK) {
399                 error = -ENOMEM;
400                 goto init_failed;
401         }
402
403         LinuxBridgeInit();
404
405         PVRMMapInit();
406
407 #if defined(LDM_PLATFORM) || defined(LDM_PCI)
408
409 #if defined(LDM_PLATFORM)
410         if ((error = platform_driver_register(&powervr_driver)) != 0) {
411                 PVR_DPF((PVR_DBG_ERROR,
412                          "PVRCore_Init: unable to register platform driver (%d)",
413                          error));
414
415                 goto init_failed;
416         }
417
418         if ((error = platform_device_register(&powervr_device)) != 0) {
419                 platform_driver_unregister(&powervr_driver);
420
421                 PVR_DPF((PVR_DBG_ERROR,
422                          "PVRCore_Init: unable to register platform device (%d)",
423                          error));
424
425                 goto init_failed;
426         }
427 #endif
428
429 #if defined(LDM_PCI)
430         if ((error = pci_register_driver(&powervr_driver)) != 0) {
431                 PVR_DPF((PVR_DBG_ERROR,
432                          "PVRCore_Init: unable to register PCI driver (%d)",
433                          error));
434
435                 goto init_failed;
436         }
437 #endif
438
439 #else
440
441         if ((eError = SysInitialise()) != PVRSRV_OK) {
442                 error = -ENODEV;
443 #if defined(TCF_REV) && (TCF_REV == 110)
444                 if (eError == PVRSRV_ERROR_NOT_SUPPORTED) {
445                         printk("\nAtlas wrapper (FPGA image) version mismatch");
446                         error = -ENODEV;
447                 }
448 #endif
449                 goto init_failed;
450         }
451 #endif
452
453         return 0;
454
455 init_failed:
456
457         PVRMMapCleanup();
458         LinuxMMCleanup();
459         RemoveProcEntries();
460         unregister_chrdev(AssignedMajorNumber, DRVNAME);
461
462         return error;
463
464 }
465
466 static void __exit PVRCore_Cleanup(void)
467 {
468         SYS_DATA *psSysData;
469
470         PVR_TRACE(("PVRCore_Cleanup"));
471
472         SysAcquireData(&psSysData);
473
474 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22))
475         if (
476 #endif
477                    unregister_chrdev(AssignedMajorNumber, DRVNAME)
478 #if !(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22))
479                    ;
480 #else
481             ) {
482                 PVR_DPF((PVR_DBG_ERROR, " can't unregister device major %d",
483                          AssignedMajorNumber));
484         }
485 #endif
486
487 #if defined(LDM_PLATFORM) || defined(LDM_PCI)
488
489 #if defined(LDM_PCI)
490         pci_unregister_driver(&powervr_driver);
491 #endif
492
493 #if defined (LDM_PLATFORM)
494         platform_device_unregister(&powervr_device);
495         platform_driver_unregister(&powervr_driver);
496 #endif
497
498 #else
499 #if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
500         if (gPVRPowerLevel != 0) {
501                 if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) == PVRSRV_OK) {
502                         gPVRPowerLevel = 0;
503                 }
504         }
505 #endif
506
507         SysDeinitialise(psSysData);
508 #endif
509
510         PVRMMapCleanup();
511
512         LinuxMMCleanup();
513
514         LinuxBridgeDeInit();
515
516         RemoveProcEntries();
517
518         PVR_TRACE(("PVRCore_Cleanup: unloading"));
519 }
520
521 module_init(PVRCore_Init);
522 module_exit(PVRCore_Cleanup);