//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuShBufferIoctl -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtuShBufferIoctl( DtuDeviceData* pDvcData, DtFileObject* pFile, DtIoctlObject* pIoctl) { DtStatus Status = DT_STATUS_OK; char* pIoctlStr; // Mnemonic string for Command UInt InReqSize = 0; // Required length of input buffer UInt OutReqSize = 0; // Required length of output buffer Int Index; DtuShBuffer* pShBuffer = NULL; DtuIoctlShBufCmdInput* pShBufCmdInput = (DtuIoctlShBufCmdInput*)pIoctl->m_pInputBuffer; InReqSize = OFFSETOF(DtuIoctlShBufCmdInput, m_Data); // Check if we can read m_Cmd if (pIoctl->m_InputBufferSize < OFFSETOF(DtuIoctlShBufCmdInput, m_Data)) return DT_STATUS_INVALID_PARAMETER; switch (pShBufCmdInput->m_Cmd) { case DTU_SH_BUF_CMD_INIT: pIoctlStr = "DTU_SH_BUF_CMD_INIT"; InReqSize += sizeof(DtuIoctlShBufCmdInitInput); // We expect an output buffer size, but will be checked later OutReqSize = 0; break; case DTU_SH_BUF_CMD_CLOSE: pIoctlStr = "DTU_HP_BUF_CMD_CLOSE"; // We expect no output buffer OutReqSize = 0; break; default: pIoctlStr = "??UNKNOWN VPDCMD CODE??"; Status = DT_STATUS_NOT_SUPPORTED; } if (DT_SUCCESS(Status)) { // Check buffer sizes if (pIoctl->m_InputBufferSize < InReqSize) { DtDbgOut(ERR, SHBUF, "%s: INPUT BUFFER TOO SMALL Size=%d Req=%d", pIoctlStr, pIoctl->m_InputBufferSize, InReqSize); return DT_STATUS_INVALID_PARAMETER; } if (pIoctl->m_OutputBufferSize < OutReqSize) { DtDbgOut(ERR, SHBUF, "%s: OUTPUT BUFFER TOO SMALL Size=%d Req=%d", pIoctlStr, pIoctl->m_OutputBufferSize, OutReqSize); return DT_STATUS_INVALID_PARAMETER; } DtDbgOut(MAX, SHBUF, "%s: In=%d (Rq=%d), Out=%d (Rq=%d)", pIoctlStr, pIoctl->m_InputBufferSize, InReqSize, pIoctl->m_OutputBufferSize, OutReqSize); } if (pShBufCmdInput->m_BufferIndex != 0) { DtDbgOut(ERR, SHBUF, "%s: OUTPUT BUFFER TOO SMALL Size=%d Req=%d", pIoctlStr, pIoctl->m_OutputBufferSize, OutReqSize); return DT_STATUS_INVALID_PARAMETER; } // The bytes written will be updated if needed. Set the default value here. pIoctl->m_OutputBufferBytesWritten = OutReqSize; // Lookup the shared buffer structure // Check if the PortIndex is from the NonIpPort Status = DtuGetNonIpPortIndex(pDvcData, pShBufCmdInput->m_PortIndex, &Index); if (!DT_SUCCESS(Status)) return DT_STATUS_NOT_FOUND; pShBuffer = &pDvcData->m_pNonIpPorts[Index].m_SharedBuffer; if (DT_SUCCESS(Status)) { switch (pShBufCmdInput->m_Cmd) { case DTU_SH_BUF_CMD_INIT: { char* pBuffer; UInt Size; DtPageList* pPageList = NULL; #if defined(WINBUILD) DtPageList PageList; PMDL pMdl; NTSTATUS NtStatus; // Retrieve MDL and virtual buffer from request object NtStatus = WdfRequestRetrieveOutputWdmMdl(pIoctl->m_WdfRequest, &pMdl); if (NtStatus != STATUS_SUCCESS) { DtDbgOut(ERR, SHBUF, "WdfRequestRetrieveOutputWdmMdl error: %08x", NtStatus); Status = DT_STATUS_OUT_OF_RESOURCES; } if (DT_SUCCESS(Status)) { pBuffer = MmGetMdlVirtualAddress(pMdl); if (pBuffer == NULL) { DtDbgOut(ERR, SHBUF, "DTU_SH_BUF_CMD_INIT: DT_STATUS_OUT_OF_MEMORY"); Status = DT_STATUS_OUT_OF_MEMORY; } Size = MmGetMdlByteCount(pMdl); // Build pagelist object for user space buffer pPageList = &PageList; pPageList->m_BufType = DT_BUFTYPE_USER; pPageList->m_OwnedByOs = TRUE; pPageList->m_pMdl = pMdl; pPageList->m_pVirtualKernel = NULL; } #else // LINBUILD Size = (UInt)pShBufCmdInput->m_Data.m_Init.m_BufferSize; #if defined(LIN32) pBuffer = (char*)(UInt32)pShBufCmdInput->m_Data.m_Init.m_BufferAddr; #else pBuffer = (char*)(UInt64)pShBufCmdInput->m_Data.m_Init.m_BufferAddr; #endif #endif if (DT_SUCCESS(Status)) { Status = DtuShBufferInit(pShBufCmdInput, pFile, pPageList, pBuffer, Size, DT_BUFTYPE_USER, pShBuffer); if (!DT_SUCCESS(Status)) DtDbgOut(ERR, SHBUF, "DtuShBufferInit failed"); } } break; case DTU_SH_BUF_CMD_CLOSE: if (pDvcData->m_pNonIpPorts!=NULL && pDvcData->m_pNonIpPorts[0].m_State==DTU3_STATE_READ351) { pDvcData->m_pNonIpPorts[0].m_NextState = DTU3_STATE_DET_VIDSTD; DtEventSet(&pDvcData->m_pNonIpPorts[0].m_StateChanged); DtEventWait(&pDvcData->m_pNonIpPorts[0].m_StateChangeCmpl, -1); } else if (pDvcData->m_pNonIpPorts!=NULL && pDvcData->m_pNonIpPorts[0].m_State==DTU3_STATE_WRITE315) { pDvcData->m_pNonIpPorts[0].m_NextState = DTU3_STATE_IDLE; DtEventSet(&pDvcData->m_pNonIpPorts[0].m_StateChanged); DtEventWait(&pDvcData->m_pNonIpPorts[0].m_StateChangeCmpl, -1); } Status = DtuShBufferClose(pShBuffer); break; default: Status = DT_STATUS_NOT_SUPPORTED; } } // If we failed, no data has te be copied to user space if (!DT_SUCCESS(Status)) { pIoctl->m_OutputBufferBytesWritten = 0; if (Status == DT_STATUS_NOT_SUPPORTED) DtDbgOut(MIN, SHBUF, "ShBufCmd=0x%x: NOT SUPPORTED", pShBufCmdInput->m_Cmd); } return Status; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuEventsGet -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // // Return a pending event. This functions blocks if no events are pending. // DtStatus DtuEventsGet( DtuDeviceData* pDvcData, DtFileObject* pFile, UInt* pEventType, UInt* pValue1, UInt* pValue2, Bool Wait) { DtStatus Result = DT_STATUS_OK; DtuEvents* pDtuEvents; if (pFile==NULL || pEventType==NULL || pValue1==NULL || pValue2==NULL) return DT_STATUS_INVALID_PARAMETER; // Get corresponding events object pDtuEvents = DtuEventsGetEventsObject(pDvcData, pFile); if (pDtuEvents == NULL) Result = DT_STATUS_NOT_FOUND; if (DT_SUCCESS(Result)) { DtEventReset(&pDtuEvents->m_PendingEvent); if (Wait && pDtuEvents->m_NumPendingEvents==0 && !pDtuEvents->m_CancelInProgress) { DtDbgOut(MAX, EVENTS, "Waiting for event"); // Wait for event to be triggered DtEventWait(&pDtuEvents->m_PendingEvent, -1); } // The next request will be rejected by the IoCtl function, so we can reset // the Cancel state here. if (pDtuEvents->m_CancelInProgress) Result = DT_STATUS_CANCELLED; pDtuEvents->m_CancelInProgress = FALSE; DtSpinLockAcquire(&pDtuEvents->m_Lock); // Return pending events if (pDtuEvents->m_NumPendingEvents != 0) { *pEventType = pDtuEvents->m_PendingEvents[0].m_EventType; *pValue1 = pDtuEvents->m_PendingEvents[0].m_EventValue1; *pValue2 = pDtuEvents->m_PendingEvents[0].m_EventValue2; DtDbgOut(MAX, EVENTS, "Event #%d. Type: %d, Value1: %d, Value2: %d", pDtuEvents->m_NumPendingEvents, *pEventType, *pValue1, *pValue2); pDtuEvents->m_NumPendingEvents--; if (pDtuEvents->m_NumPendingEvents != 0) { // Remove the old event DtMemMove(&pDtuEvents->m_PendingEvents[0], &pDtuEvents->m_PendingEvents[1], sizeof(DtuEvent) * pDtuEvents->m_NumPendingEvents); } } else { *pEventType = 0; *pValue1 = 0; *pValue2 = 0; if (Result == DT_STATUS_OK) Result = DT_STATUS_REQUEUE; // No pending events DtDbgOut(MAX, EVENTS, "Event #%d. No event", pDtuEvents->m_NumPendingEvents); } DtSpinLockRelease(&pDtuEvents->m_Lock); // Decrement refcount DtuEventsUnrefEventsObject(pDvcData, pDtuEvents); } return Result; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaUartWrite -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtaUartRead( DtaUartPort* pUart, UInt8* pBuf, Int BytesToRead, Int Timeout, Int* pNumBytesRead) { DtStatus Status = DT_STATUS_OK; Int NumBytesAvail, NumCanRead, FifoSize, i; Int Idx = 0; volatile UInt8* pFwbRegs = pUart->m_pFwbRegs; #ifdef WINBUILD LARGE_INTEGER StartTime, CurTime; #else struct timespec StartTime, CurTime; #endif Int TimeElapsed; Int OrigTimeout = Timeout; *pNumBytesRead = 0; // Check timeout if (Timeout < -1) return DT_STATUS_INVALID_PARAMETER; #ifdef WINBUILD KeQueryTickCount(&StartTime); #else getnstimeofday(&StartTime); #endif FifoSize = DtaFwbRegRead(pFwbRegs, &pUart->m_pFwbUart->Config_RxFifoSize); NumBytesAvail = DtaFwbRegRead(pFwbRegs, &pUart->m_pFwbUart->RxStat_FifoLoad); do { NumCanRead = (BytesToRead < NumBytesAvail) ? BytesToRead : NumBytesAvail; // Read available data from FIFO for (i=0; i<NumCanRead; i++) pBuf[Idx++] = (UInt8)DtaFwbRegRead(pFwbRegs, &pUart->m_pFwbUart->RxData); BytesToRead -= NumCanRead; *pNumBytesRead += NumCanRead; // Ready? if (BytesToRead==0 || Timeout==0) break; // Wait for data available event DtEventReset(&pUart->m_RxEvent); if (BytesToRead < FifoSize/2) DtaFwbRegWrite(pFwbRegs, &pUart->m_pFwbUart->RxCtrl_DataIdleIntEnable, 1); else DtaFwbRegWrite(pFwbRegs, &pUart->m_pFwbUart->RxCtrl_HalfFullIntEnable, 1); Status = DtEventWait(&pUart->m_RxEvent, Timeout); if (!DT_SUCCESS(Status)) break; // Check how much is availble now NumBytesAvail = DtaFwbRegRead(pFwbRegs, &pUart->m_pFwbUart->RxStat_FifoLoad); if (Timeout == -1) continue; #ifdef WINBUILD KeQueryTickCount(&CurTime); TimeElapsed = (Int)((CurTime.QuadPart - StartTime.QuadPart)*KeQueryTimeIncrement() / 10000); #else getnstimeofday(&CurTime); TimeElapsed = DtDivide64(((CurTime.tv_sec-StartTime.tv_sec)*1000000000LL + (CurTime.tv_nsec-StartTime.tv_nsec)), 1000000, NULL); #endif Timeout = OrigTimeout - TimeElapsed; } while (Timeout > 0); // Reception ready DtaFwbRegWrite(pFwbRegs, &pUart->m_pFwbUart->RxCtrl_DataIdleIntEnable, 0); DtaFwbRegWrite(pFwbRegs, &pUart->m_pFwbUart->RxCtrl_HalfFullIntEnable, 0); // A timeout is not an error in this case. Let userspace deal with the fact that // the read operation is not complete. if (Status == DT_STATUS_TIMEOUT) Status = DT_STATUS_OK; return Status; }