//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuRead -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtuRead( DtuDeviceData* pDvcData, Int PortIndex, UInt8* pBuf, Int NumToRead, Int* pNumRead) { DtStatus Status = DT_STATUS_OK; UInt8* pTempBuf = NULL; Int TempBufWrIndex = 0; Int TempBufRdIndex = 0; Int NonIpPortIndex; DtuNonIpPort* pNonIpPort; Int BytesLeft = NumToRead; Int BufIndex = 0; Int NumCopy = 0; // Get pipe for reading data Int Pipe = pDvcData->m_EzUsb.m_ReadPipe; // Nothing read yet *pNumRead = 0; DtDbgOut(MAX, RDWR, "Entry: pBuf=%p, NumToRead=%d", pBuf, NumToRead); // Check if the PortIndex is from the NonIpPort Status = DtuGetNonIpPortIndex(pDvcData, PortIndex, &NonIpPortIndex); if (!DT_SUCCESS(Status)) return Status; pNonIpPort = &pDvcData->m_pNonIpPorts[NonIpPortIndex]; // Simple checks if (NumToRead == 0) return DT_STATUS_OK; if (pBuf == NULL) return DT_STATUS_INVALID_PARAMETER; // Get temporary buffer pTempBuf = pNonIpPort->m_pTempBuf; TempBufWrIndex = pNonIpPort->m_TempBufWrIndex; TempBufRdIndex = pNonIpPort->m_TempBufRdIndex; DtDbgOut(MAX, RDWR, "NumToRead=%d, BytesLeft:%d, TempLoad=%d", NumToRead, BytesLeft, TempBufWrIndex - TempBufRdIndex); //-.-.-.-.-.-.-.-.-.-.- First check for data already pre-fetched -.-.-.-.-.-.-.-.-.-.- if (TempBufRdIndex > 0) { // Determine how much we can copy from temporary buffer Int NumInTempBuf = TempBufWrIndex - TempBufRdIndex; NumCopy = (NumInTempBuf > NumToRead) ? NumToRead : NumInTempBuf; // Copy from temporary buffer to user buffer DtMemCopyToUserBuf(&pBuf[BufIndex], &pTempBuf[TempBufRdIndex], NumCopy); // Update counters TempBufRdIndex += NumCopy; BytesLeft -= NumCopy; BufIndex += NumCopy; *pNumRead += NumCopy; DtDbgOut(MAX, RDWR, "NumCopy=%d, BytesLeft:%d, TempLoad=%d", NumCopy, BytesLeft, TempBufWrIndex-TempBufRdIndex); } // Temporary buffer empty? if (TempBufRdIndex==TempBufWrIndex) { // Reset indices, so we don't need a wraparround TempBufRdIndex = TempBufWrIndex = 0; } //.-.-.-.-.-.-.-.-.- Directly copy multiples of DTU_BULK_TRANSFER_ALIGN -.-.-.-.-.-.-.-.-. while (DT_SUCCESS(Status) && BytesLeft>=DTU_BULK_TRANSFER_ALIGN) { if (BytesLeft>=DTU_BULK_PACKETSIZE) // Copy DTU_BULK_PACKETSIZE bytes directly NumCopy = DTU_BULK_PACKETSIZE; else if (BytesLeft%DTU_BULK_TRANSFER_ALIGN == 0) // Bytes left is multiple of DTU_BULK_TRANSFER_ALIGN copy it directly NumCopy = BytesLeft; else // Copy the rest via temporary buffer break; // Read data #ifdef LINBUILD // For Linux, we have to read from a temp. buffer. We can not read from // the user buffer directly Status = DtUsbPipeRead(&pDvcData->m_Device, NULL, Pipe, pTempBuf, NumCopy, MAX_USB_RW_TIMEOUT); DtMemCopyToUserBuf(&pBuf[BufIndex], pTempBuf, NumCopy); #else Status = DtUsbPipeRead(&pDvcData->m_Device, NULL, Pipe, &pBuf[BufIndex], NumCopy, MAX_USB_RW_TIMEOUT); #endif // Update counters BytesLeft -= NumCopy; BufIndex += NumCopy; *pNumRead += NumCopy; DtDbgOut(MAX, RDWR, "NumCopy=%d, BytesLeft:%d", NumCopy, BytesLeft); } //.-.-.-.-.-.-.-.-.- Copy the remaining bytes via temporary buffer -.-.-.-.-.-.-.-.-. if (DT_SUCCESS(Status) && BytesLeft>0) { Int NumToTemp; DT_ASSERT(TempBufRdIndex==0 && TempBufWrIndex==0); // Copy a multiple of DTU_BULK_TRANSFER_ALIGN NumToTemp = ((BytesLeft + DTU_BULK_TRANSFER_ALIGN-1)/DTU_BULK_TRANSFER_ALIGN) * DTU_BULK_TRANSFER_ALIGN; // Read data for temporary buffer Status = DtUsbPipeRead(&pDvcData->m_Device, NULL, Pipe, pTempBuf, NumToTemp, MAX_USB_RW_TIMEOUT); // Copy remaining bytes from temporary buffer to user buffer NumCopy = BytesLeft; DtMemCopyToUserBuf(&pBuf[BufIndex], pTempBuf, NumCopy); // Update indices and counters TempBufWrIndex = NumToTemp; TempBufRdIndex = NumCopy; BytesLeft -= NumCopy; BufIndex += NumCopy; *pNumRead += NumCopy; DtDbgOut(MAX, RDWR, "NumCopy=%d, BytesLeft:%d", NumCopy, BytesLeft); } // Save temporary buffer indices pNonIpPort->m_TempBufWrIndex = TempBufWrIndex; pNonIpPort->m_TempBufRdIndex = TempBufRdIndex; DtDbgOut(MAX, RDWR, "Exit: pBuf[0]: %d, BytesLeft:%d, TempLoad=%d",pBuf[0], BytesLeft, TempBufWrIndex-TempBufRdIndex); return Status; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- 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; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuWrite -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtuWrite( DtuDeviceData* pDvcData, Int PortIndex, UInt8* pBuf, Int NumToWrite) { DtStatus Status = DT_STATUS_OK; UInt8* pTempBuf = NULL; Int TempBufWrIndex = 0; Int TempBufRdIndex = 0; Int NonIpPortIndex; DtuNonIpPort* pNonIpPort; Int BytesLeft = NumToWrite; Int BufIndex = 0; Int NumCopy = 0; // Get pipe for writing data Int Pipe = pDvcData->m_EzUsb.m_WritePipe; DtDbgOut(MAX, RDWR, "Entry: pBuf=%p, NumToWrite=%d", pBuf, NumToWrite); // Check if the PortIndex is from the NonIpPort Status = DtuGetNonIpPortIndex(pDvcData, PortIndex, &NonIpPortIndex); if (!DT_SUCCESS(Status)) return Status; pNonIpPort = &pDvcData->m_pNonIpPorts[NonIpPortIndex]; // Simple checks if (NumToWrite == 0) return DT_STATUS_OK; if (pBuf == NULL) return DT_STATUS_INVALID_PARAMETER; // Get temporary buffer pTempBuf = pNonIpPort->m_pTempBuf; TempBufWrIndex = pNonIpPort->m_TempBufWrIndex; TempBufRdIndex = pNonIpPort->m_TempBufRdIndex; DT_ASSERT(TempBufRdIndex==0); DtDbgOut(MAX, RDWR, "NumToWrite=%d, BytesLeft:%d, TempLoad=%d", NumToWrite, BytesLeft, TempBufWrIndex ); //-.-.-.-.-.-.-.-.-.-.-.-.- Check for minimum transfer size -.-.-.-.-.-.-.-.-.-.-.-.-. // First transfer data from internal buffer if (TempBufWrIndex>0 && (TempBufWrIndex+NumToWrite)>=DTU_BULK_TRANSFER_ALIGN) { // Determine maximum to copy in TempBuf such that TempBuf is full or // filled with a multiple of DTU_BULK_TRANSFER_ALIGN bytes if ((TempBufWrIndex + NumToWrite) >= DTU_BULK_PACKETSIZE) NumCopy = DTU_BULK_PACKETSIZE - TempBufWrIndex; else NumCopy = NumToWrite - (TempBufWrIndex+NumToWrite)%DTU_BULK_TRANSFER_ALIGN; DtMemCopyFromUserBuf(&pTempBuf[TempBufWrIndex], &pBuf[BufIndex], NumCopy); DtDbgOut(MAX, RDWR, "NumCopy=%d, BytesLeft:%d, TempLoad=%d", NumCopy, BytesLeft, TempBufWrIndex); // Write data Status = DtUsbPipeWrite(&pDvcData->m_Device, NULL, Pipe, pTempBuf, TempBufWrIndex+NumCopy, MAX_USB_RW_TIMEOUT); // Temporary buffer is empty now TempBufWrIndex = 0; TempBufRdIndex = 0; // Update counters BytesLeft -= NumCopy; BufIndex += NumCopy; } //-.-.-.-.-.-.-.-.-.-.-.-.- Directly copy multiples of 1024 -.-.-.-.-.-.-.-.-.-.-.-.-. while (DT_SUCCESS(Status) && BytesLeft>=DTU_BULK_TRANSFER_ALIGN) { if (BytesLeft>DTU_BULK_PACKETSIZE) NumCopy = DTU_BULK_PACKETSIZE; else NumCopy = BytesLeft - (BytesLeft%DTU_BULK_TRANSFER_ALIGN); DtDbgOut(MAX, RDWR, "NumCopy=%d, BytesLeft:%d, TempLoad=%d", NumCopy, BytesLeft, TempBufWrIndex); // Write data #ifdef LINBUILD // For Linux, we have to write to a temp. buffer. We can not write to // the user buffer directly DtMemCopyFromUserBuf(pTempBuf, &pBuf[BufIndex], NumCopy); Status = DtUsbPipeWrite(&pDvcData->m_Device, NULL, Pipe, pTempBuf, NumCopy, MAX_USB_RW_TIMEOUT); #else Status = DtUsbPipeWrite(&pDvcData->m_Device, NULL, Pipe, &pBuf[BufIndex], NumCopy, MAX_USB_RW_TIMEOUT); #endif BytesLeft -= NumCopy; BufIndex += NumCopy; } //-.-.-.-.-.-.-.-.-.-.- Copy remaining data to temporary buffer -.-.-.-.-.-.-.-.-.-.-. if (DT_SUCCESS(Status) && BytesLeft > 0 ) { NumCopy = BytesLeft; DtDbgOut(MAX, RDWR, "NumCopy=%d, BytesLeft:%d, TempLoad=%d", NumCopy, BytesLeft, TempBufWrIndex); DtMemCopyFromUserBuf(&pTempBuf[TempBufWrIndex], &pBuf[BufIndex], NumCopy); // Update index and counters TempBufWrIndex += NumCopy; BytesLeft -= NumCopy; BufIndex += NumCopy; } // Save temporary buffer indices pNonIpPort->m_TempBufWrIndex = TempBufWrIndex; pNonIpPort->m_TempBufRdIndex = TempBufRdIndex; DtDbgOut(MAX, RDWR, "Exit: BytesLeft:%d, TempLoad=%d", BytesLeft, TempBufWrIndex); return Status; }