diff options
Diffstat (limited to 'drivers/misc/gpsip/cgdriver/CgxDriverLinux.c')
| -rw-r--r-- | drivers/misc/gpsip/cgdriver/CgxDriverLinux.c | 1373 |
1 files changed, 1373 insertions, 0 deletions
diff --git a/drivers/misc/gpsip/cgdriver/CgxDriverLinux.c b/drivers/misc/gpsip/cgdriver/CgxDriverLinux.c new file mode 100644 index 00000000..7d9cdc3c --- /dev/null +++ b/drivers/misc/gpsip/cgdriver/CgxDriverLinux.c @@ -0,0 +1,1373 @@ +/****************************************************************************** + * LEGAL NOTICE * + * * + * USE OF THIS SOFTWARE (including any copy or compiled version thereof) AND * + * DOCUMENTATION IS SUBJECT TO THE SOFTWARE LICENSE AND RESTRICTIONS AND THE * + * WARRANTY DISLCAIMER SET FORTH IN LEGAL_NOTICE.TXT FILE. IF YOU DO NOT * + * FULLY ACCEPT THE TERMS, YOU MAY NOT INSTALL OR OTHERWISE USE THE SOFTWARE * + * OR DOCUMENTATION. * + * NOTWITHSTANDING ANYTHING TO THE CONTRARY IN THIS NOTICE, INSTALLING OR * + * OTHERISE USING THE SOFTWARE OR DOCUMENTATION INDICATES YOUR ACCEPTANCE OF * + * THE LICENSE TERMS AS STATED. * + * * + ******************************************************************************/ +/* Version: 1.8.9\3686 */ +/* Build : 13 */ +/* Date : 12/08/2012 */ + + +/** + \cond OS_LINUX +*/ + +/** + \file + \brief Linux specific driver code + \attention This file should not be modified. + If you think something is wrong here, please contact CellGuide + Specific code required for the CellGuide GPS driver for Linux. +*/ +// =========================================================================== + +#define __CGXLINUXDRIVER_C__ +#include <asm/io.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/cdev.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/poll.h> +#include <linux/device.h> +#include <linux/major.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/completion.h> +#include <linux/dma-mapping.h> + +#ifdef CONFIG_OF +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_gpio.h> +#endif + +#include "CgTypes.h" +#include "CgReturnCodes.h" +#include "CgCpu.h" +#include "CgxDriverCore.h" +#include "CgxDriverOs.h" +#include "CgxDriverPlatform.h" + +#include "platform.h" +#include "CgCpuOs.h" + + +extern U32 CGCORE_REG_OFFSET_CORE_RESETS; +extern U32 CGCORE_REG_OFFSET_VERSION; +extern U32 poffset; + + +struct class * gps_class; +struct device * gps_dev; + + + +/*paulluo add test*/ +//#define FIX_MEMORY +#ifdef CGCORE_ACCESS_VIA_SPI +extern int gpsspidev_init(void); +extern void gpsspidev_exit(void); +#endif + + +// =========================================================================== + +// +// Driver instance structure. +// +typedef struct { + struct cdev cdev; + int nNumOpens; + int DataReady_irq; + int GpsIntr_irq; + struct completion xferCompleted; // was rcvSem + TCgxDriverPhysicalMemory chunk; + TCgxDriverState state; + void *xfer_buff_ptr; // Internal buffer pointer + unsigned long xfer_buff_len; // Internal buffer len (bytes) + int xfer_buff_pg_order; // Internal buffer page order (log2(n)) + int xfer_buff_mmapped; // Internal buffer is mapped + struct fasync_struct *async_queue; + wait_queue_head_t resumeq; + char pm_resumed; +} DRVCONTEXT; + +// Use a static DriverContext, as only one driver instance is needed +static DRVCONTEXT DrvContext; +//bxd add for first alloc mem failed from engine +static void *init_buff_ptr; + +static void GpsIntr_BH(struct work_struct *work); +DECLARE_WORK( girq_work, GpsIntr_BH ); +static struct workqueue_struct *girq_wq = NULL; +#define GIRQ_WQ_NAME "GIRQ WorkQueue" + +static void DataReady_BH(struct work_struct *work); +DECLARE_WORK( drdy_work, DataReady_BH ); +static struct workqueue_struct *drdy_wq = NULL; +#define DRDY_WQ_NAME "DRDY WorkQueue" + +// In certain devices, there will not be an irq for DMA ready, but instead, a wait-able, exported sync-object. +#ifdef CGX_DRIVE_DMA_INT_GLOBAL_SYNC_OBJECT + + static void DataReady_Completion_WorkQueue(struct work_struct *work); + DECLARE_WORK( drdy_completion_work, DataReady_Completion_WorkQueue ); + static struct workqueue_struct *drdy_completion_wq = NULL; + #define DRDY_COMPLETION_WQ_NAME "DRDY Completion WorkQueue" + + extern struct completion CGX_DRIVE_DMA_INT_GLOBAL_SYNC_OBJECT; + + /* + DataReady Interrupt Handlers: + DataReady_BH: The Bottom-Half (Handler Thread) + DataReady_TH: The Top-Half (ISR) + CgxDriverDataReadyInterruptHandlerStart: Register the DataReady ISR + */ + static void DataReady_Completion_WorkQueue(struct work_struct *work) + { + // DBG_FUNC_NAME("DataReady_BH") + // DBGMSG("START"); + while (1) + { + wait_for_completion( &CGX_DRIVE_DMA_INT_GLOBAL_SYNC_OBJECT ); + CgxDriverDataReadyInterruptHandler(&DrvContext, &DrvContext.state); + } + + // DBGMSG("END"); + } +#endif + +static int cgxdrv_major = 0; /* 0 = dynamic major */ +#define MODULE_NAME "cgxdrv" + + +/* + DataReady Interrupt Handlers: + DataReady_BH: The Bottom-Half (Handler Thread) + DataReady_TH: The Top-Half (ISR) + CgxDriverDataReadyInterruptHandlerStart: Register the DataReady ISR + */ +static void DataReady_BH(struct work_struct *work) +{ + // DBG_FUNC_NAME("DataReady_BH") + // DBGMSG("START"); + CgxDriverDataReadyInterruptHandler(&DrvContext, &DrvContext.state); + //enable_irq( DrvContext.DataReady_irq ); + // DBGMSG("END"); +} + +static irqreturn_t DataReady_TH(int irq, void *dev_id) +{ + // DBG_FUNC_NAME("DataReady_TH") + // DBGMSG("START"); + //disable_irq_nosync( irq ); + + queue_work(drdy_wq, &drdy_work); + // DBGMSG("END"); + + return IRQ_HANDLED; +} + + +#ifdef CGCORE_ACCESS_VIA_SPI +u32 GetRequestLen(void) +{ + TCgxDriverState *pState = &DrvContext.state; + + return pState->transfer.bytes.required; +} + +void DataReady_TH_start(void ) +{ + + CgxDriverDataReadyInterruptHandler(&DrvContext, &DrvContext.state); + +} +#endif +void* Data_Get_DrvContext(void) +{ + + return DrvContext.xfer_buff_ptr; +} + +void CCgCpuDmaHandle(int irq,void* dev_id) +{ + CgxDriverDataReadyInterruptHandler(&DrvContext, &DrvContext.state); +} + + +TCgReturnCode CgxDriverDataReadyInterruptHandlerStart(void *pDriver) +{ + DBG_FUNC_NAME("CgxDriverDataReadyInterruptHandlerStart") + DRVCONTEXT *pDriverInfo = (DRVCONTEXT *)pDriver; + + int rv = 0; + + // First check if there is an irq dedicated to the DataReady event + pDriverInfo->DataReady_irq = CgxDriverDataReadyInterruptCode(); + if( pDriverInfo->DataReady_irq != 0) + { + drdy_wq = create_singlethread_workqueue(DRDY_WQ_NAME); + + if (drdy_wq == NULL) { + DBGMSG("create_singlethread_workqueue(" DRDY_WQ_NAME ") Failed"); + return ECgInitFailure; + } + + rv = request_irq( pDriverInfo->DataReady_irq, DataReady_TH, IRQF_DISABLED, "drdy-bh", NULL ); + if (rv != 0) { + DBGMSG1("request_irq(%d) Failed", pDriverInfo->DataReady_irq ); + return ECgInitFailure; + } + DBGMSG1("request_irq(DRDY/%d) OK", pDriverInfo->DataReady_irq ); + } + else + { + // There is no irq. Lets check if there is an exported sync-object + #ifdef CGX_DRIVE_DMA_INT_GLOBAL_SYNC_OBJECT + drdy_completion_wq = create_singlethread_workqueue(DRDY_COMPLETION_WQ_NAME); + if ( OK(drdy_completion_wq) ) + queue_work(drdy_completion_wq, &drdy_completion_work); + else + return ECgInitFailure; + #else + DBGMSG1("request_irq(DRDY/%d) Skipped", pDriverInfo->DataReady_irq ); + #endif + } + + return ECgOk; +} + + + +/* + GpsIntr Interrupt Handlers: + GpsIntr_BH: The Bottom-Half (Handler Thread) + GpsIntr_TH: The Top-Half (ISR) + CgxDriverGeneralInterruptHandlerStart: Register the GpsIntr ISR + */ +static void GpsIntr_BH(struct work_struct *work) +{ + // DBG_FUNC_NAME("GpsIntr_BH") + // DBGMSG("START"); + CgxDriverGpsInterruptHandler(&DrvContext, &DrvContext.state); + // DBGMSG("END"); + enable_irq( DrvContext.GpsIntr_irq ); +} + +static irqreturn_t GpsIntr_TH(int irq, void *dev_id) +{ + // DBG_FUNC_NAME("GpsIntr_TH") + // DBGMSG("START"); + disable_irq_nosync( irq ); + + queue_work(girq_wq, &girq_work); + + // DBGMSG("END"); + return IRQ_HANDLED; +} + +TCgReturnCode CgxDriverGpsInterruptHandlerStart(void *pDriver) +{ + DBG_FUNC_NAME("CgxDriverGpsInterruptHandlerStart") + DRVCONTEXT *pDriverInfo = (DRVCONTEXT *)pDriver; + + int rv = 0; + pDriverInfo->GpsIntr_irq = CgxDriverGpsInterruptCode(); + if (pDriverInfo->GpsIntr_irq != 0) + { + girq_wq = create_singlethread_workqueue(GIRQ_WQ_NAME); + if (girq_wq == NULL) { + DBGMSG("create_singlethread_workqueue(" GIRQ_WQ_NAME ") Failed"); + return ECgInitFailure; + } + #ifdef CGCORE_ACCESS_VIA_SPI + rv = request_irq( pDriverInfo->GpsIntr_irq, GpsIntr_TH, IRQF_TRIGGER_RISING, "girq-bh", NULL ); + #else + rv = request_irq( pDriverInfo->GpsIntr_irq, GpsIntr_TH, IRQF_DISABLED, "girq-bh", NULL ); + #endif + if (rv != 0) { + DBGMSG1("request_irq(%d) Failed", pDriverInfo->GpsIntr_irq ); + return ECgInitFailure; + } + DBGMSG1("request_irq(GPS/%d) OK", pDriverInfo->GpsIntr_irq ); + } + else + DBGMSG1("request_irq(GPS/%d) Skipped", pDriverInfo->GpsIntr_irq ); + + return ECgOk; +} + + + + + +TCgReturnCode CgxDriverTransferEndCreate(void *pDriver) +{ + DBG_FUNC_NAME("CgxDriverTransferEndCreate") + DRVCONTEXT *pDriverInfo = (DRVCONTEXT *)pDriver; + + DBGMSG( "Entering... Initializing completion semaphore" ); + + init_completion( &pDriverInfo->xferCompleted ); + + DBGMSG1( "Initialized Semaphore=%u", pDriverInfo->xferCompleted.done ); + + return ECgOk; +} + + + +TCgReturnCode CgxDriverTransferEndSignal(void *pDriver) +{ + //DBG_FUNC_NAME("CgxDriverTransferEndSignal") + DRVCONTEXT *pDriverInfo = (DRVCONTEXT *)pDriver; + +/* DBGMSG( "Entering" );*/ + + //DBGMSG1( "Marking completion... Semaphore=%u", pDriverInfo->xferCompleted.done ); + complete( &pDriverInfo->xferCompleted ); + //DBGMSG1( "Marked completion... After Semaphore=%u", pDriverInfo->xferCompleted.done ); + + return ECgOk; +} + + +TCgReturnCode CgxDriverTransferEndWait(void *pDriver, U32 aTimeoutMS) +{ + DRVCONTEXT *pDriverInfo = (DRVCONTEXT *)pDriver; + TCgReturnCode rc = ECgOk; + unsigned long timeout = aTimeoutMS * HZ / 1000; + unsigned long rv = 0 ; + DBG_FUNC_NAME("CgxDriverTransferEndWait") + + DBGMSG1( "Timeout=%lu", timeout ); + + + for (;;) { + if (pDriverInfo->state.flags.resume == 1) { + DBGMSG("Resume!"); + return ECgResume; + } + //DBGMSG1( "Waiting for completion... Semaphore=%u", pDriverInfo->xferCompleted.done ); + /*bxd modify because of can't entry susnpend when use wait_for_completion_interruptible_timeout func */ + //rv = wait_for_completion_interruptible_timeout( &pDriverInfo->xferCompleted, timeout ); + rv = wait_for_completion_timeout( &pDriverInfo->xferCompleted, timeout ); + if (rv != -ERESTARTSYS) + break; + } + + if ((rv == 0) && (timeout > 0)) + { + rc = ECgTimeout; + DBGMSG( "Timed-out" ); + } + else + { + DBGMSG1( "wait_for_completion_interruptible_timeout returned=%d", rv ); + } + + if (pDriverInfo->state.flags.resume == 1) { + DBGMSG("Resume!"); + rc = ECgResume; + } + + return rc; +} + + +TCgReturnCode CgxDriverTransferEndDestroy(void *pDriver) +{ + return ECgOk; +} + + +//#define FIX_MEMORY + +#ifdef FIX_MEMORY +unsigned char buf_data[6*1024*1024]; +#else + void* buf_data; +#endif + +#ifndef CGCORE_ACCESS_VIA_SPI +void clear_buf_data(void) +{ + memset(DrvContext.xfer_buff_ptr,0,DrvContext.xfer_buff_len); +} +#endif + +TCgReturnCode CgxDriverAllocInternalBuff(void *pDriver, U32 aLength, void **apBuffer, U32 aProcessID) +{ + DBG_FUNC_NAME("CgxDriverAllocInternalBuff") + DRVCONTEXT *pDriverInfo = (DRVCONTEXT *)pDriver; + DBGMSG( "Entering..." ); + + /* Already alloc'ed, return error and ask to free 1st */ + if (DrvContext.xfer_buff_ptr != NULL) { + DBGMSG( "Returning ECgNotSupported" ); + return ECgNotSupported; + } + + + #ifndef FIX_MEMORY + DrvContext.xfer_buff_pg_order = get_order(aLength); + //bxd add for first alloc mem failed from engine + if(init_buff_ptr != NULL) + DrvContext.xfer_buff_ptr = init_buff_ptr; + else + DrvContext.xfer_buff_ptr = (void *)__get_free_pages(GFP_KERNEL, DrvContext.xfer_buff_pg_order); + DrvContext.xfer_buff_len = PAGE_SIZE * (1 << DrvContext.xfer_buff_pg_order); + buf_data = DrvContext.xfer_buff_ptr; + #else + DrvContext.xfer_buff_pg_order = get_order(aLength); + DrvContext.xfer_buff_ptr =(void*)&buf_data[0]; + DrvContext.xfer_buff_len = 6*1024*1024; + + #endif + + + if (DrvContext.xfer_buff_ptr == NULL) { + DBGMSG( "Returning ECgErrMemory" ); + return ECgErrMemory; + } + + pDriverInfo->state.buffer.length = DrvContext.xfer_buff_len; + pDriverInfo->state.buffer.virtAddr = DrvContext.xfer_buff_ptr; + pDriverInfo->state.buffer.physAddr = __pa((void *)DrvContext.xfer_buff_ptr) ; + DBGMSG2( "Returning ECgOk - Requested: %lu - Granted: %lu", aLength, DrvContext.xfer_buff_len ); + + *apBuffer = (void *)pDriverInfo->state.buffer.physAddr; +#if defined(CGTEST) || defined(DEBUG) + memset(pDriverInfo->state.buffer.virtAddr, 0x43, aLength); +#endif + DBGMSG3(">>>>>>> memory allocated at DrvContext.xfer_buff_ptr=[0x%08X] buffer.virtAddr=[0x%08X], buffer.physAddr=[0x%08X]",DrvContext.xfer_buff_ptr, pDriverInfo->state.buffer.virtAddr, pDriverInfo->state.buffer.physAddr ); + return ECgOk; +} + +#ifdef CGCORE_ACCESS_VIA_SPI +int get_blocksize(void) +{ + return DrvContext.state.transfer.blockSize; +} +#endif + + +void *CgxDriverGetInternalBuff(void *pSource, U32 length) +{ +// if (length != DrvContext.xfer_buff_len) +// return NULL; + + return DrvContext.xfer_buff_ptr; +} + + + +TCgReturnCode CgxDriverFreeInternalBuff(void *pDriver, U32 unUsed) +{ + /* Already alloc'ed, return error and ask to free 1st */ + if (DrvContext.xfer_buff_ptr == NULL) + return ECgNotSupported; + + /* Buffer is mmap'ed. return error and ask to free 1st */ + if (DrvContext.xfer_buff_mmapped) + return ECgNotAllowed; + +#ifndef FIX_MEMORY +//bxd + //free_pages((unsigned long)DrvContext.xfer_buff_ptr, DrvContext.xfer_buff_pg_order); +#endif + + DrvContext.xfer_buff_ptr = NULL; + DrvContext.xfer_buff_len = 0; + DrvContext.xfer_buff_pg_order = 0; + + //bxd add for first alloc mem failed from engine + //if(init_buff_ptr != NULL) + // init_buff_ptr = NULL; + + return ECgOk; +} + + + +unsigned long CgxCopyFromUser(void *to, const void *fromuser, unsigned long n) +{ + return copy_from_user(to, fromuser, n); +} + + + +static void getdata32_to_data64(TCgDriverControl_32bit *In32,TCgDriverControl *In64) +{ + In64->read.alignedLength = In32->read.alignedLength; + In64->read.blockLength = In32->read.blockLength; + In64->read.byteOrder = In32->read.byteOrder; + In64->read.buf = Data_Get_DrvContext(); + In64->read.bufPhys = In32->read.bufPhys; + In64->read.timeoutMS = In32->read.timeoutMS; + In64->wait.timeoutMS = In32->wait.timeoutMS; + In64->wait.blockNumber = In32->wait.blockNumber; +// In64->write.pSource = &In32->write.pSource; + In64->write.length = In32->write.length; + In64->GPIO.code = In32->GPIO.code; + In64->GPIO.out = In32->GPIO.out; + In64->GPIO.mode = In32->GPIO.mode; + In64->readReg.offset = In32->readReg.offset; + In64->writeReg.offset = In32->writeReg.offset; + In64->writeReg.value = In32->writeReg.value; + In64->cancel.onByteCount = In32->cancel.onByteCount; + In64->reset.resetLevel = In32->reset.resetLevel; + In64->alloc.length = In32->alloc.length; + In64->alloc.processId = In32->alloc.processId; + In64->tcxoControl.enable = In32->tcxoControl.enable; + + +#if 0 + printk("read.alignedLength: 0x%x\n", In32->read.alignedLength); + printk("read.blockLength: 0x%x\n", In32->read.blockLength); + printk("read.byteOrder: 0x%x\n", In32->read.byteOrder); + printk("read.buf: 0x%x\n", In32->read.buf); + printk("read.bufPhys: 0x%x\n", In32->read.bufPhys); + printk("read.timeoutMS: 0x%x\n", In32->read.timeoutMS); + + printk("wait.timeoutMS: 0x%x\n", In32->wait.timeoutMS); + printk("wait.blockNumber: 0x%x\n", In32->wait.blockNumber); + printk("write.pSource: 0x%x\n", In32->write.pSource); + printk("write.length: 0x%x\n", In32->write.length); + printk("GPIO.code: 0x%x\n", In32->GPIO.code); + + printk("GPIO.out: 0x%x\n", In32->GPIO.out); + printk("GPIO.mode: 0x%x\n", In32->GPIO.mode); + printk("readReg.offset: 0x%x\n", In32->readReg.offset); + printk("writeReg.offset: 0x%x\n", In32->writeReg.offset); + printk("writeReg.value: 0x%x\n", In32->writeReg.value); + printk("cancel.onByteCount: 0x%x\n", In32->cancel.onByteCount); + printk("reset.resetLevel: 0x%x\n", In32->reset.resetLevel); + printk("alloc.length: 0x%x\n", In32->alloc.length); + printk("alloc.processId: 0x%x\n", In32->alloc.processId); + printk("tcxoControl.enable: 0x%x\n", In32->tcxoControl.enable); + + + printk("read.alignedLength In64: 0x%x\n", In64->read.alignedLength); + printk("read.blockLength In64: 0x%x\n", In64->read.blockLength); + printk("read.byteOrder In64: 0x%x\n", In64->read.byteOrder); + printk("read.buf In64: 0x%x\n", In64->read.buf); + printk("read.bufPhys In64: 0x%x\n", In64->read.bufPhys); + printk("read.timeoutMS In64: 0x%x\n", In64->read.timeoutMS); + + printk("wait.timeoutMS In64: 0x%x\n", In64->wait.timeoutMS); + printk("wait.blockNumber In64: 0x%x\n", In64->wait.blockNumber); + printk("write.pSource In64: 0x%x\n", In64->write.pSource); + printk("write.length In64: 0x%x\n", In64->write.length); + printk("GPIO.code In64: 0x%x\n", In64->GPIO.code); + + printk("GPIO.out In64: 0x%x\n", In64->GPIO.out); + printk("GPIO.mode In64: 0x%x\n", In64->GPIO.mode); + printk("readReg.offset In64: 0x%x\n", In64->readReg.offset); + printk("writeReg.offset In64: 0x%x\n", In64->writeReg.offset); + printk("writeReg.value In64: 0x%x\n", In64->writeReg.value); + printk("cancel.onByteCount In64: 0x%x\n", In64->cancel.onByteCount); + printk("reset.resetLevel In64: 0x%x\n", In64->reset.resetLevel); + printk("alloc.length In64: 0x%x\n", In64->alloc.length); + printk("alloc.processId In64: 0x%x\n", In64->alloc.processId); + printk("tcxoControl.enable In64: 0x%x\n", In64->tcxoControl.enable); +#endif +} + + + +static void putdata64_to_data32(TCgDriverStatus_32bit *Out32,TCgDriverStatus *Out64) +{ + Out32->rc = Out64->rc; + Out32->buffer.bufferPhysAddr = (unsigned int)Out64->buffer.bufferPhysAddr; + Out32->buffer.bufferAppVirtAddr = poffset; + Out32->buffer.size = Out64->buffer.size; + Out32->GPIO.code = Out64->GPIO.code; + Out32->GPIO.val = Out64->GPIO.val; + //Out32->version.buildVersion = &Out64->version.buildVersion[0]; + //Out32->version.buildNumber = &Out64->version.buildNumber[0]; + //Out32->version.buildDate = &Out64->version.buildDate[0]; + //Out32->version.buildTime = &Out64->version.buildTime[0]; + //Out32->version.buildMode = &Out64->version.buildMode[0]; + //Out32->version.buildName = &Out64->version.buildName[0]; + Out32->readReg.offset = Out64->readReg.offset; + Out32->readReg.value = Out64->readReg.value; + //Out32->cpuRevision.revisionCode = &Out64->cpuRevision.revisionCode[0]; + Out32->readRtc.year = Out64->readRtc.year; + Out32->readRtc.month = Out64->readRtc.month; + Out32->readRtc.day = Out64->readRtc.day; + Out32->readRtc.hour = Out64->readRtc.hour; + Out32->readRtc.minute = Out64->readRtc.minute; + Out32->readRtc.second = Out64->readRtc.second; + Out32->readRtc.dayInWeek = Out64->readRtc.dayInWeek; + Out32->readRtc.tick = Out64->readRtc.tick; + Out32->state.flags.terminate = Out64->state.flags.terminate; + Out32->state.flags.wait = Out64->state.flags.wait; + Out32->state.flags.overrun = Out64->state.flags.overrun; + Out32->state.flags.resume = Out64->state.flags.resume; + Out32->state.counters.interrupt.all = Out64->state.counters.interrupt.all; + Out32->state.counters.interrupt.snapStart = Out64->state.counters.interrupt.snapStart; + Out32->state.counters.interrupt.overrun = Out64->state.counters.interrupt.overrun; + Out32->state.transfer.bufferPhys = Out64->state.transfer.bufferPhys; + Out32->state.transfer.originalBuffer = (unsigned int)( Out64->state.transfer.originalBuffer); + Out32->state.transfer.byteOrder = Out64->state.transfer.byteOrder; + Out32->state.transfer.done = Out64->state.transfer.done; + Out32->state.transfer.bytes.required = Out64->state.transfer.bytes.required; + Out32->state.transfer.bytes.received = Out64->state.transfer.bytes.received; + Out32->state.transfer.blocks.required = Out64->state.transfer.blocks.required; + Out32->state.transfer.blocks.received = Out64->state.transfer.blocks.received; + Out32->state.transfer.chunks.required = Out64->state.transfer.blocks.received; + Out32->state.transfer.chunks.received = Out64->state.transfer.chunks.received; + Out32->state.transfer.chunks.active = Out64->state.transfer.chunks.active; + Out32->state.transfer.cancel.request = Out64->state.transfer.cancel.request; + Out32->state.transfer.cancel.onByte = Out64->state.transfer.cancel.onByte; + Out32->state.transfer.cancel.onChunk = Out64->state.transfer.cancel.onChunk; + //Out32->state.transfer.bufferOffset = Out64->state.transfer.bufferOffset; + Out32->state.transfer.blockSize = Out64->state.transfer.blockSize; + Out32->state.transfer.lastBlockSize = Out64->state.transfer.lastBlockSize; + Out32->state.buffer.physAddr = Out64->state.buffer.physAddr; + Out32->state.buffer.virtAddr = (unsigned int)(Out64->state.buffer.virtAddr); + Out32->state.buffer.length = Out64->state.buffer.length; + Out32->state.buffer.driverContextVirtBufferAddr = (unsigned int)(Out64->state.buffer.driverContextVirtBufferAddr); + Out32->state.constructionRc = Out64->state.constructionRc; +#if 0 + printk("Out64.readReg.offset: 0x%x\n", Out64->readReg.offset); + printk("Out64.readReg.value: 0x%x\n", Out64->readReg.value); + printk("Out32.readReg.offset: 0x%x\n", Out32->readReg.offset); + printk("Out32.readReg.value: 0x%x\n", Out32->readReg.value); + #endif +} +#if 0 +static void printdata32(TCgDriverStatus_32bit *Out32) +{ + + printk(" Out32->rc: 0x%x\n", Out32->rc); + printk(" Out32->buffer.bufferPhysAddr: 0x%x\n", Out32->buffer.bufferPhysAddr); + printk(" Out32->buffer.bufferAppVirtAddr: 0x%x\n", Out32->buffer.bufferAppVirtAddr); + printk(" Out32->buffer.size : 0x%x\n", Out32->buffer.size ); + printk(" Out32->GPIO.code : 0x%x\n", Out32->GPIO.code ); + printk(" Out32->GPIO.val: 0x%x\n", Out32->GPIO.val); + + printk(" Out32->version.buildVersion: 0x%x\n", Out32->version.buildVersion); + printk(" Out32->version.buildNumber: 0x%x\n", Out32->version.buildNumber); + printk(" Out32->version.buildDate : 0x%x\n", Out32->version.buildDate ); + printk(" Out32->version.buildTime: 0x%x\n", Out32->version.buildTime); + printk(" Out32->version.buildMode : 0x%x\n", Out32->version.buildMode ); + printk(" Out32->version.buildName: 0x%x\n", Out32->version.buildName); + + printk(" Out32->readReg.offset: 0x%x\n", Out32->readReg.offset); + printk(" Out32->readReg.value: 0x%x\n", Out32->readReg.value); + printk(" Out32->readRtc.year : 0x%x\n", Out32->readRtc.year ); + printk(" Out32->readRtc.month: 0x%x\n", Out32->readRtc.month); + printk(" Out32->readRtc.day: 0x%x\n", Out32->readRtc.day); + printk(" Out32->readRtc.hour: 0x%x\n", Out32->readRtc.hour); + printk(" Out32->readRtc.minute: 0x%x\n", Out32->readRtc.minute); + printk(" Out32->readRtc.second: 0x%x\n", Out32->readRtc.second); + printk(" Out32->readRtc.dayInWeek: 0x%x\n", Out32->readRtc.dayInWeek); + printk(" Out32->readRtc.tick: 0x%x\n", Out32->readRtc.tick); + + + + + printk(" Out32->state.flags.terminate: 0x%x\n", Out32->state.flags.terminate); + printk(" Out32->state.flags.wait: 0x%x\n", Out32->state.flags.wait); + printk(" Out32->state.flags.overrun: 0x%x\n", Out32->state.flags.overrun); + printk(" Out32->state.flags.resume: 0x%x\n", Out32->state.flags.resume); + printk(" Out32->state.counters.interrupt.all: 0x%x\n", Out32->state.counters.interrupt.all); + printk(" Out32->state.counters.interrupt.snapStart: 0x%x\n", Out32->state.counters.interrupt.snapStart); + printk(" Out32->state.counters.interrupt.overrun: 0x%x\n", Out32->state.counters.interrupt.overrun); + printk(" Out32->state.transfer.bufferPhys: 0x%x\n", Out32->state.transfer.bufferPhys); + printk(" Out32->state.transfer.originalBuffer: 0x%x\n", Out32->state.transfer.originalBuffer); + printk(" Out32->state.transfer.byteOrder: 0x%x\n", Out32->state.transfer.byteOrder); + printk(" Out32->state.transfer.done: 0x%x\n", Out32->state.transfer.done); + printk(" Out32->state.transfer.bytes.required: 0x%x\n", Out32->state.transfer.bytes.required); + printk(" Out32->state.transfer.bytes.received: 0x%x\n", Out32->state.transfer.bytes.received); + printk(" Out32->state.transfer.blocks.required: 0x%x\n", Out32->state.transfer.blocks.required); + printk(" Out32->state.transfer.blocks.received: 0x%x\n", Out32->state.transfer.blocks.received); + printk(" Out32->state.transfer.chunks.required: 0x%x\n", Out32->state.transfer.chunks.required); + printk(" Out32->state.transfer.chunks.received: 0x%x\n", Out32->state.transfer.chunks.received); + printk(" Out32->state.transfer.chunks.active: 0x%x\n", Out32->state.transfer.chunks.active); + printk(" Out32->state.transfer.cancel.request: 0x%x\n", Out32->state.transfer.cancel.request); + printk(" Out32->state.transfer.cancel.onByte: 0x%x\n", Out32->state.transfer.cancel.onByte); + printk(" Out32->state.transfer.cancel.onChunk : 0x%x\n", Out32->state.transfer.cancel.onChunk ); + printk(" Out32->state.transfer.bufferOffset: 0x%x\n", Out32->state.transfer.bufferOffset); + printk(" Out32->state.transfer.blockSize: 0x%x\n", Out32->state.transfer.blockSize); + printk(" Out32->state.transfer.lastBlockSize: 0x%x\n", Out32->state.transfer.lastBlockSize); + printk(" Out32->state.buffer.physAddr: 0x%x\n", Out32->state.buffer.physAddr); + printk(" Out32->state.buffer.virtAddr: 0x%x\n", Out32->state.buffer.virtAddr); + + printk(" Out32->state.buffer.length: 0x%x\n", Out32->state.buffer.length); + printk(" Out32->state.buffer.driverContextVirtBufferAddr: 0x%x\n", Out32->state.buffer.driverContextVirtBufferAddr); + printk(" Out32->state.constructionRc: 0x%x\n", Out32->state.constructionRc); + printk(" Out32->rc: 0x%x\n", Out32->rc); + printk(" Out32->rc: 0x%x\n", Out32->rc); + + + + + + + + + + + //Out32->cpuRevision.revisionCode = &Out64->cpuRevision.revisionCode[0]; + +} +#endif +//====================================================================== +// CGX_IOControl - Called when DeviceIOControl called +// +//static int CGX_IOControl(struct inode *inode,struct file *filp, +static long CGX_IOControl(struct file *filp, + + unsigned int cmd, unsigned long arg) +{ + DBG_FUNC_NAME("CGX_IOControl") + TCgReturnCode rc = ECgOk; + TCgDriverControl In; + TCgDriverStatus Out; + + TCgDriverControl_32bit In_32; + TCgDriverStatus_32bit Out_32; + +//printk("cmd:0x%x,arg:0x%x\n",cmd,arg); + /* DBGMSG1( "Entering...[%d]" , cmd); */ + + + // Check we can read the TCgDriverControl from User Space + if ( !access_ok( VERIFY_READ, (void __user *)arg, sizeof(TCgDriverControl_32bit) ) ) { + DBGMSG( "Returning -EFAULT 1" ); + return -EFAULT; + } + + // Check we can write the TCgDriverStatus to User Space + if ( !access_ok( VERIFY_WRITE, (void __user *)arg, sizeof(TCgDriverStatus_32bit) ) ) { + DBGMSG( "Returning -EFAULT 2" ); + return -EFAULT; + } + + if ( copy_from_user( &In_32, (void __user *)arg, sizeof(In_32) ) ) { + DBGMSG( "Returning -EFAULT 3" ); + return -EFAULT; + } + + getdata32_to_data64(&In_32,&In); + + rc = CgxDriverExecute( &DrvContext, &DrvContext.state, cmd, &In, &Out); + + putdata64_to_data32(&Out_32,&Out); + + if ( copy_to_user( (void __user *)arg, &Out_32, sizeof(Out_32) ) ) { + DBGMSG( "Returning -EFAULT 4" ); + return -EFAULT; + } + + DBGMSG1( "Returning %d", (OK(rc)) ? 0 : -ENOTTY ); + return (OK(rc)) ? 0 : -ENOTTY; + +} + + +int CGX_CompleteDrv(void) +{ + complete(&DrvContext.xferCompleted); + return 0; +} + +EXPORT_SYMBOL_GPL(CGX_CompleteDrv); + +//====================================================================== +// CGX_Fasync - Called when driver closed +// +static int CGX_Fasync( int fd, struct file *filp, int mode) +{ + return fasync_helper(fd, filp, mode, &DrvContext.async_queue); +} + +unsigned int CgxDriverCheckAllocInternalBuff(void) +{ + + if (DrvContext.xfer_buff_ptr != NULL) { + printk( "\n already alloc page \n" ); + return 0; + } + return 1; +} + + + +//====================================================================== +// CGX_Close - Called when driver closed +// +static int CGX_Close( struct inode *inode, struct file *filp) +{ +/* DBGMSG( "Entering..." ); */ + +#if 0 + //gaole add begin + int rc = 0; + + CgCoreReleaseRes(); + if (CgxDriverCheckAllocInternalBuff() == 0) + { + printk("\n gaole: close check if old page be released \n"); + + rc = CgxDriverFreeInternalBuff(NULL, 0); + + if(ECgOk != rc) + { + printk("\n gaole: close run CgxDriverFreeInternalBuff error,error code is %d \n",rc); + } + + } + + rc = CgCpuDmaStop(0); + if(ECgOk != rc) + { + printk("\n gaole: run CgCpuDmaStop error,error code is %d \n",rc); + + } + CgGpsReset(); +#endif + + CgCpuDmaDestroy(0,0); + // gaole add end + + + if (DrvContext.nNumOpens) + DrvContext.nNumOpens--; + + if ( filp->f_flags & FASYNC) { + CGX_Fasync(-1, filp, 0); /* Remove from async queue */ + } + +/* DBGMSG( "Returning 0" ); */ + return 0; +} + + +//====================================================================== +// CGX_Read - Called when driver read +// +static ssize_t CGX_Read( struct file *filp, char __user *buff, size_t count, loff_t *offp) +{ + while (DrvContext.pm_resumed == 0) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + //DBGMSG( "Waiting for resume to take place... Going to sleep\n" ); + if (wait_event_interruptible(DrvContext.resumeq, (DrvContext.pm_resumed != 0))) + return -ERESTARTSYS; + } + + /* + * Copy 1 char sizeof(*(char*)) from DrvContext.pm_resumed to buff + */ + if (put_user(DrvContext.pm_resumed, (char __user *)buff)) { + return -EFAULT; + } + + DrvContext.pm_resumed = 0; + return 1; +} + + +//====================================================================== +// CGX_Write - Called when driver written +// +static ssize_t CGX_Write( struct file *filp, const char __user *buff, size_t count, loff_t *offp) +{ + return 0; +} + + +//====================================================================== +// CGX_Poll - Called when driver select()/poll() +// +static unsigned int CGX_Poll(struct file *filp, poll_table *wait) +{ + poll_wait(filp, &DrvContext.resumeq, wait); + + if (DrvContext.pm_resumed == 'R') + return (POLLIN | POLLRDNORM); + + return 0; +} + +//====================================================================== +// CGX_Seek - Called when SetFilePtr called +// +static loff_t CGX_Seek (struct file *filp, loff_t off, int whence) +{ + return 0; +} + + + + + + +//====================================================================== +// CGX_Open - Called when driver opened +// +static int CGX_Open( struct inode *inode, struct file *filp ) +{ + + /* + * XXX-PK-XXX: Hold lock on DrvContext + */ + CgCpuDmaCreate(0,0); + +/* DBGMSG( "Entering..." ); */ + + // Count the number of opens. + DrvContext.nNumOpens++; + +/* DBGMSG( "Returning 0" ); */ + return 0; +} + + +/* + * CGX_vma_open and CGX_vma_close keep track of how many times + * the buffer is mapped, to avoid Freeing it while in use. + */ +static void CGX_vma_open(struct vm_area_struct *vma) +{ + DBG_FUNC_NAME("CGX_vma_open") + DrvContext.xfer_buff_mmapped++; + DBGMSG4("vma open [%d]: virt 0x%lx, Offs %lu, Len %lu", + DrvContext.xfer_buff_mmapped, + vma->vm_start, vma->vm_pgoff << PAGE_SHIFT, vma->vm_end - vma->vm_start ); +} + +static void CGX_vma_close(struct vm_area_struct *vma) +{ + DBG_FUNC_NAME("CGX_vma_close") +/* DBGMSG( "Entering..." ); */ + + DrvContext.xfer_buff_mmapped--; + DBGMSG1("vma close [%d]", DrvContext.xfer_buff_mmapped ); + +/* DBGMSG( "Exit" ); */ +} + +#if LINUX_VERSION_CODE >= 132634 +static int CGX_vma_nopage(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + return VM_FAULT_SIGBUS; // Remapping is not allowed ! +} +#else +static struct page *CGX_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type) +{ + return NOPAGE_SIGBUS; // Remapping is not allowed ! +} +#endif + +static struct vm_operations_struct cgx_remap_ops = { + .open = CGX_vma_open, + .close = CGX_vma_close, + #if LINUX_VERSION_CODE >= 132634 + .fault = CGX_vma_nopage, + #else + .nopage = CGX_vma_nopage, + #endif +}; + +static int CGX_Mmap(struct file *filp, struct vm_area_struct *vma) +{ + DBG_FUNC_NAME("CGX_Mmap") + int rv; + unsigned long len = (vma->vm_end - vma->vm_start); + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + unsigned long physical = __pa((void *)DrvContext.xfer_buff_ptr) + off; + + DBGMSG3( "Entering... len=%lu off=%lu DrvContext.xfer_buff_len=%lu", len, off, DrvContext.xfer_buff_len ); + + if ( len > (DrvContext.xfer_buff_len - off) ) { + DBGMSG( "Returning -EINVAL" ); + return -EINVAL; + } + +#ifdef CGCORE_ACCESS_VIA_SPI + rv = remap_pfn_range(vma, vma->vm_start, + physical >> PAGE_SHIFT, len, + (vma->vm_page_prot)); +#else + + rv = remap_pfn_range(vma, vma->vm_start, + physical >> PAGE_SHIFT, len, + pgprot_noncached(vma->vm_page_prot)); + +#endif + + + + if (rv < 0) { + DBGMSG1( "Returning %d", rv ); + return rv; + } + + vma->vm_ops = &cgx_remap_ops; + CGX_vma_open(vma); +/* DBGMSG( "Returning 0" ); */ + return 0; +} + + +#if 0 +#warning CGX_AddSysDev is needed only for debugging ! +static int CGX_AddSysDev(struct sys_device *dev) +{ + DBGMSG( "Got to CGX_AddSysDev\n" ); + return 0; +} +#endif + + +static int CGX_PMSuspend(struct device *dev, pm_message_t state) +{ + #if 0 + //DBGMSG( "Got to CGX_PMSuspend\n" ); + printk("%s\n",__func__); + //if (DrvContext.nNumOpens > 0) + if(flag_power_up == 1) + { + CgxDriverPowerDown(); + CgxDriverRFPowerDown(); + } + #endif + return 0; +} + + +static int CGX_PMResume(struct device *dev) +{ + #if 0 + //DBGMSG( "Got to CGX_PMResume\n" ); + printk("%s\n",__func__); + //if (DrvContext.nNumOpens > 0) + if(flag_power_up == 1) + { + + DrvContext.state.flags.resume = 1; + #if 0 + DrvContext.pm_resumed = 'R'; + + /* awake read()ers and poll()ers (select) */ + wake_up_interruptible(&DrvContext.resumeq); + + /* signal async readers */ + if (DrvContext.async_queue) + kill_fasync(&DrvContext.async_queue, SIGIO, POLL_IN); + #endif + CgxDriverPowerUp(); + CgxDriverRFPowerUp(); + } +#endif + return 0; +} + + + +//====================================================================== +// CGX_Init - Driver initialization function +// +struct file_operations cgx_fops = { + .owner = THIS_MODULE, + .llseek = CGX_Seek, + .read = CGX_Read, + .write = CGX_Write, + .poll = CGX_Poll, + //bxd + //.ioctl = CGX_IOControl, + .unlocked_ioctl = CGX_IOControl, + #ifdef CONFIG_COMPAT + .compat_ioctl = CGX_IOControl, + #endif + .open = CGX_Open, + .fasync = CGX_Fasync, + .release = CGX_Close, + .mmap = CGX_Mmap, +}; + +#ifdef CONFIG_OF +#ifndef CGCORE_ACCESS_VIA_SPI +struct gps_2351_addr gps_2351; +u32 gps_get_core_base(void) +{ + return gps_2351.gps_base; +} + +u32 gps_get_ahb_base(void) +{ + return gps_2351.ahb_base; +} + +u32 gps_get_irq(void) +{ + return gps_2351.irq_num; +} + +u32 gps_get_lna_gpio(void) +{ + return gps_2351.lna_gpio; +} + +#ifdef CONFIG_ARCH_SCX30G +u32 gps_get_pmu_base(void) +{ + return gps_2351.pmu_base; +} +#endif + +static int cgxdrv_gps_source_init(void) +{ + int ret; + + struct device_node *np; + struct resource res; + + np = of_find_node_by_name(NULL, "gps_2351"); + if (!np) { + printk("Can't get the gps_2351 node!\n"); + return -ENODEV; + } + printk(" find the gps_2351 node!\n"); + + ret = of_address_to_resource(np, 0, &res); + if (ret < 0) { + printk("Can't get the gps reg base!\n"); + return -EIO; + } + gps_2351.gps_base = (unsigned long)ioremap_nocache(res.start, resource_size(&res)); + printk("gps reg base is 0x%x\n", gps_2351.gps_base); + + ret = of_address_to_resource(np, 1, &res); + if (ret < 0) { + printk("Can't get the ahbreg base!\n"); + return -EIO; + } + gps_2351.ahb_base = (unsigned long)ioremap_nocache(res.start, resource_size(&res)); + printk("ahb reg base is 0x%x\n", gps_2351.ahb_base); + + #ifdef CONFIG_ARCH_SCX30G + ret = of_address_to_resource(np, 2, &res); + if (ret < 0) { + printk("Can't get the pmu base!\n"); + return -EIO; + } + gps_2351.pmu_base = (unsigned long)ioremap_nocache(res.start, resource_size(&res)); + printk("pmu_base base is 0x%x\n", gps_2351.pmu_base); + #endif + + gps_2351.irq_num = irq_of_parse_and_map(np, 0); + if (gps_2351.irq_num == 0) { + printk("Can't get the gps irq_num!\n"); + return -EIO; + } + printk(" gps_2351.gps_irq_num is %d\n", gps_2351.irq_num); + + gps_2351.lna_gpio = of_get_gpio(np, 0); + if(gps_2351.lna_gpio < 0){ + printk("fail to get gps lna gpio\n"); + } + return ret; +} +#endif +#endif +static int __init CGX_Init(void) +{ + DBG_FUNC_NAME("CGX_Init") + int rv; + dev_t devno = MKDEV(cgxdrv_major, 0); + +/* DBGMSG( "Entering..." ); */ + + DBGMSG("Initializing"); + + #ifdef CONFIG_OF + #ifndef CGCORE_ACCESS_VIA_SPI + cgxdrv_gps_source_init(); + #endif + #endif + + //bxd add for first alloc mem failed from engine + init_buff_ptr = (void *)__get_free_pages(GFP_KERNEL, 8); + if(init_buff_ptr == NULL) + printk("init_buff_ptr alloc failed\n"); + +#ifndef CGCORE_ACCESS_VIA_SPI + sprd_get_rf2351_ops(&gps_rf_ops); +#endif + +#ifdef CGCORE_ACCESS_VIA_SPI + gpsspidev_init(); +#endif + + /* Init structure */ + memset (&(DrvContext), 0, sizeof (DRVCONTEXT)); + init_waitqueue_head(&DrvContext.resumeq); + + /* Register char dev (Major can be provided at load time) */ + if (cgxdrv_major) { + rv = register_chrdev_region(devno, 1, "cgxdrv"); + printk(KERN_ERR "[CGX|%s] register_chrdev_region \r\n", __FUNCTION__); + } else { + rv = alloc_chrdev_region(&devno, 0, 1, "cgxdrv"); + cgxdrv_major = MAJOR(devno); + printk(KERN_ERR "[CGX|%s] alloc_chrdev_region, cgxdrv_major=%d \r\n", __FUNCTION__, cgxdrv_major); + } + + if (rv < 0) { + printk(KERN_ERR MODULE_NAME " Error can't get major %d\r\n", cgxdrv_major); + goto out; + } + + if ( CgxDriverConstruct(&DrvContext, &DrvContext.state) != ECgOk ) { + DBGMSG("CgxDriverConstruct Failed"); + rv = -ENOMEM; + goto out1; + } + + // Device is ready... Activate it + cdev_init(&DrvContext.cdev, &cgx_fops); + DrvContext.cdev.owner = THIS_MODULE; + DrvContext.cdev.ops = &cgx_fops; + rv = cdev_add (&DrvContext.cdev, devno, 1); + if (rv) { + // Cleanup + DBGMSG1(" Error %d adding cgxdrv device\r\n", rv); + goto out2; + } + + /* Create the device class. */ + gps_class = class_create(THIS_MODULE, "cgxdrv_class"); + if (IS_ERR(gps_class)) + { + DBGMSG(" Error: create cgxdrv class failed\r\n"); + } + + //bxd + gps_class->suspend = CGX_PMSuspend; + gps_class->resume = CGX_PMResume; + + /* register in /dev */ + gps_dev = device_create(gps_class, NULL, devno, NULL, "cgxdrv"); + if (IS_ERR(gps_dev)) + { + DBGMSG(" Error: device_create failed\r\n"); + class_destroy(gps_class); + } + + DBGMSG1(" Driver Ready... Major DevId: %d", cgxdrv_major ); + DBGMSG1(" Driver Byte order %d", CGX_DRIVER_NATIVE_BYTE_ORDER); + + goto out; + +out2: + /* + * XXX-PK-XXX: FIXME: Add CgxDriverConstruct Cleanup + * For example: free IRQs, destroy workqueues, etc. + */ +out1: + unregister_chrdev_region( devno, 1 ); +out: + return rv; +} + + +//====================================================================== +// CGX_Deinit - Driver de-initialization function +// +static void __exit CGX_Deinit(void) +{ + printk(KERN_ERR "[CGX|%s] in\r\n", __FUNCTION__); + + // Free the driver state buffer. + if (DrvContext.GpsIntr_irq != 0) + { + free_irq(DrvContext.GpsIntr_irq, NULL); + printk(KERN_ERR "free_irq GpsIntr_irq"); + } + + if (DrvContext.DataReady_irq != 0) + { + free_irq(DrvContext.DataReady_irq, NULL); + printk(KERN_ERR "free_irq DataReady_irq"); + } + + if (girq_wq) { + flush_workqueue(girq_wq); + destroy_workqueue(girq_wq); + printk(KERN_ERR "destroy_workqueue girq_wq"); + } + if (drdy_wq) { + flush_workqueue(drdy_wq); + destroy_workqueue(drdy_wq); + printk(KERN_ERR "destroy_workqueue drdy_wq"); + } + + #ifdef CGX_DRIVE_DMA_INT_GLOBAL_SYNC_OBJECT + if (drdy_completion_wq) { + printk(KERN_ERR "CGX_Deinit (1)"); + //flush_workqueue(drdy_completion_wq); //commented for debug, because this function blocks ! + //destroy_workqueue(drdy_completion_wq); + printk(KERN_ERR "CGX_Deinit (2)"); + } + #endif +#if 0 + DrvContext.state.request.terminate = TRUE; + if(DrvContext.chunk.ptr) { + BOOL boo = FreePhysMem(DrvContext.chunk.ptr); + } +#endif + printk(KERN_ERR "CGX_Deinit (3)"); + + //free_irq(TEMPLATE_CPU_DMA_IRQ, NULL); + +#ifndef CGCORE_ACCESS_VIA_SPI + sprd_put_rf2351_ops(&gps_rf_ops); +#endif + CgxDriverFreeInternalBuff(&DrvContext, 0); + + cdev_del(&DrvContext.cdev); + + device_destroy(gps_class, MKDEV(cgxdrv_major, 0)); + class_destroy(gps_class); + + unregister_chrdev_region(MKDEV(cgxdrv_major, 0), 1); +#ifdef CGCORE_ACCESS_VIA_SPI + gpsspidev_exit(); +#endif + printk(KERN_ERR "CGX_Deinit out"); +} + + +late_initcall(CGX_Init); +module_exit(CGX_Deinit); + + +MODULE_LICENSE("GPL and additional rights"); +MODULE_AUTHOR("Pablo 'merKur' Kohan <pablo@ximpo.com> - for CellGuide Ltd."); +MODULE_DESCRIPTION("CellGuide GPSense CGX3XXX/CGX5XXX GPS CoProcessor driver"); + +/** \endcond */ |
