/* -*- Mode: C; tab-width: 4; indent-tabs-mode: 't; c-basic-offset: 4 -*-
*
* Name : $RCSfile: module.c $
*
* Copyright : 2000,2001,2002 by Imagination Technologies Limited.
* All rights reserved.
* No part of this software, either material or conceptual
* may be copied or distributed, transmitted, transcribed,
* stored in a retrieval system or translated into any
* human or computer language in any form by any means,
* electronic, mechanical, manual or other-wise, or
* disclosed to third parties without the express written
* permission of:
* Imagination Technologies Limited,
* HomePark Industrial Estate,
* Kings Langley,
* Hertfordshire,
* WD4 8LZ,
* UK
*
* Description : module init/deinit/ioctl for pvr core drivers
*
* Version : $Revision: 1.40 $
*
**************************************************************************/
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/kdev_t.h>
#include <linux/pci.h>
#include <linux/list.h>
#include <linux/init.h>
#include "mmap.h"
#include "virtmem.h"
#include "kernmem.h"
#include "debug.h"
/* ResMan */
void ResManProcessConnect(int dwProcID);
void ResManProcessDisconnect(void);
void RecoverPrimarySurface(void);
#define RESMAN_PROCESSID_FIND 0xffffffff
/****************************************************/
/* FILE OPERATIONS */
/****************************************************/
int pmxcore_driver_init = 0;
/* Registry */
int number_registry_entries = 0;
REGISTRY_ENTRY pvrcore_registry[MAX_REGISTRY_ENTRIES];
int send_registry_info(void *); /* send to the kernel */
int get_registry_info(void *, void *); /* get from the kernel */
LIST_HEAD(pvrProcList);
extern PKV_OFFSET_LOCKED_STRUCT psKVOffsetStruct;
void ReleaseDpf(char *format, ...)
{
asm("pop %%ebp\njmp *%0\n" : : "r" (&printk));
}
int pmxcore_open(void)
{
int Ret = 0;
struct list_head *ptr = 0;
struct pvrProcRecord *entry = 0;
unsigned found = 0;
MOD_INC_USE_COUNT;
if(pmxcore_driver_init)
{
pmxcore_driver_init += 1;
ResManProcessConnect(RESMAN_PROCESSID_FIND);
/* process open ref count for KVOT lock */
for (ptr = pvrProcList.next; ptr != &pvrProcList; ptr = ptr->next)
{
entry = list_entry(ptr, struct pvrProcRecord, list);
if (entry->pid == current->pid)
{
entry->count++;
found = 1;
break;
}
}
if (!found)
{
entry = kmalloc(sizeof(struct pvrProcRecord), GFP_KERNEL);
entry->pid = current->pid;
INIT_LIST_HEAD(&entry->mmapList);
entry->count = 1;
entry->drmMMAP = 0;
list_add_tail(&entry->list, &pvrProcList);
}
}
DPF("pmxcore_open ok");
return Ret;
}
int pvr_switch_to_pvr(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct list_head *ptr = 0;
struct pvrProcRecord *entry = 0;
for (ptr = pvrProcList.next; ptr != &pvrProcList; ptr = ptr->next)
{
entry = list_entry(ptr, struct pvrProcRecord, list);
if (entry->pid == current->pid)
entry->drmMMAP = 0;
}
return 0;
}
int pvr_switch_to_drm(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct list_head *ptr = 0;
struct pvrProcRecord *entry = 0;
for (ptr = pvrProcList.next; ptr != &pvrProcList; ptr = ptr->next)
{
entry = list_entry(ptr, struct pvrProcRecord, list);
if (entry->pid == current->pid)
entry->drmMMAP = 1;
}
return 0;
}
int pvrUsingDRMMMAP(void)
{
struct list_head *ptr = 0;
struct pvrProcRecord *entry = 0;
for (ptr = pvrProcList.next; ptr != &pvrProcList; ptr = ptr->next)
{
entry = list_entry(ptr, struct pvrProcRecord, list);
if (entry->pid == current->pid)
return entry->drmMMAP;
}
return 0;
}
int pmxcore_release(void)
{
int Ret = 0;
struct list_head *ptr = 0;
struct pvrProcRecord *entry = 0;
DPF("pmxcore_release");
if(pmxcore_driver_init > 1)
{
ResManProcessDisconnect();
/* Check if we need to break the KVOT lock */
for (ptr = pvrProcList.next; ptr != &pvrProcList; ptr = ptr->next)
{
entry = list_entry(ptr, struct pvrProcRecord, list);
if (entry->pid == current->pid)
{
if (--entry->count == 0) {
if (psKVOffsetStruct &&
(*psKVOffsetStruct->lockAddress == current->pid))
*psKVOffsetStruct->lockAddress = 0;
while (!list_empty(&entry->mmapList))
{
struct pvrMMAPRecord *mrecord;
mrecord = list_entry(entry->mmapList.next,
struct pvrMMAPRecord,
list);
list_del(&mrecord->list);
kfree(mrecord);
}
list_del(&entry->list);
kfree(entry);
/* Put this back when turning */
/* fullscreen flipping back on */
/* RecoverPrimarySurface(); */
}
break;
}
}
}
MOD_DEC_USE_COUNT;
return Ret;
}
/****************************************************/
/* DRIVER INIT AND DEINIT */
/****************************************************/
#if defined(SUPPORT_AGP)
extern void InitializeAGP(void);
extern void ShutdownAGP(void);
#endif
void pvr_munmap_event(void *pvIn)
{
MUNMAP_EVENT *munmap = (MUNMAP_EVENT *)pvIn;
struct list_head *ptr = 0;
struct pvrProcRecord *processEntry = 0;
struct pvrMMAPRecord *mmapEntry = 0;
for (ptr = pvrProcList.next; ptr != &pvrProcList; ptr = ptr->next)
{
processEntry = list_entry(ptr, struct pvrProcRecord, list);
if (processEntry->pid == current->pid)
{
struct list_head *mptr;
for (mptr = processEntry->mmapList.next; mptr != &processEntry->mmapList; mptr = mptr->next)
{
mmapEntry = list_entry(mptr, struct pvrMMAPRecord, list);
if ((mmapEntry->userAddress == munmap->userAddress) &&
(mmapEntry->length == munmap->length))
{
list_del(&mmapEntry->list);
kfree(mmapEntry);
break;
}
}
break;
}
}
}
int send_registry_info(void *pvIn)
{
REGISTRY_ENTRY *reg_entry;
int i;
reg_entry = (REGISTRY_ENTRY*)pvIn;
/* first check if the current registry setting exists */
for(i=0; i<number_registry_entries; i++)
{
if(!strcmp(pvrcore_registry[i].cEntryName, reg_entry->cEntryName))
if(!strcmp(pvrcore_registry[i].cKeyName, reg_entry->cKeyName))
{
/* we have found the entry in the registry so just overwrite it */
pvrcore_registry[i].dwData = reg_entry->dwData;
if(reg_entry->cData[0])
strcpy(pvrcore_registry[i].cData, reg_entry->cData);
else
pvrcore_registry->cData[0]='\0';
return 0;
}
}
if (number_registry_entries < MAX_REGISTRY_ENTRIES)
{
memcpy(pvrcore_registry[number_registry_entries].cEntryName, ®_entry->cEntryName, 64);
memcpy(pvrcore_registry[number_registry_entries].cKeyName, ®_entry->cKeyName, 32);
pvrcore_registry[number_registry_entries].dwData = reg_entry->dwData;
if(reg_entry->cData[0])
strcpy(pvrcore_registry[number_registry_entries].cData, reg_entry->cData);
else
pvrcore_registry[number_registry_entries].cData[0] = '\0';
number_registry_entries += 1;
}
return 0;
}
int get_registry_info(void *pvIn, void *pvOut)
{
int code;
code = *((int*)(pvIn));
if(!code)
{
/* the user asks how many registry entries are there */
*((int*)(pvOut)) = number_registry_entries;
return 0;
}
/* we return the whole registry */
memcpy(pvOut, pvrcore_registry, sizeof(REGISTRY_ENTRY) * number_registry_entries);
return 0;
}
/* end of $RCSfile: module.c $ */
|