📄 krua.c
字号:
/***************************************** Copyright © 2001-2003 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* @file em8xxx.c See licensing details in LICENSING file */#define ALLOW_OS_CODE 1#include "../../../emhwlib/include/emhwlib.h"#include "../../../emhwlib/include/emhwlib_properties_1000.h"#include "../../../emhwlib/include/emhwlib_event.h"#include "../../../emhwlib/include/emhwlib_chipspecific.h"#include "../include/em8xxx_uk.h"#include "../../../llad/kinclude/kernelcalls.h"#include "../../../llad/kinclude/mum_kk.h"#include "../../../llad/include/kdmapool.h"#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)#include <linux/moduleparam.h>#endif#include <linux/fs.h>#include <linux/sched.h>#include <linux/interrupt.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)#include <linux/devfs_fs_kernel.h>#endif#include <linux/poll.h>#include "em8xxx.h"#include "em8xxx_proc.h"#include "../../../gbuslib/include/gbus_time.h"#include "../../../gbuslib/include/gbus_host_interrupt.h"// to enable or disable the debug related to cleanup messages of this source file, put 1 or 0 below#if 0#define CLEANDBG ENABLE#else#define CLEANDBG DISABLE#endif// to enable or disable the debug related event messages of this source file, put 1 or 0 below#if 0#define EVENTDBG ENABLE#else#define EVENTDBG DISABLE#endif// to enable or disable the debug messages of this source file, put 1 or 0 below#if 0#define LOCALDBG ENABLE#else#define LOCALDBG DISABLE#endifMODULE_DESCRIPTION("rua kernel module for em8xxx chips");MODULE_AUTHOR("Julien Soulier <julien_soulier@realmagic.fr>, Emmanuel Michon <em@sdesigns.com>");#ifdef MODULE_LICENSEMODULE_LICENSE("Proprietary"); // parsed keyword, don't change!#endif // MODULE_LICENSEstatic int major = EM8XXX_MAJOR;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)module_param(major, int,0);#elseMODULE_PARM(major, "i");#endifMODULE_PARM_DESC(major, "Sets the major number");RMstatus krua_register_event_callback(void *pE, RMuint32 ModuleID, RMuint32 mask, Event_callback callback);RMstatus krua_unregister_event_callback(void *pE, RMuint32 ModuleID, Event_callback callback);RMstatus krua_register_sendcomplete_callback(void *pE, Alsa_callback callback);RMstatus krua_unregister_sendcomplete_callback(void *pE);#define MAXDMAPOOL 32struct condition_cookie_type { struct em8xxxprivate *pE; RMuint32 event_count; struct em8xxx_event *pEvents; RMint32 event_num;}; /* em8xxx_id is an id identifying a unique memore space. All threads within a same process should have the same em8xxx_id. The tgid corresponds to this id, unfortunately on 2.4 linux kernels it is not implemented this way and we cannot use it. Instead we use the process group id, which behaves as expected. 2.6 kernels do not have the pgrp on the current task structure. Therefore we need the switch below.*/#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) #define CURRENT_EM8XXX_ID (current->pgrp) #else#define CURRENT_EM8XXX_ID (current->signal->pgrp) #endifstruct em8xxxprivate Etable[MAXLLAD]={ { 0 } };#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)/* the major number for devfs is local to this file */static unsigned long devfs_major;#endifstatic inline void kc_atomic_clear_mask(RMuint32 *addr, RMuint32 mask){ RMuint32 bit = 0; while (mask) { if (1 & mask) kc_clear_bit(bit, addr); bit ++; mask >>= 1; }}static inline void kc_atomic_set_mask(RMuint32 *addr, RMuint32 mask){ RMuint32 bit = 0; while (mask) { if (1 & mask) kc_set_bit(bit, addr); bit ++; mask >>= 1; }} int emergency_exit(struct em8xxxprivate *pE){ RMuint32 i,processedentries=0; // first the standard properties for (i=0 ; i<MAX_CLEANABLE ; i++) { if ((pE->cl[i].PropertyID!=0) && (pE->cl[i].em8xxx_id==CURRENT_EM8XXX_ID)) { PE_RMDBGLOG((CLEANDBG,"emergency_exit: #%d %d-%d-%d-0x%08lx\n", i, CURRENT_EM8XXX_ID, pE->cl[i].ModuleID, pE->cl[i].PropertyID, pE->cl[i].value)); // note: this call normally calls EMhwlibUnregisterCleanable if (EMhwlibSetProperty(pE->pemhwlib, pE->cl[i].ModuleID, pE->cl[i].PropertyID, &pE->cl[i].value, sizeof(RMuint32)) != RM_OK) { PE_RMDBGLOG((CLEANDBG,"emergency_exit: cannot set property %lu for module 0x%lx\n", pE->cl[i].PropertyID, pE->cl[i].ModuleID)); return -1; } processedentries++; } } // then RMFree ... for (i=0 ; i<MAX_MEMORY_AREA ; i++) { if ((pE->mem_area[i].PropertyID!=0) && ((pE->mem_area[i].em8xxx_id == 0) || (pE->mem_area[i].em8xxx_id==CURRENT_EM8XXX_ID) || (pE->mem_area[i].em8xxx_id==pE->insmod_em8xxx_id))) { /* if (pE->mem_area[i].id) { //RUASetAddressID marked the memory to not be freed PE_RMDBGLOG((CLEANDBG,"emergency_exit: do not free address 0x%08x with refcount %lu and id %lu\n", pE->mem_area[i].address_start, pE->mem_area[i].refcount, pE->mem_area[i].id)); continue; } */ if (pE->mem_area[i].refcount > 0) { PE_RMDBGLOG((CLEANDBG,"emergency_exit: address 0x%08x with refcount %lu > 0 do not free\n", pE->mem_area[i].address_start, pE->mem_area[i].refcount)); pE->mem_area[i].em8xxx_id = 0; /* this area is not attached to a process anymore */ } else { RMuint32 module_id = pE->mem_area[i].ModuleID; // note: RMMMPropertyID_Free fails for MM module with index not NULL - filter it if ((EMHWLIB_MODULE_CATEGORY(module_id) == MM) && (pE->mem_area[i].PropertyID == RMMMPropertyID_Free)) module_id = MM; PE_RMDBGLOG((CLEANDBG,"emergency_exit: freeing entry %d, address 0x%08x.\n", i, pE->mem_area[i].address_start)); // note: this call normally calls EMhwlibUnregisterCleanable if (EMhwlibSetProperty(pE->pemhwlib, module_id, pE->mem_area[i].PropertyID, &pE->mem_area[i].address_start, sizeof(RMuint32)) != RM_OK) { PE_RMDBGLOG((CLEANDBG,"emergency_exit: cannot set property %lu for module 0x%lx address=0x%lx\n", pE->mem_area[i].PropertyID, pE->mem_area[i].ModuleID, pE->mem_area[i].address_start)); return -1; } processedentries++; } } } PE_RMDBGLOG((CLEANDBG,"emergency_exit: %d entries processed\n", processedentries)); return processedentries;}static inline RMint32 find_and_clear_event(struct em8xxxprivate *pE, RMuint32 EventCount, struct em8xxx_event *pEvents){ RMuint32 i,j; RMstatus rc; for (j=0 ; j<EventCount ; j++) { for (i=0 ; i<pE->event_count ; i++) { if (pEvents[j].module_id != pE->event_array[i].module_id) continue; if (!(pEvents[j].event_mask & pE->event_array[i].event_mask)) break; /* takes only bits present inside rua */ pEvents[j].event_mask &= pE->event_array[i].event_mask; /* clear mask inside rua address space */ kc_atomic_clear_mask(&(pE->event_array[i].event_mask), pEvents[j].event_mask); /* 0 means application only event */ if (pEvents[j].module_id != 0) { /* clear mask inside emhwlib */ kc_spin_lock_bh(pE->lock); rc = EMhwlibSetProperty(pE->pemhwlib, pEvents[j].module_id, RMGenericPropertyID_ClearEventMask, &(pEvents[j].event_mask), sizeof(pEvents[j].event_mask)); kc_spin_unlock_bh(pE->lock); if (rc != RM_OK) PE_RMDBGLOG((ENABLE, "Cannot clear event inside emhwlib %lu 0x%08lx\n", pEvents[j].module_id, pEvents[j].event_mask)); } /* we could decrease the pE->event_count, if pE->event_array[i].event_mask == 0, because no more event is set for this index. However, this implies more locking that what we currently do and the code will be less efficient. If an event occurs for a given module (and application waits for it), it is very likely that this event will occur again and therefore, we may end-up by constantly removing and adding entries in the event array for no gain. The event array is cleared on the last close of the process, and therefore during the lifetime of a process, the array can only grow. This could be a problem only if the same process was doing one after the other two tasks with completely different set of events. We could end up by not having enough space inside the event array while if would have been possible to handle it, if we have decremented the event count here */ PE_RMDBGLOG((EVENTDBG, "find and clear event %lu 0x%08lx\n", pEvents[j].module_id, pEvents[j].event_mask)); return j; } } return -1;}static unsigned int wait_condition(void *cookie) { struct condition_cookie_type *param = (struct condition_cookie_type *) cookie; param->event_num = find_and_clear_event(param->pE, param->event_count, param->pEvents); return (param->event_num >= 0);}static int em8xxx_ioctl(struct inode *i_node, struct file *filp,unsigned int cmd, unsigned long arg){ struct em8xxxprivate *pE = (struct em8xxxprivate *) filp->private_data; int rc; if (pE->pllad == NULL) return -EINVAL; switch (cmd) { case EM8XXX_IOCTL_SET_PROPERTY: { struct em8xxx_property param; void *propIn; if (kc_logging_copy_from_user(¶m, (char *)arg, sizeof(param)) > 0) return -EFAULT; if (param.propInSize > MAX_PROPSIZE) propIn = kc_vmalloc(param.propInSize); else propIn = pE->buf1; if (kc_logging_copy_from_user(propIn, param.propInVal, param.propInSize) > 0) { if (param.propInSize > MAX_PROPSIZE) kc_vfree(propIn); return -EFAULT; } PE_RMDBGLOG((LOCALDBG,"set property moduleId %lu, propId %lu \n", param.moduleId, param.propId)); kc_spin_lock_bh(pE->lock); param.status = EMhwlibSetProperty(pE->pemhwlib, param.moduleId, param.propId, propIn, param.propInSize); kc_spin_unlock_bh(pE->lock); if (param.propInSize > MAX_PROPSIZE) kc_vfree(propIn); if (kc_logging_copy_to_user((char *) arg, ¶m, sizeof(param)) > 0) return -EFAULT; rc = 0; } break; case EM8XXX_IOCTL_GET_PROPERTY: { struct em8xxx_property param; void *propOut; if (kc_logging_copy_from_user(¶m, (char *)arg, sizeof(param)) > 0) return -EFAULT; if (param.propOutSize > MAX_PROPSIZE) propOut = kc_vmalloc(param.propOutSize); else propOut = pE->buf1; PE_RMDBGLOG((LOCALDBG,"get property moduleId %lu, propId %lu \n", param.moduleId, param.propId)); kc_spin_lock_bh(pE->lock); param.status = EMhwlibGetProperty(pE->pemhwlib, param.moduleId, param.propId, propOut, param.propOutSize); kc_spin_unlock_bh(pE->lock); if (kc_logging_copy_to_user(param.propOutVal, propOut, param.propOutSize) > 0) { if (param.propOutSize > MAX_PROPSIZE) kc_vfree(propOut); return -EFAULT; } if (param.propOutSize > MAX_PROPSIZE) kc_vfree(propOut); if (kc_logging_copy_to_user((char *) arg, ¶m, sizeof(param)) > 0) return -EFAULT; rc = 0; } break; case EM8XXX_IOCTL_EXCHANGE_PROPERTY: { struct em8xxx_property param; void *propOut, *propIn; if (kc_logging_copy_from_user(¶m, (char *)arg, sizeof(param)) > 0) return -EFAULT; if (param.propInSize > MAX_PROPSIZE) propIn = kc_vmalloc(param.propInSize); else propIn = pE->buf1; if (kc_logging_copy_from_user(propIn, param.propInVal, param.propInSize) > 0) { if (param.propInSize > MAX_PROPSIZE) kc_vfree(propIn); return -EFAULT; } if (param.propOutSize > MAX_PROPSIZE) propOut = kc_vmalloc(param.propOutSize); else propOut = pE->buf2; kc_spin_lock_bh(pE->lock); param.status = EMhwlibExchangeProperty(pE->pemhwlib, param.moduleId, param.propId, propIn, param.propInSize, propOut, param.propOutSize); kc_spin_unlock_bh(pE->lock); if (param.propInSize > MAX_PROPSIZE) kc_vfree(propIn); if (kc_logging_copy_to_user(param.propOutVal, propOut, param.propOutSize) > 0) { if (param.propOutSize > MAX_PROPSIZE) kc_vfree(propOut); return -EFAULT; } if (param.propOutSize > MAX_PROPSIZE) kc_vfree(propOut); if (kc_logging_copy_to_user((char *) arg, ¶m, sizeof(param)) > 0) return -EFAULT; rc = 0; } break; case EM8XXX_IOCTL_SEND_DATA: { struct em8xxx_data param; void *info; RMuint32 context; if (kc_logging_copy_from_user(¶m, (char *)arg, sizeof(param)) > 0) return -EFAULT; if (param.infoSize > MAX_PROPSIZE) info = kc_vmalloc(param.infoSize); else info = pE->buf1; if (kc_logging_copy_from_user(info, param.info, param.infoSize) > 0) { if (param.infoSize > MAX_PROPSIZE) kc_vfree(info); return -EFAULT; } context = ((pE-Etable) << 16) + param.poolId + 1; kc_spin_lock_bh(pE->lock); rc = EMhwlibSendBuffer(pE->pemhwlib, param.moduleId, param.bus_addr, param.dataSize, info, param.infoSize, (void *) context); kc_spin_unlock_bh(pE->lock); rc = (rc == RM_OK) ? 0 : -EINVAL; if (param.infoSize > MAX_PROPSIZE) kc_vfree(info); } break; case EM8XXX_IOCTL_RECEIVE_DATA: { struct em8xxx_data param; void *info; void *context; if (kc_logging_copy_from_user(¶m, (char *)arg, sizeof(param)) > 0) return -EFAULT; if (param.infoSize > MAX_PROPSIZE) info = kc_vmalloc(param.infoSize); else info = pE->buf1; kc_spin_lock_bh(pE->lock); rc = EMhwlibReceiveBuffer(pE->pemhwlib, param.moduleId, &(param.bus_addr), &(param.dataSize), info, &(param.infoSize), &context); kc_spin_unlock_bh(pE->lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -