/**********************************************************************
*
* 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.
+ *
+ * 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
+ * Home Park Estate, Kings Langley, Herts, WD4 8LZ, UK
*
******************************************************************************/
-#ifndef AUTOCONF_INCLUDED
-#include <linux/config.h>
-#endif
-
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
-#if defined(LDM_PLATFORM)
#include <linux/platform_device.h>
-#endif
-
-#if defined(LDM_PCI)
-#include <linux/pci.h>
-#endif
-
-#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
-#include <asm/uaccess.h>
-#endif
#include "img_defs.h"
#include "services.h"
#include "kernelbuffer.h"
#include "syscommon.h"
#include "pvrmmap.h"
+#include "mutils.h"
#include "mm.h"
#include "mmap.h"
-#include "mutex.h"
#include "pvr_debug.h"
#include "srvkm.h"
#include "perproc.h"
#include "handle.h"
#include "pvr_bridge_km.h"
+#include "sgx_bridge_km.h"
#include "proc.h"
#include "pvrmodule.h"
+#include "private_data.h"
+#include "pvr_events.h"
+
+#ifdef CONFIG_DEBUG_FS
+#include "pvr_debugfs.h"
+#endif
#define DRVNAME "pvrsrvkm"
-#define DEVNAME "pvrsrvkm"
-MODULE_SUPPORTED_DEVICE(DEVNAME);
-#ifdef DEBUG
+#ifdef CONFIG_PVR_DEBUG_EXTRA
static int debug = DBGPRIV_WARNING;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
#include <linux/moduleparam.h>
module_param(debug, int, 0);
-#else
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Sets the level of debug output (default=0x4)");
-#endif
#endif
-void PVRDebugSetLevel(IMG_UINT32 uDebugLevel);
-
-extern IMG_BOOL PVRGetDisplayClassJTable(PVRSRV_DC_DISP2SRV_KMJTABLE *
- psJTable);
-extern IMG_BOOL PVRGetBufferClassJTable(PVRSRV_BC_BUFFER2SRV_KMJTABLE *
- psJTable);
-EXPORT_SYMBOL(PVRGetDisplayClassJTable);
-EXPORT_SYMBOL(PVRGetBufferClassJTable);
-
-static int AssignedMajorNumber;
-
-extern int PVRSRV_BridgeDispatchKM(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-static int PVRSRVOpen(struct inode *pInode, struct file *pFile);
-static int PVRSRVRelease(struct inode *pInode, struct file *pFile);
+static int pvr_open(struct inode unref__ * inode, struct file *filp)
+{
+ struct PVRSRV_FILE_PRIVATE_DATA *priv;
+ void *block_alloc;
+ int ret = -ENOMEM;
+ enum PVRSRV_ERROR err;
+ u32 pid;
-PVRSRV_LINUX_MUTEX gPVRSRVLock;
+ pvr_lock();
-static struct file_operations pvrsrv_fops = {
-owner: THIS_MODULE,
-ioctl: PVRSRV_BridgeDispatchKM,
-open: PVRSRVOpen,
-release:PVRSRVRelease,
-mmap: PVRMMap,
-};
+ if (pvr_is_disabled()) {
+ ret = -ENODEV;
+ goto err_unlock;
+ }
-#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
-static IMG_UINT32 gPVRPowerLevel;
-#endif
+ pid = OSGetCurrentProcessIDKM();
-#if defined(LDM_PLATFORM) || defined(LDM_PCI)
+ if (PVRSRVProcessConnect(pid) != PVRSRV_OK)
+ goto err_unlock;
-#if defined(LDM_PLATFORM)
-#define LDM_DEV struct platform_device
-#define LDM_DRV struct platform_driver
-#if defined(LDM_PCI)
-#undef LDM_PCI
-#endif
-#endif
+ err = OSAllocMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+ sizeof(*priv),
+ (void **)&priv, &block_alloc);
-#if defined(LDM_PCI)
-#define LDM_DEV struct pci_dev
-#define LDM_DRV struct pci_driver
-#endif
+ if (err != PVRSRV_OK)
+ goto err_unlock;
-#if defined(LDM_PLATFORM)
-static int PVRSRVDriverRemove(LDM_DEV * device);
-static int PVRSRVDriverProbe(LDM_DEV * device);
-#endif
-#if defined(LDM_PCI)
-static void PVRSRVDriverRemove(LDM_DEV * device);
-static int PVRSRVDriverProbe(LDM_DEV * device, const struct pci_device_id *id);
-#endif
-static int PVRSRVDriverSuspend(LDM_DEV * device, pm_message_t state);
-static void PVRSRVDriverShutdown(LDM_DEV * device);
-static int PVRSRVDriverResume(LDM_DEV * device);
-
-#if defined(LDM_PCI)
-struct pci_device_id powervr_id_table[] __devinitdata = {
- {PCI_DEVICE(SYS_SGX_DEV_VENDOR_ID, SYS_SGX_DEV_DEVICE_ID)},
- {0}
-};
+ priv->ui32OpenPID = pid;
+ priv->hBlockAlloc = block_alloc;
+ filp->private_data = priv;
-MODULE_DEVICE_TABLE(pci, powervr_id_table);
-#endif
+ INIT_LIST_HEAD(&priv->event_list);
+ init_waitqueue_head(&priv->event_wait);
+ priv->event_space = 4096; /* set aside 4k for event buffer */
-static LDM_DRV powervr_driver = {
-#if defined(LDM_PLATFORM)
- .driver = {
- .name = DRVNAME,
- },
-#endif
-#if defined(LDM_PCI)
- .name = DRVNAME,
- .id_table = powervr_id_table,
-#endif
- .probe = PVRSRVDriverProbe,
-#if defined(LDM_PLATFORM)
- .remove = PVRSRVDriverRemove,
-#endif
-#if defined(LDM_PCI)
- .remove = __devexit_p(PVRSRVDriverRemove),
-#endif
- .suspend = PVRSRVDriverSuspend,
- .resume = PVRSRVDriverResume,
- .shutdown = PVRSRVDriverShutdown,
-};
+ ret = 0;
+err_unlock:
+ pvr_unlock();
-LDM_DEV *gpsPVRLDMDev;
-
-#if defined(LDM_PLATFORM)
-static void PVRSRVDeviceRelease(struct device *device);
-
-static struct platform_device powervr_device = {
- .name = DEVNAME,
- .id = -1,
- .dev = {
- .release = PVRSRVDeviceRelease}
-};
-#endif
+ return ret;
+}
-#if defined(LDM_PLATFORM)
-static int PVRSRVDriverProbe(LDM_DEV * pDevice)
-#endif
-#if defined(LDM_PCI)
-static int __devinit PVRSRVDriverProbe(LDM_DEV * pDevice,
- const struct pci_device_id *id)
-#endif
+static int pvr_release(struct inode unref__ * inode, struct file *filp)
{
- SYS_DATA *psSysData;
+ struct PVRSRV_FILE_PRIVATE_DATA *priv;
- PVR_TRACE(("PVRSRVDriverProbe(pDevice=%p)", pDevice));
+ pvr_lock();
-#if 0
-
- if (PerDeviceSysInitialise((IMG_PVOID) pDevice) != PVRSRV_OK) {
- return -EINVAL;
- }
-#endif
+ priv = filp->private_data;
- if (SysAcquireData(&psSysData) != PVRSRV_OK) {
- gpsPVRLDMDev = pDevice;
+ pvr_release_events(priv);
- if (SysInitialise() != PVRSRV_OK) {
- return -ENODEV;
- }
- }
+ PVRSRVProcessDisconnect(priv->ui32OpenPID);
- return 0;
-}
+ OSFreeMem(PVRSRV_OS_NON_PAGEABLE_HEAP,
+ sizeof(*priv),
+ priv, priv->hBlockAlloc);
-#if defined (LDM_PLATFORM)
-static int PVRSRVDriverRemove(LDM_DEV * pDevice)
-#endif
-#if defined(LDM_PCI)
-static void __devexit PVRSRVDriverRemove(LDM_DEV * pDevice)
-#endif
-{
- SYS_DATA *psSysData;
-
- PVR_TRACE(("PVRSRVDriverRemove(pDevice=%p)", pDevice));
-
- if (SysAcquireData(&psSysData) == PVRSRV_OK) {
-#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
- if (gPVRPowerLevel != 0) {
- if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) ==
- PVRSRV_OK) {
- gPVRPowerLevel = 0;
- }
- }
-#endif
- SysDeinitialise(psSysData);
+ pvr_unlock();
- gpsPVRLDMDev = IMG_NULL;
- }
-#if 0
- if (PerDeviceSysDeInitialise((IMG_PVOID) pDevice) != PVRSRV_OK) {
- return -EINVAL;
- }
-#endif
-
-#if defined (LDM_PLATFORM)
return 0;
-#endif
-#if defined (LDM_PCI)
- return;
-#endif
}
-static void PVRSRVDriverShutdown(LDM_DEV * pDevice)
+static const struct file_operations pvr_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = PVRSRV_BridgeDispatchKM,
+ .open = pvr_open,
+ .release = pvr_release,
+ .mmap = PVRMMap,
+ .poll = pvr_poll,
+ .read = pvr_read,
+};
+
+static void pvr_shutdown(struct platform_device *pdev)
{
- PVR_TRACE(("PVRSRVDriverShutdown(pDevice=%p)", pDevice));
+ PVR_TRACE("pvr_shutdown(pdev=%p)", pdev);
(void)PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3);
}
-static int PVRSRVDriverSuspend(LDM_DEV * pDevice, pm_message_t state)
+static int pvr_suspend(struct platform_device *pdev, pm_message_t state)
{
-#if !(defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL))
- PVR_TRACE(("PVRSRVDriverSuspend(pDevice=%p)", pDevice));
+ PVR_TRACE("pvr_suspend(pdev=%p)", pdev);
- if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3) != PVRSRV_OK) {
+ if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3) != PVRSRV_OK)
return -EINVAL;
- }
-#endif
return 0;
}
-static int PVRSRVDriverResume(LDM_DEV * pDevice)
+static int pvr_resume(struct platform_device *pdev)
{
-#if !(defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL))
- PVR_TRACE(("PVRSRVDriverResume(pDevice=%p)", pDevice));
+ PVR_TRACE("pvr_resume(pdev=%p)", pdev);
- if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) != PVRSRV_OK) {
+ if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) != PVRSRV_OK)
return -EINVAL;
- }
-#endif
return 0;
}
-#if defined(LDM_PLATFORM)
-static void PVRSRVDeviceRelease(struct device *pDevice)
-{
- PVR_DPF((PVR_DBG_WARNING, "PVRSRVDeviceRelease(pDevice=%p)", pDevice));
-}
-#endif
-#endif
+static struct miscdevice pvr_miscdevice = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DRVNAME,
+ .fops = &pvr_fops,
+};
-#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
-int PVRProcSetPowerLevel(struct file *file, const char *buffer,
- unsigned long count, void *data)
+static int __devinit pvr_probe(struct platform_device *pdev)
{
- char data_buffer[2];
- IMG_UINT32 PVRPowerLevel;
+ struct SYS_DATA *sysdata;
+ int ret;
- if (count != sizeof(data_buffer)) {
- return -EINVAL;
- } else {
- if (copy_from_user(data_buffer, buffer, count))
- return -EINVAL;
- if (data_buffer[count - 1] != '\n')
- return -EINVAL;
- PVRPowerLevel = data_buffer[0] - '0';
- if (PVRPowerLevel != gPVRPowerLevel) {
- if (PVRPowerLevel != 0) {
- if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D3)
- != PVRSRV_OK) {
- return -EINVAL;
- }
- } else {
- if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0)
- != PVRSRV_OK) {
- return -EINVAL;
- }
- }
-
- gPVRPowerLevel = PVRPowerLevel;
- }
- }
- return (count);
-}
+ PVR_TRACE("pvr_probe(pdev=%p)", pdev);
-int PVRProcGetPowerLevel(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- if (off == 0) {
- *start = (char *)1;
- return printAppend(page, count, 0, "%lu\n", gPVRPowerLevel);
+ if (SysAcquireData(&sysdata) != PVRSRV_OK &&
+ SysInitialise(pdev) != PVRSRV_OK) {
+ ret = -ENODEV;
+ goto err_exit;
}
- *eof = 1;
- return 0;
-}
-#endif
-static int PVRSRVOpen(struct inode unref__ * pInode,
- struct file unref__ * pFile)
-{
- int Ret = 0;
-
- LinuxLockMutex(&gPVRSRVLock);
+ ret = misc_register(&pvr_miscdevice);
+ if (ret < 0)
+ goto err_exit;
- if (PVRSRVProcessConnect(OSGetCurrentProcessIDKM()) != PVRSRV_OK) {
- Ret = -ENOMEM;
- }
+ return 0;
- LinuxUnLockMutex(&gPVRSRVLock);
+err_exit:
+ dev_err(&pdev->dev, "probe failed (%d)\n", ret);
- return Ret;
+ return ret;
}
-static int PVRSRVRelease(struct inode unref__ * pInode,
- struct file unref__ * pFile)
+static int __devexit pvr_remove(struct platform_device *pdev)
{
- int Ret = 0;
+ struct SYS_DATA *sysdata;
+ int ret;
- LinuxLockMutex(&gPVRSRVLock);
+ PVR_TRACE("pvr_remove(pdev=%p)", pdev);
- PVRSRVProcessDisconnect(OSGetCurrentProcessIDKM());
+ ret = misc_deregister(&pvr_miscdevice);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "remove failed (%d)\n", ret);
+ return ret;
+ }
- LinuxUnLockMutex(&gPVRSRVLock);
+ if (SysAcquireData(&sysdata) == PVRSRV_OK)
+ SysDeinitialise(sysdata);
- return Ret;
+ return 0;
}
-static int __init PVRCore_Init(void)
-{
- int error;
-#if !(defined(LDM_PLATFORM) || defined(LDM_PCI))
- PVRSRV_ERROR eError;
-#endif
-
- PVR_TRACE(("PVRCore_Init"));
-
- AssignedMajorNumber = register_chrdev(0, DEVNAME, &pvrsrv_fops);
-
- if (AssignedMajorNumber <= 0) {
- PVR_DPF((PVR_DBG_ERROR,
- "PVRCore_Init: unable to get major number"));
-
- return -EBUSY;
- }
- PVR_TRACE(("PVRCore_Init: major device %d", AssignedMajorNumber));
+static struct platform_driver pvr_driver = {
+ .driver = {
+ .name = DRVNAME,
+ },
+ .probe = pvr_probe,
+ .remove = __devexit_p(pvr_remove),
+ .suspend = pvr_suspend,
+ .resume = pvr_resume,
+ .shutdown = pvr_shutdown,
+};
- if (CreateProcEntries()) {
- unregister_chrdev(AssignedMajorNumber, DRVNAME);
+static int __init pvr_init(void)
+{
+ int error;
- return -ENOMEM;
- }
+ pvr_dbg_init();
- LinuxInitMutex(&gPVRSRVLock);
+ PVR_TRACE("pvr_init");
-#ifdef DEBUG
+#ifdef CONFIG_PVR_DEBUG_EXTRA
PVRDebugSetLevel(debug);
#endif
- if (LinuxMMInit() != PVRSRV_OK) {
- error = -ENOMEM;
- goto init_failed;
- }
-
- LinuxBridgeInit();
-
- PVRMMapInit();
-
-#if defined(LDM_PLATFORM) || defined(LDM_PCI)
-
-#if defined(LDM_PLATFORM)
- if ((error = platform_driver_register(&powervr_driver)) != 0) {
- PVR_DPF((PVR_DBG_ERROR,
- "PVRCore_Init: unable to register platform driver (%d)",
- error));
-
- goto init_failed;
- }
-
- if ((error = platform_device_register(&powervr_device)) != 0) {
- platform_driver_unregister(&powervr_driver);
+#ifdef CONFIG_DEBUG_FS
+ pvr_debugfs_init();
+#endif
- PVR_DPF((PVR_DBG_ERROR,
- "PVRCore_Init: unable to register platform device (%d)",
- error));
+ error = CreateProcEntries();
+ if (error < 0)
+ goto err1;
- goto init_failed;
- }
-#endif
+ error = -ENOMEM;
+ if (LinuxMMInit() != PVRSRV_OK)
+ goto err2;
-#if defined(LDM_PCI)
- if ((error = pci_register_driver(&powervr_driver)) != 0) {
- PVR_DPF((PVR_DBG_ERROR,
- "PVRCore_Init: unable to register PCI driver (%d)",
- error));
+ if (LinuxBridgeInit() != PVRSRV_OK)
+ goto err3;
- goto init_failed;
- }
-#endif
+ PVRMMapInit();
-#else
+ error = platform_driver_register(&pvr_driver);
+ if (error < 0)
+ goto err4;
- if ((eError = SysInitialise()) != PVRSRV_OK) {
- error = -ENODEV;
-#if defined(TCF_REV) && (TCF_REV == 110)
- if (eError == PVRSRV_ERROR_NOT_SUPPORTED) {
- printk("\nAtlas wrapper (FPGA image) version mismatch");
- error = -ENODEV;
- }
-#endif
- goto init_failed;
- }
-#endif
+ pvr_init_events();
return 0;
-init_failed:
-
+err4:
PVRMMapCleanup();
+ LinuxBridgeDeInit();
+err3:
LinuxMMCleanup();
+err2:
RemoveProcEntries();
- unregister_chrdev(AssignedMajorNumber, DRVNAME);
+err1:
+ pr_err("%s: failed (%d)\n", __func__, error);
return error;
-
}
-static void __exit PVRCore_Cleanup(void)
+static void __exit pvr_cleanup(void)
{
- SYS_DATA *psSysData;
+ PVR_TRACE("pvr_cleanup");
- PVR_TRACE(("PVRCore_Cleanup"));
+ pvr_exit_events();
- SysAcquireData(&psSysData);
-
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22))
- if (
-#endif
- unregister_chrdev(AssignedMajorNumber, DRVNAME)
-#if !(LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22))
- ;
-#else
- ) {
- PVR_DPF((PVR_DBG_ERROR, " can't unregister device major %d",
- AssignedMajorNumber));
- }
-#endif
-
-#if defined(LDM_PLATFORM) || defined(LDM_PCI)
-
-#if defined(LDM_PCI)
- pci_unregister_driver(&powervr_driver);
-#endif
-
-#if defined (LDM_PLATFORM)
- platform_device_unregister(&powervr_device);
- platform_driver_unregister(&powervr_driver);
-#endif
-
-#else
-#if defined(DEBUG) && defined(PVR_MANUAL_POWER_CONTROL)
- if (gPVRPowerLevel != 0) {
- if (PVRSRVSetPowerStateKM(PVRSRV_POWER_STATE_D0) == PVRSRV_OK) {
- gPVRPowerLevel = 0;
- }
- }
-#endif
-
- SysDeinitialise(psSysData);
-#endif
+ platform_driver_unregister(&pvr_driver);
PVRMMapCleanup();
-
LinuxMMCleanup();
-
LinuxBridgeDeInit();
-
RemoveProcEntries();
- PVR_TRACE(("PVRCore_Cleanup: unloading"));
+ PVR_TRACE("pvr_cleanup: unloading");
+
+#ifdef CONFIG_DEBUG_FS
+ pvr_debugfs_cleanup();
+#endif
+ pvr_dbg_cleanup();
}
-module_init(PVRCore_Init);
-module_exit(PVRCore_Cleanup);
+module_init(pvr_init);
+module_exit(pvr_cleanup);
+
+MODULE_SUPPORTED_DEVICE(DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+