NvError NvEcPowerSuspend( NvEcPowerState PowerState) { NvError e = NvSuccess; NvEcPrivState *ec = &g_ec; NvOsMutexLock(ec->mutex); // Call transport's power off only if it's in ON state if (ec->powerState == NV_TRUE) { // Perform pre-suspend EC operations NV_CHECK_ERROR_CLEANUP( NvEcPrivPowerSuspendHook(ec->hEc, PowerState) ); // Enter low power state ec->EnterLowPowerState = NV_TRUE; // Signal priv thread to get ready for power suspend. NvOsSemaphoreSignal(ec->sema); // Wait till priv thread is ready for power suspend. NvOsSemaphoreWait(ec->LowPowerEntrySema); e = NvEcTransportPowerSuspend(ec->transport); ec->powerState = NV_FALSE; } fail: NvOsMutexUnlock(ec->mutex); return e; }
static void PmuThread(void* args) { NvRmPmu* pPmu = (NvRmPmu*)args; for (;;) { NvOsSemaphoreWait(pPmu->hSemaphore); if (pPmu->AbortThread) { break; } NvOsMutexLock(pPmu->hMutex); if (pPmu->IntrMasked) { NvOsMutexUnlock(pPmu->hMutex); continue; } NvOdmPmuInterruptHandler(pPmu->hOdmPmu); NvOsMutexUnlock(pPmu->hMutex); if (pPmu->hInterrupt) NvRmInterruptDone(pPmu->hInterrupt); } }
/* * Thread to send no-op commands to EC */ static void NvEcPrivPingThread(void *args) { NvError NvStatus = NvError_Success; NvEcRequest req; NvEcResponse resp; NvEcPrivState *ec = (NvEcPrivState *)args; //Nvidia_patch_ for_ deviceLockup_and_audio_lost_issue[START] //set_freezable_with_signal(); set_freezable(); //Nvidia_patch_ for_ deviceLockup_and_audio_lost_issue[END] for (;;) { NvOsSemaphoreWait(ec->hPingSema); if (ec->exitPingThread) break; // send no-op commands DISP_MESSAGE(("NvEcPrivPingThread: Sending no-op command\n")); req.PacketType = NvEcPacketType_Request; req.RequestType = NvEcRequestResponseType_Control; req.RequestSubtype = (NvEcRequestResponseSubtype) NvEcControlSubtype_NoOperation; req.NumPayloadBytes = 0; NvStatus = NvEcSendRequest( ec->hEc, &req, &resp, sizeof(req), sizeof(resp)); if (NvStatus != NvError_Success) DISP_MESSAGE(("NvEcPrivPingThread: no-op command send fail\n")); if (resp.Status != NvEcStatus_Success) DISP_MESSAGE(("NvEcPrivPingThread: no-op command fail\n")); DISP_MESSAGE(("NvEcPrivPingThread: no-op command sent\n")); ec->IsEcActive = NV_FALSE; } }
void NvBatteryEventHandlerThread(void *args) { NvU8 BatteryState = 0, BatteryEvent = 0; for (;;) { NvOsSemaphoreWait(batt_dev->hOdmSemaphore); if (batt_dev->exitThread) break; if (!batt_dev->hOdmBattDev) continue; NvOdmBatteryGetBatteryStatus(batt_dev->hOdmBattDev, NvOdmBatteryInst_Main, &BatteryState); NvOdmBatteryGetEvent(batt_dev->hOdmBattDev, &BatteryEvent); NvOsDebugPrintf("ec_rs BatteryEvent = 0x%x\n", BatteryEvent); if ((BatteryState == NVODM_BATTERY_STATUS_UNKNOWN) || (BatteryEvent == NvOdmBatteryEventType_Num)) { /* Do nothing */ } else { //if (BatteryEvent & NvOdmBatteryEventType_RemainingCapacityAlarm) { if (BatteryEvent & NvOdmBatteryEventType_LowBatteryIntr) { //Daniel 20100701, just force off while receive LOW_BAT# interrupt(not low capacity alarm). //if (BatteryState == (NVODM_BATTERY_STATUS_CRITICAL | // NVODM_BATTERY_STATUS_VERY_CRITICAL | // NVODM_BATTERY_STATUS_DISCHARGING)) { // pr_info("nvec_battery:calling kernel_power_off...\n"); NvOsDebugPrintf("ec_rs batt low battery interrupt.\r\n"); // kernel_power_off(); //} } else { /* Update the battery and power supply info for other events */ power_supply_changed(&tegra_power_supplies[NvPowerSupply_TypeBattery]); power_supply_changed(&tegra_power_supplies[NvPowerSupply_TypeAC]); } } } }
NvError NvEcSendRequest( NvEcHandle hEc, NvEcRequest *pRequest, NvEcResponse *pResponse, NvU32 RequestSize, NvU32 ResponseSize) { NvEcPrivState *ec; NvError e = NvSuccess; NvEcRequestNode *requestNode = NULL; NvEcResponseNode *responseNode = NULL; NvOsSemaphoreHandle requestSema = NULL; NvOsSemaphoreHandle responseSema = NULL; NV_ASSERT( pRequest ); NV_ASSERT( hEc ); if ( (RequestSize > sizeof(NvEcRequest)) || (ResponseSize > sizeof(NvEcResponse)) ) return NvError_InvalidSize; ec = hEc->ec; requestNode = NvOsAlloc(sizeof(NvEcRequestNode)); if ( NULL == requestNode ) { e = NvError_InsufficientMemory; goto fail; } NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &requestSema, 0 ) ); if ( pResponse ) { responseNode = NvOsAlloc(sizeof(NvEcResponseNode)); if ( NULL == responseNode ) { e = NvError_InsufficientMemory; goto fail; } NV_CHECK_ERROR_CLEANUP( NvOsSemaphoreCreate( &responseSema, 0 ) ); } ec->IsEcActive = NV_TRUE; // request end-queue. Timeout set to infinite until request sent. NvOsMemset( requestNode, 0, sizeof(NvEcRequestNode) ); pRequest->RequestorTag = hEc->tag; // assigned tag here DISP_MESSAGE(("NvEcSendRequest:pRequest->RequestorTag=0x%x\n", pRequest->RequestorTag)); NvOsMemcpy(&requestNode->request, pRequest, RequestSize); requestNode->tag = hEc->tag; DISP_MESSAGE(("NvEcSendRequest:requestNode->tag=0x%x\n", requestNode->tag)); requestNode->sema = requestSema; requestNode->timeout = NV_WAIT_INFINITE; requestNode->completed = NV_FALSE; requestNode->size = RequestSize; NvOsMutexLock( ec->requestMutex ); NVEC_ENQ( ec->request, requestNode ); DISP_MESSAGE(("\r\nSendReq ec->requestBegin=0x%x", ec->requestBegin)); NvOsMutexUnlock( ec->requestMutex ); // response en-queue. Timeout set to infinite until request completes. if ( pResponse ) { NvOsMemset( responseNode, 0, sizeof(NvEcResponseNode) ); requestNode->responseNode = responseNode; // association between responseNode->requestNode = requestNode; // request & response responseNode->sema = responseSema; responseNode->timeout = NV_WAIT_INFINITE; responseNode->tag = hEc->tag; DISP_MESSAGE(("NvEcSendRequest:responseNode->tag=0x%x\n", responseNode->tag)); responseNode->size = ResponseSize; NvOsMutexLock( ec->responseMutex ); NVEC_ENQ( ec->response, responseNode ); DISP_MESSAGE(("\r\nSendReq ec->responseBegin=0x%x", ec->responseBegin)); NvOsMutexUnlock( ec->responseMutex ); } NvOsMutexLock( ec->mutex ); if ( !ec->thread ) NvEcPrivThreadCreate( ec ); NvOsMutexUnlock( ec->mutex ); // Trigger EcPrivThread NvOsSemaphoreSignal( ec->sema ); DISP_MESSAGE(("\r\nSendReq requestNode=0x%x, requestNode->responseNode=0x%x", requestNode, requestNode->responseNode)); // Wait on Request returns NvOsSemaphoreWait( requestSema ); DISP_MESSAGE(("\r\nSendReq Out of req sema")); e = requestNode->status; if ( NvSuccess != e ) { NvEcResponseNode *t = NULL, *p = NULL; // de-queue responseNode too !!!! NvOsMutexLock( ec->responseMutex ); NVEC_REMOVE_FROM_Q( ec->response, responseNode, t, p ); DISP_MESSAGE(("\r\nSendReq responseBegin=0x%x", ec->responseBegin)); NvOsMutexUnlock( ec->responseMutex ); goto fail; } if ( pResponse ) { // Wait on Response returns NvOsSemaphoreWait( responseSema ); DISP_MESSAGE(("\r\nSendReq Out of resp sema")); NV_CHECK_ERROR_CLEANUP( responseNode->status ); NvOsMemcpy(pResponse, &responseNode->response, ResponseSize); } // if successful, nodes should be de-queue already but not freed yet fail: NvOsSemaphoreDestroy( requestSema ); NvOsSemaphoreDestroy( responseSema ); DISP_MESSAGE(("\r\nSendReq Freeing requestNode=0x%x, responseNode=0x%x", requestNode, responseNode)); NvOsFree( requestNode ); NvOsFree( responseNode ); return e; }
/* * Always use one EcPrivThread-global clock/time for timeout calculations */ static void NvEcPrivThread( void * args ) { NvEcPrivState *ec = (NvEcPrivState *)args; NvU32 t, timeout = NV_WAIT_INFINITE; NvU32 tStatus = 0; NvError wait = NvSuccess; NvError e; while( !ec->exitThread ) { #if ENABLE_TIMEOUT if ( timeout ) wait = NvOsSemaphoreWaitTimeout( ec->sema, timeout ); #else NvOsSemaphoreWait( ec->sema ); wait = NvSuccess; #endif #if ENABLE_FAKE_TIMEOUT_TEST t = ec->lastTime + 0x200; #else t = NvOsGetTimeMS(); #endif ec->timeDiff = t - ec->lastTime; ec->lastTime = t; // update last timer value if ( !timeout || (wait == NvError_Timeout) ) { // timeout case NvEcPrivProcessTimeout( ec ); } // look for any pending packets tStatus = NvEcTransportQueryStatus( ec->transport ); e = NvSuccess; /* * SEND_COMPLETE event must be processed before RESPONSE_RECEIVE_COMPLETE * event as SEND_COMPLETE event schedules timeout for RESPONSE_RECEIVE event. */ if ( tStatus & (NVEC_TRANSPORT_STATUS_SEND_COMPLETE | NVEC_TRANSPORT_STATUS_SEND_ERROR) ) { NvEcPrivProcessPostSendRequest( ec, (tStatus & NVEC_TRANSPORT_STATUS_SEND_COMPLETE) ? NvSuccess : NvError_I2cWriteFailed ); } if ( tStatus & (NVEC_TRANSPORT_STATUS_RESPONSE_RECEIVE_ERROR | NVEC_TRANSPORT_STATUS_RESPONSE_RECEIVE_COMPLETE) ) { e = (tStatus & NVEC_TRANSPORT_STATUS_RESPONSE_RECEIVE_COMPLETE) ? NvSuccess : NvError_I2cReadFailed; e = NvEcPrivProcessReceiveResponse( ec, e ); // return ignored. Could be spurious response. } if ( tStatus & (NVEC_TRANSPORT_STATUS_EVENT_RECEIVE_ERROR | NVEC_TRANSPORT_STATUS_EVENT_RECEIVE_COMPLETE) ) { e = (tStatus & NVEC_TRANSPORT_STATUS_EVENT_RECEIVE_COMPLETE) ? NvSuccess : NvError_I2cReadFailed; e = NvEcPrivProcessReceiveEvent( ec, e ); // return ignored. Could be spurious event. } if ( tStatus & NVEC_TRANSPORT_STATUS_EVENT_PACKET_MAX_NACK ) { // signal the ping thread to send a ping command since max // number of nacks have been sent to the EC if (ec->hPingSema) { NvOsSemaphoreSignal(ec->hPingSema); } } // send request whenever possible if ( (ec->timeout[NVEC_IDX_REQUEST] == NV_WAIT_INFINITE) && (ec->EnterLowPowerState == NV_FALSE) ) NvEcPrivProcessSendRequest( ec ); #if ENABLE_TIMEOUT timeout = NvEcPrivUpdateActualTimeout( ec ); #endif if (ec->EnterLowPowerState) { // This code assumes that EC is already in kept in sleep mode by // either shim or top level code. And there will not be any activity // going on SM bus. if (ec->timeout[NVEC_IDX_REQUEST] != NV_WAIT_INFINITE) { NvOsDebugPrintf("\r\nNvEc has active requests during suspend. " "It shouldn't have. check it."); } // No active request is pending. Enter into low power state. // Signal power suspend API to enter into suspend mode. NvOsSemaphoreSignal(ec->LowPowerEntrySema); // Wait till power resume API signals resume operation. NvOsSemaphoreWait(ec->LowPowerExitSema); // Update the timeouts for the active responses, which are scheduled // to receive before system entering into suspend. #if ENABLE_TIMEOUT NvEcPrivResetActiveRequestResponseTimeouts( ec ); timeout = NvEcPrivUpdateActualTimeout( ec ); #endif // ENABLE_TIMEOUT } } }
static void tegra_audiofx_notifier_thread(void *arg) { struct tegra_audio_data *audio_context = (struct tegra_audio_data *)arg; FxNotifier *m_FxNotifier = (FxNotifier*)&audio_context->m_FxNotifier; NvError e; int retry = 0; NvU32 messageSize; NvAudioFxMessage* message = (NvAudioFxMessage*)m_FxNotifier->RcvMessageBuffer; while (retry < 5) { e = NvRmTransportConnect(m_FxNotifier->hTransport, 5000); if (e == NvSuccess) break; retry++; } if (e != NvSuccess) { snd_printk(KERN_ERR "NvRmTransportConnect failed!\n"); m_FxNotifier->Connected = 0; goto EXIT; } m_FxNotifier->Connected = 1; while (1) { NvOsSemaphoreWait(m_FxNotifier->hTransportSemaphore); if (m_FxNotifier->Exit) { break; } e = NvRmTransportRecvMsg(m_FxNotifier->hTransport, message, 256, &messageSize); if (e == NvSuccess) { switch (message->Event) { case NvAudioFxEventBufferDone:{ NvAudioFxBufferDoneMessage* bdm = (NvAudioFxBufferDoneMessage*)message; struct pcm_runtime_data* prtd = (struct pcm_runtime_data*)bdm->m.pContext; up(&prtd->buf_done_sem); } break; case NvAudioFxEventEndOfStream: break; case NvAudioFxEventStateChange:{ NvAudioFxStateChangeMessage* scm = (NvAudioFxStateChangeMessage*)message; struct pcm_runtime_data* prtd = (struct pcm_runtime_data*)scm->m.pContext; up(&prtd->stop_done_sem); } break; case NvAudioFxEventControlChange:{ NvAudioFxControlChangeMessage* ccm = (NvAudioFxControlChangeMessage*)message; if (message->hFx == (NvAudioFxHandle)audio_context->mi2s1) { if (ccm->Property == NvAudioFxIoProperty_OutputAvailable) { NvAudioFxIoDeviceControlChangeMessage* iccm = (NvAudioFxIoDeviceControlChangeMessage*)message; audio_context->mi2s1_device_available = iccm->IoDevice; tegra_audiofx_route(audio_context); } } else if (message->hFx == (NvAudioFxHandle)audio_context->mroute) { if (ccm->Property == NvAudioFxIoProperty_OutputAvailable) { NvAudioFxIoDeviceControlChangeMessage* iccm = (NvAudioFxIoDeviceControlChangeMessage*)message; audio_context->mspdif_device_available = iccm->IoDevice; tegra_audiofx_route(audio_context); } } } break; default: pr_debug("Unhandled event 0x%08x\n", message->Event); break; } } } EXIT: return; }
static void AlsaTransportServiceThread(void *arg) { NvError status = NvSuccess; static NvFxTransportMessageResultBuffer in; NvU32 messageSize = 0; int retry = 0; #define transport_complete(comp) \ complete((struct completion*)comp); while (retry < 5 ) { status = NvRmTransportConnect(atrans->hRmTransport, TEGRA_TRANSPORT_CONNECT_TIMEOUT); if (status == NvSuccess) break; retry++; } if (status) { snd_printk(KERN_ERR "AlsaTransportServiceThread: Failed to \ connect to remote end. Giving up ! \n"); atrans->TransportConnected = 0; return; } atrans->TransportConnected = 1; while (!atrans->ShutDown) { NvOsSemaphoreWait(atrans->hServiceSema); if (atrans->ShutDown) break; status = NvRmTransportRecvMsg(atrans->hRmTransport, &in, sizeof(NvFxTransportMessageResultBuffer), &messageSize); if (status == NvSuccess) { switch (in.Message.Message) { case NVFXTRANSPORT_MESSAGE_MIXER_OPEN: { *in.MixerOpen.phMixer = in.MixerOpen.hMixer; // 20110223, , media server restart 2 [start] *in.MixerOpen.pReturnError = in.MixerOpen.ReturnError; // 20110223, , media server restart 2 [end] transport_complete(in.MixerOpen.pPrivateData); } break; case NVFXTRANSPORT_MESSAGE_MIXER_CLOSE: { transport_complete(in.MixerClose.pPrivateData); } break; case NVFXTRANSPORT_MESSAGE_CREATE_OBJECT: { *in.CreateObject.phObject = in.CreateObject.hObject; transport_complete(in.CreateObject.pPrivateData); } break; case NVFXTRANSPORT_MESSAGE_DESTROY_OBJECT: { transport_complete(in.DestroyObject.pPrivateData); } break; case NVFXTRANSPORT_MESSAGE_MAP_BUFFER: { *in.MapBuffer.phMixBuffer = in.MapBuffer.hMixBuffer; transport_complete(in.MapBuffer.pPrivateData); } break; case NVFXTRANSPORT_MESSAGE_UNMAP_BUFFER: { transport_complete(in.UnmapBuffer.pPrivateData); } break; case NVFXTRANSPORT_MESSAGE_GET_PROPERTY: { *in.GetProperty.pReturnError = in.GetProperty.ReturnError; if (in.GetProperty.ReturnError == NvSuccess) { NvOsMemcpy(in.GetProperty.pProperty, in.GetProperty.PropertyData, in.GetProperty.Size); } transport_complete(in.GetProperty.pPrivateData); } break; case NVFXTRANSPORT_MESSAGE_SET_PROPERTY: { *in.SetProperty.pReturnError = in.SetProperty.ReturnError; transport_complete(in.SetProperty.pPrivateData); } break; case NVFXTRANSPORT_MESSAGE_STREAM_ADD_BUFFER: { *in.StreamAddBuffer.pReturnError = in.StreamAddBuffer.ReturnError; transport_complete(in.StreamAddBuffer.pPrivateData); } break; default: break; } } } }
void NvOdmOsSemaphoreWait(NvOdmOsSemaphoreHandle semaphore) { NvOsSemaphoreWait((NvOsSemaphoreHandle)semaphore); }