//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DriverParametersKeyWrite -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // NTSTATUS DriverParametersKeyWrite( WDFDRIVER Driver, DtString* pKeyName, DtString* pValueName, Int64 BinValue, DtString* pStrValue) { NTSTATUS NtStatus; WDFKEY ParametersKey; WDFKEY Key = NULL; WDFSTRING WdfString; DT_ASSERT(KeGetCurrentIrql()<=PASSIVE_LEVEL); // Check if the registry path already exists. If not, create the registry path. if (!DT_SUCCESS(CheckAndCreateRegistryPath(Driver, pKeyName))) return STATUS_UNSUCCESSFUL; // Open the drivers parameters key (under services) NtStatus = WdfDriverOpenParametersRegistryKey(Driver, KEY_WRITE, WDF_NO_OBJECT_ATTRIBUTES, &ParametersKey); if (!NT_SUCCESS(NtStatus)) { DtDbgOut(ERR, SAL, "WdfDriverOpenParametersRegistryKey failed. Error: 0x%x", NtStatus); return NtStatus; } // Open the key (including part of path) NtStatus = WdfRegistryOpenKey(ParametersKey, pKeyName, KEY_WRITE, WDF_NO_OBJECT_ATTRIBUTES, &Key); if (!NT_SUCCESS(NtStatus)) DtDbgOut(ERR, SAL, "WdfRegistryOpenKey failed. Error: 0x%x", NtStatus); if (NT_SUCCESS(NtStatus)) { // Write string or binary value if (pStrValue != NULL) { // Set string attributes with the key as parent object, so that the string // object is freed when the key object is destroyed. If we donot do this the // string object is freed when the driver unloads, meaning that the each call // to DriverParametersKeyWrite result in an increase of memory usage, only // to be freed on the unload. WDF_OBJECT_ATTRIBUTES WdfStringAttr; WDF_OBJECT_ATTRIBUTES_INIT(&WdfStringAttr); WdfStringAttr.ParentObject = Key; NtStatus = WdfStringCreate(pStrValue, &WdfStringAttr, &WdfString); if (NT_SUCCESS(NtStatus)) NtStatus = WdfRegistryAssignString(Key, pValueName, WdfString); } else NtStatus = WdfRegistryAssignValue(Key, pValueName, REG_QWORD, sizeof(Int64), &BinValue); if (!NT_SUCCESS(NtStatus)) DtDbgOut(ERR, SAL, "WdfRegistryAssignValue failed. Error: 0x%x", NtStatus); } if (Key != NULL) WdfRegistryClose(Key); WdfRegistryClose(ParametersKey); return NtStatus; }
//.-.-.-.-.-.-.-.-.-.-.-.- PathAppendSettingsSerialDeviceCategory -.-.-.-.-.-.-.-.-.-.-.-. // DtStatus PathAppendSettingsSerialDeviceCategory( DtString* pPath, UInt64 DvcSerial, Char* pCategory) { DtStatus Status = DT_STATUS_OK; DT_STRING_DECL(SettingsStr, "Settings\\"); DT_STRING_DECL(DeviceStr, "\\Device"); // Registry path starts with <\Settings\> Status = DtStringAppendDtString(pPath, &SettingsStr); if (DT_SUCCESS(Status)) // Convert serial to unicode string and append to path Status = DtStringUInt64ToDtStringAppend(pPath, 10, DvcSerial); if (DT_SUCCESS(Status)) { Status = DtStringAppendDtString(pPath, &DeviceStr); if (DT_SUCCESS(Status)) { if (pCategory != NULL) { // Append category Status = DtStringAppendChars(pPath, "\\"); if (DT_SUCCESS(Status)) Status = DtStringAppendChars(pPath, pCategory); } } } return Status; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- CheckAndCreateRegistryPath -.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus CheckAndCreateRegistryPath( WDFDRIVER Driver, DtString* pItemPath) { DtStringChar* pRegistryPath; DtString RegistryPath; DtString FullKeyName; UInt PathLength; DtStatus Status; Int i; DT_STRING_DECL(ParamItemName, "\\Parameters"); // Build the full path pRegistryPath = WdfDriverGetRegistryPath(Driver); PathLength = wcslen(pRegistryPath); DT_STRING_INIT_CONST(RegistryPath, pRegistryPath, PathLength); // Allocate a new DtString buffer for the complete path inclusive a '\0' character and // extra '\' if (!DT_SUCCESS(DtStringAlloc(&FullKeyName, PathLength+ DtStringGetStringLength(&ParamItemName)+ DtStringGetStringLength(pItemPath)+2))) return STATUS_NO_MEMORY; DtStringAppendDtString(&FullKeyName, &RegistryPath); DtStringAppendDtString(&FullKeyName, &ParamItemName); if (RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, FullKeyName.Buffer) != STATUS_SUCCESS) RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, FullKeyName.Buffer); Status = DT_STATUS_OK; i = 1; // Get all subitems from pItemPath and check if the registry entry exist. // If not, create the registry entry. // This function is needed, because Wuindows only allows us to create one registry entry // at a time and not a complete path. while (Status == DT_STATUS_OK) { DtStringAppendChars(&FullKeyName, "\\"); Status = DtStringAppendSubstring(&FullKeyName, pItemPath, i, '\\'); if (DT_SUCCESS(Status)) { if (RtlCheckRegistryKey(RTL_REGISTRY_ABSOLUTE, FullKeyName.Buffer) != STATUS_SUCCESS) RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, FullKeyName.Buffer); } i++; } DtStringFree(&FullKeyName); return DT_STATUS_OK; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- EzUsbLoadFirmware -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus EzUsbLoadFirmware( DtuDeviceData* pDvcData, const DtuIntelHexRecord* pMicroCode) { DtStatus Status; Int Dummy = 0; DtuIntelHexRecord* pPtr = NULL; if (pMicroCode == NULL) return DT_STATUS_INVALID_PARAMETER; //.-.-.-.-.-.-.-.-.-.-.-.- Download firmware to internal RAM -.-.-.-.-.-.-.-.-.-.-.-.- // // Before starting the upload, stop the 8051 Status = EzUsbResetProcessor(pDvcData, TRUE); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Failed to stop the processor (Status=0x%08X)", Status); return Status; } pPtr = (DtuIntelHexRecord*)pMicroCode; while (pPtr->Type == 0) { // Send load command Status = DtUsbVendorRequest(&pDvcData->m_Device, NULL, EZUSB_FX2_LOAD_INTERNAL, pPtr->Address, 0, DT_USB_HOST_TO_DEVICE, pPtr->Data, pPtr->Length, &Dummy, MAX_USB_REQ_TIMEOUT); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Failed to send load command (Status=0x%08X)", Status); return Status; } pPtr++; } // Restart the 8051 if (Status == DT_STATUS_OK) { Status = EzUsbResetProcessor(pDvcData, FALSE); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Failed to start the processor (Status=0x%08X)", Status); return Status; } } return DT_STATUS_OK; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtTableGetForType -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtTableGetForType( const char* pTypeName, Int TypeNumber, Int SubDvc, Int HwRev, Int FwVer, Int FwVariant, const char* pTableName, Int PortIndex, UInt MaxNumEntries, UInt* pNumEntries, DtTableEntry* pTableEntry2, UInt OutBufSize) { DtPropertyData PropData; DtStatus Status = DT_STATUS_OK; // Init property data structure PropData.m_TypeNumber = TypeNumber; PropData.m_SubDvc = SubDvc; PropData.m_FirmwareVariant = FwVariant; PropData.m_FirmwareVersion = FwVer; PropData.m_HardwareRevision = HwRev; PropData.m_TypeName = (char*)pTypeName; Status = DtTablesInit(&PropData); if (!DT_SUCCESS(Status)) return Status; // Now find the table return DtTableGet(&PropData, pTableName, PortIndex, MaxNumEntries, pNumEntries, pTableEntry2, OutBufSize); }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- EzUsbIsFirmwareLoaded -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // // Check if microcode for the EzUsb chip has been loaded // Bool EzUsbIsFirmwareLoaded(DtuDeviceData* pDvcData) { DtStatus Status; DtString DtStr; DtStringChar DtStrBuffer[64]; // Connect DtStrBuffer to DtStr DT_STRING_INIT(DtStr, DtStrBuffer, 64); // Found a uninitialised DTU-2xx device with manuf microcode if (pDvcData->m_DevInfo.m_ProductId == DTU2xx_MANUF) return TRUE; // For DTU-3XX devices check that the manufacturer string is "DekTec". if (pDvcData->m_DevInfo.m_TypeNumber>=300 && pDvcData->m_DevInfo.m_TypeNumber<400) return DtUsbManufNameEq(&pDvcData->m_Device, "DekTec"); //.-.-.-.-.-.-.-.- Check for the availability of a string descriptor -.-.-.-.-.-.-.-.- // // If there is no microcode there will be no string descriptor Status = DtUsbQueuryString(&pDvcData->m_Device, &DtStr, 1); if (!DT_SUCCESS(Status)) return FALSE; // Must find a string descriptor with a size >= 3 return DtStringGetStringLength(&DtStr)>=3 ? TRUE : FALSE; }
//-.-.-.-.-.-.-.-.-.-.-.-.- PathAppendSettingsSerialPortCategory -.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus PathAppendSettingsSerialPortCategory( DtString* pPath, UInt64 DvcSerial, Int Port, Char* pCategory) { DtStatus Status = DT_STATUS_OK; DT_STRING_DECL(SettingsStr, "Settings\\"); DT_STRING_DECL(PortStr, "\\Port"); // Registry path starts with <\Settings\> Status = DtStringAppendDtString(pPath, &SettingsStr); if (DT_SUCCESS(Status)) { // Convert serial to unicode string and append to path Status = DtStringUInt64ToDtStringAppend(pPath, 10, DvcSerial); } if (DT_SUCCESS(Status)) { // Append port if provided if (Port >= 0) { Status = DtStringAppendDtString(pPath, &PortStr); if (DT_SUCCESS(Status)) { // Convert Port to unicode string Status = DtStringUIntegerToDtStringAppend(pPath, 10, Port); } } if (DT_SUCCESS(Status)) { if (pCategory != NULL) { // Append category Status = DtStringAppendChars(pPath, "\\"); if (DT_SUCCESS(Status)) Status = DtStringAppendChars(pPath, pCategory); } } } return Status; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuDvcPowerSupplyInit -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // // Initializes the Altera power supply // DtStatus DtuDvcPowerSupplyInit(DtuDeviceData* pDvcData) { DtStatus Status = DT_STATUS_OK; UInt8 I2cBuf[8]; Int TypeNumber = pDvcData->m_DevInfo.m_TypeNumber; if (TypeNumber==215) { // Start 1V2 power supply (ALTERA core voltage) // NOTE: we only start the 1V2 power supply here. Other power supplies are started // later when we init the device hardware. I2cBuf[0] = DTU215_IIC_ADDR_PWR_1V2; I2cBuf[1] = DTU215_IIC_PWR_1V2_CTRL; Status = DtuI2cWrite(pDvcData, NULL, DTU215_IIC_ADDR_PWR_SUPPLY, 2, I2cBuf); // Sleep shortly to allow power-supply to settle DtSleep(200); if (DT_SUCCESS(Status)) DtDbgOut(AVG, DTU, "DTU-%d power supply started", TypeNumber); else DtDbgOut(ERR, DTU, "DTU-%d power supply start ERROR. Error: %xh", TypeNumber, Status); } else if ((TypeNumber==350 || TypeNumber==351) && pDvcData->m_DevInfo.m_UsbSpeed==2) { Status = DtUsbVendorRequest(&pDvcData->m_Device, NULL, DTU_USB3_PNP_CMD, DTU_PNP_CMD_DVC_POWER, DTU_DVC_POWER_ON, DT_USB_HOST_TO_DEVICE, NULL, 0, NULL, MAX_USB_REQ_TIMEOUT); if (DT_SUCCESS(Status)) DtSleep(100); } else if (TypeNumber==315 && pDvcData->m_DevInfo.m_UsbSpeed==2) { // DTU-315 specific: Enable LED (fade PWM mode) Dtu3RegWrite(pDvcData, DTU3_FX3_BLOCK_OFFSET, &FwbFx3.LedCtrl, 1); } return Status; }
DtStatus DtIoConfigReadFromNonVolatileStorage( DtDrvObject* pSalDrvObj, UInt64 Serial, Int PortIndex, Int IoGroup, DtIoConfigValueDriver* pCfgValue) { DtStatus Result; Int32 Value; Int64 BinValue; Char StrValue[IOCONFIG_NAME_MAX_SIZE]; Int ParXtraIdx; DtIoConfigValueDriver IoConfig; Char GroupName[IOCONFIG_NAME_MAX_SIZE]; // Get the IO group name Result = IoConfigNameGet(IoGroup, GroupName, sizeof(GroupName) ); if (!DT_SUCCESS(Result)) return Result; // Get config value Result = DtNonVolatileSettingsStringRead(pSalDrvObj, Serial, PortIndex, GroupName, "ConfigValue", StrValue, sizeof(StrValue)); if (!DT_SUCCESS(Result)) return Result; Result = IoConfigCodeGet(StrValue, &Value); if (!DT_SUCCESS(Result)) return Result; IoConfig.m_Value = (Int)Value; // Get config subvalue Result = DtNonVolatileSettingsStringRead(pSalDrvObj, Serial, PortIndex, GroupName, "ConfigSubValue", StrValue, sizeof(StrValue)); if (!DT_SUCCESS(Result)) return Result; Result = IoConfigCodeGet(StrValue, &Value); if (!DT_SUCCESS(Result)) return Result; IoConfig.m_SubValue = Value; // Read ParXtra for (ParXtraIdx=0; ParXtraIdx<DT_MAX_PARXTRA_COUNT; ParXtraIdx++) { Result = DtNonVolatileSettingsValueRead(pSalDrvObj, Serial, PortIndex, GroupName, (Char*)IoParXtraNames[ParXtraIdx], &BinValue); if (!DT_SUCCESS(Result)) return DT_STATUS_CONFIG_ERROR; IoConfig.m_ParXtra[ParXtraIdx] = BinValue; } // Copy result only if succeeded *pCfgValue = IoConfig; return DT_STATUS_OK; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuShBufferInit -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtuShBufferInit( DtuIoctlShBufCmdInput* pShBufCmdInput, DtFileObject* pFile, DtPageList* pPageList, char* pBuffer, Int BufSize, UInt BufType, DtuShBuffer* pShBuffer) { DtStatus Status; if (pShBuffer->m_Initialised) return DT_STATUS_IN_USE; // Create a pagelist for the shared buffer Status = DtCreatePageList(pBuffer, BufSize, BufType, &pShBuffer->m_PageList); if (!DT_SUCCESS(Status)) return Status; pShBuffer->m_pBuffer = pBuffer; if (BufType == DT_BUFTYPE_USER) { // Lock buffer into kernel memory Status = DtLockUserBuffer(&pShBuffer->m_PageList, pBuffer); if (DT_SUCCESS(Status)) pShBuffer->m_pBuffer = pShBuffer->m_PageList.m_pVirtualKernel; } if (!DT_SUCCESS(Status)) { DtDeletePageList(&pShBuffer->m_PageList); return Status; } pShBuffer->m_Owner = *pFile; pShBuffer->m_Initialised = TRUE; return Status; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- EzUsbLoadFirmware -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus EzUsbLoadFirmwareFx3( DtuDeviceData* pDvcData, const DtuFx3HexRecord* pMicroCode) { DtStatus Status; Int Dummy = 0; const DtuFx3HexRecord* pPtr = pMicroCode; Bool Cont = TRUE; if (pMicroCode == NULL) return DT_STATUS_INVALID_PARAMETER; DtDbgOut(MAX, DTU, "Loading firmware"); while (Cont) { UInt32 Len = pPtr->Length; UInt32 Addr = pPtr->Address; UInt8* Data = (UInt8*)(pPtr->Data); UInt32 NumToWrite; Cont = (pPtr->Length != 0); do { NumToWrite = Len < FX3_MAX_CHUNK_SIZE ? Len : FX3_MAX_CHUNK_SIZE; // Send load command Status = DtUsbVendorRequest(&pDvcData->m_Device, NULL, EZUSB_FX2_LOAD_INTERNAL, Addr&0xFFFF, Addr>>16, DT_USB_HOST_TO_DEVICE, Data, NumToWrite, &Dummy, MAX_USB_REQ_TIMEOUT); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Failed to send load command (Status=0x%08X)", Status); return Status; } Len -= NumToWrite; Addr += NumToWrite; Data += NumToWrite; } while (Len > 0); pPtr++; } return DT_STATUS_OK; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtPropertiesGet -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtPropertiesGet(DtPropertyData* pPropData, const char* pName, Int PortIndex, DtPropertyValue* pValue, DtPropertyValueType* pType, DtPropertyScope* pScope, Int DtapiMaj, Int DtapiMin, Int DtapiBugfix) { DtStatus Status = DT_STATUS_OK; // Find the property in the property tables const DtProperty* pProperty = NULL; Status = DtPropertiesFind(pPropData, pName, PortIndex, &pProperty, DtapiMaj, DtapiMin, DtapiBugfix); if (Status == DT_STATUS_NOT_FOUND) { Int i; Int NumAltNames = 0; const char* const* pAltNames; // If not found, look for alternative names // Get the alternative names DtPropertiesGetAltName(pName, &NumAltNames, &pAltNames); // Try to get the property for the alternative name for (i=0; i<NumAltNames && Status==DT_STATUS_NOT_FOUND; i++) { Status = DtPropertiesFind(pPropData, pAltNames[i], PortIndex, &pProperty, DtapiMaj, DtapiMin, DtapiBugfix); } } // Get property details if (DT_SUCCESS(Status) && pProperty!=NULL) { // Copy property info *pValue = pProperty->m_Value; *pType = pProperty->m_Type; *pScope = pProperty->m_Scope; DtDbgOut(MAX, PROP, "Found property %s for %s-%d, FW %d, HW %d. " "Value: 0x%08x%08x, Type:%i, Scope:%i", pName, pPropData->m_TypeName, pPropData->m_TypeNumber, pPropData->m_FirmwareVersion, pPropData->m_HardwareRevision, (UInt32)(*pValue>>32),(UInt32)*pValue, *pType, *pScope); }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuDemodInit -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtuDemodInit(DtuDeviceData* pDvcData) { DtStatus Status = DT_STATUS_OK; const DtuDemodFirmwareStore* pDemodFirmware = NULL; pDemodFirmware = DtuGetDemodFirmware(pDvcData->m_DevInfo.m_ProductId, pDvcData->m_DevInfo.m_HardwareRevision); if (pDemodFirmware == NULL) return DT_STATUS_OK; Status = DtuLoadDemodFirmware(pDvcData, pDemodFirmware); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Failed to upload demodulator firmware (Status=0x%08X)", Status); return Status; } DtDbgOut(AVG, DTU, "Demodulator firmware uploaded successfully"); return Status; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- 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; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuLoadDemodFirmware -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtuLoadDemodFirmware( DtuDeviceData* pDvcData, const DtuDemodFirmwareStore* pDemodFirmware) { DtStatus Status = DT_STATUS_OK; UInt8 Buffer[2]; Int i, j; UInt DvcAddr = pDemodFirmware->m_DemodI2cAddress; DT_ASSERT(pDemodFirmware != NULL); // First do the PRE-upload register writes if (pDemodFirmware->m_pPreUpload != NULL) { const DtuInitRegisterStruct* pInitRegisterData = pDemodFirmware->m_pPreUpload; for (i=0; i<pInitRegisterData->m_RegisterDataCount; i++) { Buffer[0] = pInitRegisterData->m_RegData[i].m_Data[0]; Buffer[1] = pInitRegisterData->m_RegData[i].m_Data[1]; Status = DtuI2cWrite(pDvcData, NULL, DvcAddr, 2, Buffer); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Error writing I2C pre-upload data. (Status=0x%08X)", Status); return Status; } } } // Upload demodulator firmware if (pDemodFirmware->m_pFirmware != NULL) { const Int MAX_BYTES_TO_TRY = 60; UInt8 AddrHigh; UInt8 AddrLow; Int DataCount; Int BytesToTry; const DtuHexStruct* pFirmware = pDemodFirmware->m_pFirmware; UInt8* pHexData=NULL; // First allocate memory for temporary helper buffer pHexData = DtMemAllocPool(DtPoolNonPaged, 4096, DTU_TAG); if (pHexData == NULL) return DT_STATUS_OUT_OF_MEMORY; for (i=0; i<pFirmware->m_HexBlockCount; i++) { const DtuHexBlockStruct* pHexBlock = &(pFirmware->m_HexBlock[i]); DataCount = pHexBlock->m_DataCount; BytesToTry = 0; while (DataCount > 0) { AddrHigh = (UInt8)((pHexBlock->m_Address + pHexBlock->m_DataCount-DataCount) >> 8); AddrLow = (UInt8)(pHexBlock->m_Address + pHexBlock->m_DataCount-DataCount); // Write high address Buffer[0] = (UInt8)pDemodFirmware->m_AddrRegH; Buffer[1] = AddrHigh; Status = DtuI2cWrite(pDvcData, NULL, DvcAddr, 2, Buffer); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Error writing I2C high address. (Status=0x%08X)", Status); DtMemFreePool(pHexData, DTU_TAG); return Status; } // Write low address Buffer[0] = (UInt8)pDemodFirmware->m_AddrRegL; Buffer[1] = AddrLow; Status = DtuI2cWrite(pDvcData, NULL, DvcAddr, 2, Buffer); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Error writing I2C low address. (Status=0x%08X)", Status); DtMemFreePool(pHexData, DTU_TAG); return Status; } // Write data pHexData[0] = (UInt8)pDemodFirmware->m_DataReg; BytesToTry = (DataCount<=MAX_BYTES_TO_TRY ? DataCount : MAX_BYTES_TO_TRY); for (j=0; j<BytesToTry; j++) pHexData[j + 1] = pHexBlock->m_Data[j + pHexBlock->m_DataCount - DataCount]; Status = DtuI2cWrite(pDvcData, NULL, DvcAddr, BytesToTry+1, pHexData); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Error writing I2C data. (Status=0x%08X)", Status); DtMemFreePool(pHexData, DTU_TAG); return Status; } DataCount -= BytesToTry; } } DtMemFreePool(pHexData, DTU_TAG); } // Do the STOP-upload register writes if (pDemodFirmware->m_pStopUpload != NULL) { const DtuInitRegisterStruct* pInitRegisterData = pDemodFirmware->m_pStopUpload; for (i=0; i<pInitRegisterData->m_RegisterDataCount; i++) { Buffer[0] = pInitRegisterData->m_RegData[i].m_Data[0]; Buffer[1] = pInitRegisterData->m_RegData[i].m_Data[1]; Status = DtuI2cWrite(pDvcData, NULL, DvcAddr, 2, Buffer); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Error writing I2C stop-upload data. (Status=0x%08X)", Status); return Status; } } } // Wait until AP is running if (pDemodFirmware->m_pFirmware != NULL) { Int TimeOut; Buffer[0] = (UInt8)pDemodFirmware->m_ApStatReg; Status = DtuI2cWrite(pDvcData, NULL, DvcAddr, 1, Buffer); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Error writing I2C apstat data. (Status=0x%08X)", Status); return Status; } // Wait until ready Buffer[0] = 1; TimeOut = 0; while (Buffer[0]==1 && TimeOut<250) // Wait max. 250ms { DtSleep(10); TimeOut += 10; // Read the app status Status = DtuI2cRead(pDvcData, NULL, DvcAddr, 1, Buffer); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Error reading I2C apstat data. (Status=0x%08X)", Status); return Status; } } if (Buffer[0] == 1) { DtDbgOut(ERR, DTU, "TIMEOUT! APSTAT = %x.", (Int)(Buffer[0])); } } //Do the post-upload register writes if (pDemodFirmware->m_pPostUpload != NULL) { const DtuInitRegisterStruct* pInitRegisterData = pDemodFirmware->m_pPostUpload; for (i=0; i<pInitRegisterData->m_RegisterDataCount; i++) { Buffer[0] = pInitRegisterData->m_RegData[i].m_Data[0]; Buffer[1] = pInitRegisterData->m_RegData[i].m_Data[1]; Status = DtuI2cWrite(pDvcData, NULL, DvcAddr, 2, Buffer); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Error writing I2C post-upload data. (Status=0x%08X)", Status); return Status; } } } return Status; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtNonVolatileSettingsWrite -.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtNonVolatileSettingsWrite( DtDrvObject* pDrvObj, UInt64 DvcSerial, Int Port, Char* pCategory, Char* pName, Int64 BinValue, Char* pStrValue) { DtStatus Status = DT_STATUS_OK; #ifdef WINBUILD // Windows uses the registry to store non volatile settings NTSTATUS NtStatus; DtString RegKeyName; DtString ValueName; // Allocate RegKeyName buffer Status = DtStringAlloc(&RegKeyName, 150); if (DT_SUCCESS(Status)) { Status = DtStringAlloc(&ValueName, 50); if (DT_SUCCESS(Status)) { // Create registry path string Status = PathAppendSettingsSerialPortCategory(&RegKeyName, DvcSerial, Port, pCategory); if (DT_SUCCESS(Status)) { // Convert value name to DtString Status = DtStringAppendChars(&ValueName, pName); if (DT_SUCCESS(Status)) { if (pStrValue!=NULL) { DtString StrValue; Status = DtStringAlloc(&StrValue, 50); if (DT_SUCCESS(Status)) { // Convert value to DtString Status = DtStringAppendChars(&StrValue, pStrValue); if (DT_SUCCESS(Status)) { // Write register string value NtStatus = DriverParametersKeyWrite(pDrvObj->m_WdfDriver, &RegKeyName, &ValueName, -1, &StrValue); } // Free ValueName DtStringFree(&StrValue); } } else { // Write register binary value NtStatus = DriverParametersKeyWrite(pDrvObj->m_WdfDriver, &RegKeyName, &ValueName, BinValue, NULL); } if (!NT_SUCCESS(NtStatus)) Status = DT_STATUS_FAIL; } } // Free ValueName DtStringFree(&ValueName); } // Free RegKeyName DtStringFree(&RegKeyName); } #else // Linux can use config files, but they should not be read / write from a kernel // module --> http://www.linuxjournal.com/article/8110 // Maybe use hotplug event in user space to have helper application to perform // driver load and do the initial settings. Helper application can be DtapiService // or a simple script. Status = DT_STATUS_OK; #endif return Status; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- IoConfigCodesCodeGet -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus IoConfigCodeGet( const char* pName, Int *pConfigCode) { DtStatus Status = DT_STATUS_OK; const IoConfigCodeHashSet* pHashSets = IoConfigCodeHashSets; UInt HashSetCount = IoConfigCodesHashCount; UInt Hash = 0; Int Index; Bool ConfigNameFound = FALSE; const IoConfigCodeHashSet* pHashSet = NULL; Int ConfigCount = 0; const IoConfigCode* pConfig = NULL; // Special case empty string if (pName[0] == '\0') { *pConfigCode = -1; return Status; } // Determine the name hash Hash = DtDjb2(pName) % HashSetCount; // Get correct hash set (if exists) if (DT_SUCCESS(Status)) { pHashSet = &pHashSets[Hash]; ConfigCount = pHashSets[Hash].m_ConfigCodeCount; // Check if a hash set was available for this hash value if (pHashSet == NULL) Status = DT_STATUS_NOT_FOUND; } // Get correct config entry within hash set if (DT_SUCCESS(Status)) { // Search all configs for (Index=0; Index<ConfigCount; Index++) { pConfig = &pHashSet->m_pConfigCodes[Index]; // Compare name to check if we found the first occurrence if (DtAnsiCharArrayIsEqual(pName, pConfig->m_pName)) { *pConfigCode = pConfig->m_Value; ConfigNameFound = TRUE; break; } } if (!ConfigNameFound) Status = DT_STATUS_NOT_FOUND; } if (!ConfigNameFound) DtDbgOut(ERR, PROP, "ConfigName %s is not found", pName); else DtDbgOut(MAX, PROP, "Found config code %d for %s", *pConfigCode, pName); return Status; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- EzUsbInit -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus EzUsbInit(DtuDeviceData* pDvcData, Bool* pReEnumerate) { DtStatus Status = DT_STATUS_OK; const DtuIntelHexRecord* pEzUsbFirmware = NULL; DtPropertyData* pPropData = &pDvcData->m_PropData; Bool IsEzUsbFwLoaded=FALSE, IsPldFwLoaded=FALSE; Int FirmwareEndpoint; Int ReadEndpoint; Int WriteEndpoint; // Initialize properties FirmwareEndpoint = DtPropertiesGetInt(pPropData, "USB_END_POINT_FIRMWARE", -1); ReadEndpoint = DtPropertiesGetInt(pPropData, "USB_END_POINT_READ", -1); WriteEndpoint = DtPropertiesGetInt(pPropData, "USB_END_POINT_WRITE", -1); // Check if no property error occurred Status = DtuPropertiesReportDriverErrors(pDvcData); if (!DT_SUCCESS(Status)) return Status; // Check if we need to load firmware. NOTE: there are two conditions to load the // firmware namely: // 1. EzUsb firmware is not loaded yet // 2. PLD firmware is loaded already, which suggest a warm-reboot which we want to // treat as a cold roboot => upload EzUsb firmware, but no re-enumeration *pReEnumerate = FALSE; IsEzUsbFwLoaded = EzUsbIsFirmwareLoaded(pDvcData); IsPldFwLoaded = FALSE; if (IsEzUsbFwLoaded && !(pDvcData->m_DevInfo.m_TypeNumber>=300 && pDvcData->m_DevInfo.m_TypeNumber<400)) IsPldFwLoaded = DtuPldIsFirmwareLoaded(pDvcData); if (!IsEzUsbFwLoaded || IsPldFwLoaded) { if (IsPldFwLoaded) DtDbgOut(MIN, DTU, "PLD FW is already loaded => warm reboot"); else DtDbgOut(MIN, DTU, "No EzUsb firmware loaded => cold reboot"); if (pDvcData->m_DevInfo.m_TypeNumber>=300 && pDvcData->m_DevInfo.m_TypeNumber<400) { // Lookup firmware const DtuFx3HexRecord* pFx3Firmware = Dtu3GetFx3Firmware( pDvcData->m_DevInfo.m_TypeNumber, -1, pDvcData->m_DevInfo.m_HardwareRevision); if (pFx3Firmware == NULL) DtDbgOut(ERR, DTU, "FX3 firmware not found for Typenumber: %d," " HardwareRev: 0x%X", pDvcData->m_DevInfo.m_TypeNumber, pDvcData->m_DevInfo.m_HardwareRevision); if (!DtUsbManufNameEq(&pDvcData->m_Device, "Cypress")) { DtDbgOut(ERR, DTU, "DTU-3XX vid/pid found but wrong manufacturer string"); return DT_STATUS_FAIL; } if (pDvcData->m_DevInfo.m_ProductId == DTU3_PID_UNIT_EEPROM) pDvcData->m_BootState = DTU_BOOTSTATE_FACTORY_COLD; else pDvcData->m_BootState = DTU_BOOTSTATE_COLD; //TODOTM: verify product string is "DTU-351" // Upload firmware for EzUsb chip Status = EzUsbLoadFirmwareFx3(pDvcData, pFx3Firmware); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Failed to upload FX3 firmware (Status=0x%08X)", Status); return Status; } DtDbgOut(ERR, DTU, "FX3 firmware uploaded"); } else { // Lookup firmware pEzUsbFirmware = DtuGetEzUsbFirmware(pDvcData->m_DevInfo.m_ProductId, -1, pDvcData->m_DevInfo.m_HardwareRevision); if (pEzUsbFirmware == NULL) { DtDbgOut(ERR, DTU, "No EzUsb firmware available for DTU-%d", pDvcData->m_DevInfo.m_TypeNumber); return DT_STATUS_FAIL; } // Upload firmware for EzUsb chip Status = EzUsbLoadFirmware(pDvcData, pEzUsbFirmware); if (!DT_SUCCESS(Status)) { DtDbgOut(ERR, DTU, "Failed to upload FX2 firmware (Status=0x%08X)", Status); return Status; } } *pReEnumerate = !IsPldFwLoaded; // Device will reenumerate, if cold reboot if (!IsPldFwLoaded) return DT_STATUS_OK; // In case of cold reboot we are done (will reenumerate) } // Convert endpoint to pipe numbers if (FirmwareEndpoint != -1) { // Convert endpoint to pipe number pDvcData->m_EzUsb.m_FirmwarePipe = DtUsbGetBulkPipeNumber(&pDvcData->m_Device, DT_USB_HOST_TO_DEVICE, FirmwareEndpoint); DT_ASSERT(pDvcData->m_EzUsb.m_FirmwarePipe != -1); } if (ReadEndpoint != -1) { // Convert endpoint to pipe number pDvcData->m_EzUsb.m_ReadPipe = DtUsbGetBulkPipeNumber(&pDvcData->m_Device, DT_USB_DEVICE_TO_HOST, ReadEndpoint); DT_ASSERT(pDvcData->m_EzUsb.m_ReadPipe != -1); } if (WriteEndpoint != -1) { // Convert endpoint to pipe number pDvcData->m_EzUsb.m_WritePipe = DtUsbGetBulkPipeNumber(&pDvcData->m_Device, DT_USB_HOST_TO_DEVICE, WriteEndpoint); DT_ASSERT(pDvcData->m_EzUsb.m_WritePipe != -1); } return Status; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtDpcSchedule -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtDpcSchedule(DtDpc* pDpc, DtDpcArgs* pArgs) { DtStatus Result = DT_STATUS_OK; Int OldState; Bool DoRun = FALSE; Bool DoQueue = FALSE; DT_ASSERT(pDpc->m_SchedulingEnabled); // Try to set running from idle state OldState = DtAtomicCompareExchange((Int*)&pDpc->m_State, 0, DPC_STATE_BIT_RUNNING); if (OldState == 0) // Successfully running DoRun = TRUE; else if (pDpc->m_QueueIfRunning) { // Try to set Queuing OldState = DtAtomicCompareExchange((Int*)&pDpc->m_State, DPC_STATE_BIT_RUNNING, DPC_STATE_BIT_RUNNING|DPC_STATE_BIT_QUEUING); if (OldState == DPC_STATE_BIT_RUNNING) // Successfully set to queuing DoQueue = TRUE; // Not running anymore? // Try to set running again to be sure a full execution of the worker is pending // after the call the DtDpcSchedule... else if ((OldState&DPC_STATE_BIT_RUNNING) == 0) { // Retry to set running from idle state OldState = DtAtomicCompareExchange((Int*)&pDpc->m_State, 0, DPC_STATE_BIT_RUNNING); if (OldState == 0) // Successfully set to running DoRun = TRUE; else Result = DT_STATUS_IN_USE; } else Result = DT_STATUS_IN_USE; } if (!DT_SUCCESS(Result)) return Result; // Queue DPC? if (DoQueue) { // Copy arguments pDpc->m_QueuedArgs = *pArgs; // Set to queued (running|queuing|queued) OldState = DtAtomicCompareExchange((Int*)&pDpc->m_State, DPC_STATE_BIT_RUNNING|DPC_STATE_BIT_QUEUING, DPC_STATE_BIT_RUNNING|DPC_STATE_BIT_QUEUING|DPC_STATE_BIT_QUEUED); // Check if we failed because we were not running anymore if (OldState == DPC_STATE_BIT_QUEUING) { // Choose running slot --> try to set from queuing to running instead of // queued OldState = DtAtomicCompareExchange((Int*)&pDpc->m_State, DPC_STATE_BIT_QUEUING, DPC_STATE_BIT_RUNNING); if (OldState == DPC_STATE_BIT_QUEUING) DoRun = TRUE; else { Result = DT_STATUS_IN_USE; // Can not happen? DT_ASSERT(FALSE); } } } // Start initial DPC? if (DoRun) { pDpc->m_Args = *pArgs; #ifdef WINBUILD KeInsertQueueDpc(&pDpc->m_Kdpc, NULL, NULL); #else tasklet_schedule(&pDpc->m_Tasklet); #endif // Running flag is already set... } return Result; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaGenlockInit -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtaGenlockInit(DtaDeviceData* pDvcData) { DtStatus Status = DT_STATUS_OK; // Initialize properties DtPropertyData* pPropData = &pDvcData->m_PropData; // Assume genlock is not supported pDvcData->m_Genlock.m_IsSupported = FALSE; pDvcData->m_Genlock.m_OpModeIntSrc = GENLOCK_OPMODE_INTSRC_UNDEF; pDvcData->m_Genlock.m_GenlArch = DtPropertiesGetInt(pPropData, "GENLOCK_ARCH", -1); // Do we have a valid architecture if (pDvcData->m_Genlock.m_GenlArch > 0) pDvcData->m_Genlock.m_IsSupported = TRUE; pDvcData->m_Genlock.m_AsyncPortIndex = DtPropertiesGetInt(pPropData, "GENLOCK_ASYNC_PORT", -1); if (pDvcData->m_Genlock.m_AsyncPortIndex > 0) pDvcData->m_Genlock.m_AsyncPortIndex--; // Convert to port-index else pDvcData->m_Genlock.m_AsyncPortIndex = -1; // No async port // Get internal genref port pDvcData->m_Genlock.m_IntGenrefPortIndex = DtPropertiesGetInt(pPropData, "GENLOCK_INT_GENREF_PORT", -1); if (pDvcData->m_Genlock.m_IntGenrefPortIndex > 0) pDvcData->m_Genlock.m_IntGenrefPortIndex--; // Convert to port-index else pDvcData->m_Genlock.m_IntGenrefPortIndex = -1; // No internal genref port // Get slave genref port pDvcData->m_Genlock.m_SlaveGenrefPortIndex = DtPropertiesGetInt(pPropData, "GENLOCK_SLAVE_GENREF_PORT", -1); if (pDvcData->m_Genlock.m_SlaveGenrefPortIndex > 0) pDvcData->m_Genlock.m_SlaveGenrefPortIndex--; // Convert to port-index else pDvcData->m_Genlock.m_SlaveGenrefPortIndex = -1; // No slave genref port // Get the port group mask pDvcData->m_Genlock.m_PortGroup = DtPropertiesGetUInt32(pPropData, "GENLOCK_PORT_GROUP", -1); // Init to 'safe' default values pDvcData->m_Genlock.m_FracMode = DTA_GENLOCK_FRACMODE_NA; pDvcData->m_Genlock.m_RefPortIndex = pDvcData->m_Genlock.m_IntGenrefPortIndex; pDvcData->m_Genlock.m_RefVidStd = DT_VIDSTD_625I50; pDvcData->m_Genlock.m_OutVidStd = pDvcData->m_Genlock.m_RefVidStd; pDvcData->m_Genlock.m_RefLineDurationNs = pDvcData->m_Genlock.m_OutLineDurationNs = 1; pDvcData->m_Genlock.m_InDelayNs = 0; pDvcData->m_Genlock.m_LineOffset = 0; pDvcData->m_Genlock.m_TofAlignOffsetNs = 0; if (pDvcData->m_Genlock.m_GenlArch == GENLOCK_ARCH_2152 || pDvcData->m_Genlock.m_GenlArch == GENLOCK_ARCH_2154) { UInt16 Offset = -1; Offset = DtPropertiesGetUInt16(&pDvcData->m_PropData, "REGISTERS_GENL", -1); if (Offset == (UInt16)-1) { DtDbgOut(ERR, GENL, "Failed to get genlock register offset property"); return DT_STATUS_FAIL; } pDvcData->m_Genlock.m_pGenlRegs = (UInt8*)pDvcData->m_DtaRegs.m_pKernel + Offset; } else pDvcData->m_Genlock.m_pGenlRegs = NULL; if (pDvcData->m_Genlock.m_GenlArch == GENLOCK_ARCH_2152) { Status = DtaLmh1982Init(pDvcData, &pDvcData->m_Genlock.m_Lmh1982); if (!DT_SUCCESS(Status)) DtDbgOut(ERR, GENL, "Failed to init LMH-1982 module"); } else if (pDvcData->m_Genlock.m_GenlArch == GENLOCK_ARCH_2154) { // Must have an operational mode Int OpMode = DtPropertiesGetInt(pPropData, "GENLOCK_OPMODE_INTSRC", -1); if (OpMode!=GENLOCK_OPMODE_INTSRC_FREE_RUN && OpMode!=GENLOCK_OPMODE_INTSRC_AFD) { DtDbgOut(ERR, GENL, "Invalid value (%d) for 'GENLOCK_OPMODE_INTSRC' property", OpMode); return DT_STATUS_FAIL; } pDvcData->m_Genlock.m_OpModeIntSrc = OpMode; pDvcData->m_Genlock.m_VcxoValue = -1; pDvcData->m_Genlock.m_pVcxoOwner = NULL; Status = DtaLmh1983Init(pDvcData, &pDvcData->m_Genlock.m_Lmh1983); if (!DT_SUCCESS(Status)) DtDbgOut(ERR, GENL, "Failed to init LMH-1983 module"); } // 145/2145/2144 architecture if (pDvcData->m_Genlock.m_GenlArch==GENLOCK_ARCH_2144 || pDvcData->m_Genlock.m_GenlArch==GENLOCK_ARCH_145) Status = DtaFpgaGenlockInit(pDvcData, &pDvcData->m_Genlock.m_FpgaGenlock); return Status; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaEnDecIoctl -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtaEnDecIoctl( DtaDeviceData* pDvcData, DtFileObject* pFile, DtIoctlObject* pIoctl, Bool PowerDownPending) { DtStatus Status = DT_STATUS_OK; char* pCmdStr; // Mnemonic string for Command UInt InReqSize = 0; // Required length of input buffer UInt OutReqSize = 0; // Required length of output buffer Int NonIpPortIndex; // Index in the nonip port struct DtaNonIpPort* pNonIpPort = NULL; DtaIoctlEnDecCmdInput* pEnDecCmdInput = (DtaIoctlEnDecCmdInput*)pIoctl->m_pInputBuffer; DtaIoctlEnDecCmdOutput* pEnDecCmdOutput = (DtaIoctlEnDecCmdOutput*)pIoctl->m_pOutputBuffer; // Default require at least the size of the header preceding the data InReqSize = OFFSETOF(DtaIoctlEnDecCmdInput, m_Data); OutReqSize = OFFSETOF(DtaIoctlEnDecCmdOutput, m_Data); // Check if we can read m_Cmd / m_PortIndex if (pIoctl->m_InputBufferSize < InReqSize) return DT_STATUS_INVALID_PARAMETER; // Validate port index pNonIpPort = NULL; // Assume a board level request if (!DT_SUCCESS(DtaGetNonIpPortIndex(pDvcData, pEnDecCmdInput->m_PortIndex, &NonIpPortIndex))) return DT_STATUS_INVALID_PARAMETER; pNonIpPort = &pDvcData->m_pNonIpPorts[NonIpPortIndex]; if (!pNonIpPort->m_CapAvEnc) return DT_STATUS_NOT_SUPPORTED; // Determine final required output/input sizes switch (pEnDecCmdInput->m_Cmd) { case DTA_ENDEC_CMD_EXCLUSIVE_ACCESS: pCmdStr = "DTA_ENDEC_CMD_EXCLUSIVE_ACCESS"; InReqSize += sizeof(DtaIoctlNonIpCmdExclusiveAccessInput); OutReqSize = 0; break; case DTA_ENDEC_CMD_GET_SOURCE_PORT: pCmdStr = "DTA_ENDEC_CMD_GET_SOURCE_PORT"; InReqSize = 0; OutReqSize += sizeof(DtaIoctEnDecCmdGetSourcePortOutput); break; case DTA_ENDEC_CMD_SET_SOURCE_PORT: pCmdStr = "DTA_ENDEC_CMD_SET_SOURCE_PORT"; InReqSize += sizeof(DtaIoctEnDecCmdSetSourcePortInput); OutReqSize = 0; break; case DTA_ENDEC_CMD_GET_VIDSTD: pCmdStr = "DTA_ENDEC_CMD_GET_VIDSTD"; InReqSize = 0; OutReqSize += sizeof(DtaIoctEnDecCmdGetVidStdOutput); break; case DTA_ENDEC_CMD_SET_VIDSTD: pCmdStr = "DTA_ENDEC_CMD_SET_VIDSTD"; InReqSize += sizeof(DtaIoctEnDecCmdSetVidStdInput); OutReqSize = 0; break; default: pCmdStr = "??UNKNOWN ENDEC_CMD CODE??"; Status = DT_STATUS_NOT_SUPPORTED; } if (DT_SUCCESS(Status)) { // Check buffer sizes if (pIoctl->m_InputBufferSize < InReqSize) { DtDbgOut(ERR, D7PRO, "%s: INPUT BUFFER TOO SMALL Size=%d Req=%d", pCmdStr, pIoctl->m_InputBufferSize, InReqSize); return DT_STATUS_INVALID_PARAMETER; } if (pIoctl->m_OutputBufferSize < OutReqSize) { DtDbgOut(ERR, D7PRO, "%s: OUTPUT BUFFER TOO SMALL Size=%d Req=%d", pCmdStr, pIoctl->m_OutputBufferSize, OutReqSize); return DT_STATUS_INVALID_PARAMETER; } DtDbgOut(MAX, D7PRO, "%s: In=%d (Rq=%d), Out=%d (Rq=%d)", pCmdStr, pIoctl->m_InputBufferSize, InReqSize, pIoctl->m_OutputBufferSize, OutReqSize); } // The bytes written will be updated if needed. Set the default value here. pIoctl->m_OutputBufferBytesWritten = OutReqSize; if (DT_SUCCESS(Status)) { switch (pEnDecCmdInput->m_Cmd) { case DTA_ENDEC_CMD_EXCLUSIVE_ACCESS: Status = DtaEnDecExclusiveAccess(pNonIpPort, pFile, pEnDecCmdInput->m_Data.m_ExclusiveAccess.m_Cmd); break; case DTA_ENDEC_CMD_GET_SOURCE_PORT: Status = DtaEnDecGetSourcePort(pNonIpPort, &pEnDecCmdOutput->m_Data.m_GetSourcePort.m_PortIndex); break; case DTA_ENDEC_CMD_SET_SOURCE_PORT: Status = DtaEnDecSetSourcePort(pNonIpPort, pEnDecCmdInput->m_Data.m_SetSourcePort.m_PortIndex); break; case DTA_ENDEC_CMD_GET_VIDSTD: Status = DtaEnDecGetVidStd(pNonIpPort, &pEnDecCmdOutput->m_Data.m_GetVidStd.m_VidStd); break; case DTA_ENDEC_CMD_SET_VIDSTD: Status = DtaEnDecSetVidStd(pNonIpPort, pEnDecCmdInput->m_Data.m_SetVidStd.m_VidStd); break; } } // If we failed, no data has to be copied to user space if (!DT_SUCCESS(Status)) { pIoctl->m_OutputBufferBytesWritten = 0; if (Status == DT_STATUS_NOT_SUPPORTED) DtDbgOut(MIN, D7PRO, "EnDecCmd=0x%x: NOT SUPPORTED", pEnDecCmdInput->m_Cmd); else if (Status == DT_STATUS_IO_PENDING) DtDbgOut(MAX, D7PRO, "%s: ERROR %xh", pCmdStr, Status); // NOT A REAL ERROR else DtDbgOut(MIN, D7PRO, "%s: ERROR %xh", pCmdStr, Status); } 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; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtNonVolatileSettingsDelete -.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtNonVolatileSettingsDelete( DtDrvObject* pDrvObj, UInt64 DvcSerial, UInt NumPorts) { DtStatus Status = DT_STATUS_OK; #ifdef WINBUILD NTSTATUS NtStatus; DtString RegKeyName; Int i; // Allocate RegKeyName buffer Status = DtStringAlloc(&RegKeyName, 150); if (!DT_SUCCESS(Status)) return Status; // Remove all port settings for (i = 0; i < (Int)NumPorts; i++) { Status = DtStringClear(&RegKeyName); if (!DT_SUCCESS(Status)) { DtStringFree(&RegKeyName); return Status; } Status = PathAppendSettingsSerialPortCategory(&RegKeyName, DvcSerial, i, NULL); if (!DT_SUCCESS(Status)) { DtStringFree(&RegKeyName); return Status; } // First delete all subitems of PortX (=Categories) NtStatus = DriverParametersSubKeyDelete(pDrvObj->m_WdfDriver, &RegKeyName); // Delete registry item: PortX NtStatus = DriverParametersKeyDelete(pDrvObj->m_WdfDriver, &RegKeyName); } // Remove the device settings Status = DtStringClear(&RegKeyName); if (!DT_SUCCESS(Status)) { DtStringFree(&RegKeyName); return Status; } Status = PathAppendSettingsSerialDeviceCategory(&RegKeyName, DvcSerial, NULL); if (!DT_SUCCESS(Status)) { DtStringFree(&RegKeyName); return Status; } // First delete all subitems of device(=Categories) NtStatus = DriverParametersSubKeyDelete(pDrvObj->m_WdfDriver, &RegKeyName); // Delete registry item: Device NtStatus = DriverParametersKeyDelete(pDrvObj->m_WdfDriver, &RegKeyName); // Now remove the serial number Status = DtStringClear(&RegKeyName); if (!DT_SUCCESS(Status)) { DtStringFree(&RegKeyName); return Status; } // Create path without port number Status = PathAppendSettingsSerialPortCategory(&RegKeyName, DvcSerial, -1, NULL); if (!DT_SUCCESS(Status)) { DtStringFree(&RegKeyName); return Status; } // Delete registry item: serial number NtStatus = DriverParametersKeyDelete(pDrvObj->m_WdfDriver, &RegKeyName); if (!NT_SUCCESS(NtStatus)) { DtStringFree(&RegKeyName); return DT_STATUS_FAIL; } DtStringFree(&RegKeyName); #else // Not yet implemented in Linux. Status = DT_STATUS_OK; #endif 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; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DriverParametersSubKeyDelete -.-.-.-.-.-.-.-.-.-.-.-.-.-.- // NTSTATUS DriverParametersSubKeyDelete( WDFDRIVER Driver, DtString* pKeyName) { NTSTATUS NtStatus = STATUS_SUCCESS; DtStringChar* pRegistryPath; DtString RegistryPath; DtString FullKeyName; UInt PathLength; HANDLE hKey; OBJECT_ATTRIBUTES ObjectAttributes; KEY_BASIC_INFORMATION* pKeyInfo; ULONG Size; ULONG ResultSize; Int Index; DT_STRING_DECL(ParamItemName, "\\Parameters\\"); DT_ASSERT(KeGetCurrentIrql()<=PASSIVE_LEVEL); // Build the full path pRegistryPath = WdfDriverGetRegistryPath(Driver); PathLength = wcslen(pRegistryPath); DT_STRING_INIT_CONST(RegistryPath, pRegistryPath, PathLength); // Allocate struct for key information result Size = sizeof(KEY_BASIC_INFORMATION)+100; pKeyInfo = DtMemAllocPool(DtPoolNonPaged, Size, SAL_TAG); if (pKeyInfo == NULL) return STATUS_NO_MEMORY; // Allocate a new DtString buffer for the complete path inclusive a '\0' character // and extra '\\' if (!DT_SUCCESS(DtStringAlloc(&FullKeyName, PathLength+ DtStringGetStringLength(&ParamItemName)+ DtStringGetStringLength(pKeyName)+ 100+1+1))) { DtMemFreePool(pKeyInfo, SAL_TAG); return STATUS_NO_MEMORY; } DtStringAppendDtString(&FullKeyName, &RegistryPath); DtStringAppendDtString(&FullKeyName, &ParamItemName); DtStringAppendDtString(&FullKeyName, pKeyName); // Initialize key to open InitializeObjectAttributes(&ObjectAttributes, &FullKeyName, OBJ_KERNEL_HANDLE, NULL, NULL); NtStatus = ZwOpenKey(&hKey, KEY_ENUMERATE_SUB_KEYS , &ObjectAttributes); if (NT_SUCCESS(NtStatus)) { Index = 0; NtStatus = STATUS_SUCCESS; // Enumerate all keys while (NtStatus != STATUS_NO_MORE_ENTRIES) { NtStatus = ZwEnumerateKey(hKey, Index, KeyBasicInformation, pKeyInfo, Size, &ResultSize); if (NT_SUCCESS(NtStatus)) { DtString SubKey; // Build key to delete pKeyInfo->Name[pKeyInfo->NameLength/2] = L'\0'; DT_STRING_INIT_CONST(SubKey, pKeyInfo->Name, ((USHORT)pKeyInfo->NameLength/2)); DtStringClear(&FullKeyName); DtStringAppendDtString(&FullKeyName, pKeyName); DtStringAppendChars(&FullKeyName, "\\"); DtStringAppendDtString(&FullKeyName, &SubKey); DtDbgOut(MAX, SAL, "Delete SubKey %S.", FullKeyName.Buffer); NtStatus = DriverParametersKeyDelete(Driver, &FullKeyName); if (!NT_SUCCESS(NtStatus)) DtDbgOut(ERR, SAL, "Error deleting SubKey %S. Error: %x", FullKeyName.Buffer, NtStatus); } // In case deletion failed, skip this entry if (!NT_SUCCESS(NtStatus)) Index++; } NtStatus = ZwDeleteKey(hKey); ZwClose(hKey); } DtMemFreePool(pKeyInfo, SAL_TAG); DtStringFree(&FullKeyName); return NtStatus; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtTableGet -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtTableGet( DtPropertyData* pPropData, const char* pTableName, Int PortIndex, UInt MaxNumEntries, UInt* pNumEntries, DtTableEntry* pTableEntry2, UInt OutBufSize) { DtStatus Status = DT_STATUS_OK; const DtTableStore* pStore = (DtTableStore*)pPropData->m_pTableStore; Int HwRevision = pPropData->m_HardwareRevision; Int FwVariant = pPropData->m_FirmwareVariant; Bool TableNameFound = FALSE; Int FindCount = 0; UInt Index; DtTableLink* pTableLinkFound = NULL; // For devices with no 'EC' VPD resource and no registry key which forces the // hardware revision, treat the hardware revision as 0 if (HwRevision < 0) HwRevision = 0; *pNumEntries = 0; if (pPropData->m_pTableStore == NULL) { DtDbgOut(ERR, TABLE, "There are no tables defined at all for DTX-%d", pPropData->m_TypeNumber); return DT_STATUS_NOT_FOUND; } // If the property is not found for a specific fw-variant try a second time // without specifying a specific fw-variant for (FindCount=0; FindCount<2 && pTableLinkFound==NULL; FindCount++) { if (FindCount == 1) FwVariant = -1; TableNameFound = FALSE; // Search all tables for (Index=0; Index<pStore->m_TableLinkCount; Index++) { const DtTableLink* pTableLink = &pStore->m_pTableLink[Index]; // Check if the table name was already found. If so, we stop if // name <> NULL. if (TableNameFound) { // When the table name was found earlier, only accept entries without // a name. We just stop when (another) named entry is found. if (pTableLink->m_pName != NULL) break; } else { // Compare name to check if we found the first occurrence if (DtAnsiCharArrayIsEqual(pTableName, pTableLink->m_pName)) TableNameFound = TRUE; } if (TableNameFound) { // Check port number and firmware variant if (PortIndex==pTableLink->m_PortIndex && FwVariant==pTableLink->m_FwVariant) { // Check minimal firmware version if (pPropData->m_FirmwareVersion >= pTableLink->m_MinFw) { // Check minimal hardware version if (HwRevision >= pTableLink->m_MinHw) { pTableLinkFound = (DtTableLink*)pTableLink; // We can stop here since the parser has ordened each // property by minimal firmware version/hardware version. // This means the first hit is the best one break; } } } } } } if (!TableNameFound) { DtDbgOut(ERR, TABLE, "Table %s is not found at all for DTX-%d", pTableName, pStore->m_TypeNumber); Status = DT_STATUS_NOT_FOUND; } // Check if the table was found if (pTableLinkFound == NULL) { Status = DT_STATUS_NOT_FOUND; DtDbgOut(ERR, TABLE, "Failed to get table %s for DTX-%d:%d, FW %d, HW %d port %i", pTableName, pPropData->m_TypeNumber, pPropData->m_SubDvc, pPropData->m_FirmwareVersion, pPropData->m_HardwareRevision, PortIndex); } if (DT_SUCCESS(Status) && pTableLinkFound!=NULL) { DtDbgOut(MAX, TABLE, "Found table %s for DTX-%d:%d, FW %d, HW %d. #EL:%i #MAX:%i" , pTableName, pPropData->m_TypeNumber, pPropData->m_SubDvc, pPropData->m_FirmwareVersion, pPropData->m_HardwareRevision, pTableLinkFound->m_TableEntryCount, MaxNumEntries); *pNumEntries = pTableLinkFound->m_TableEntryCount; // Check if enough space for the table if (MaxNumEntries < pTableLinkFound->m_TableEntryCount) { if (MaxNumEntries != 0) DtDbgOut(ERR, TABLE, "Max. number of entries to small. Needed:%i, " "Space for:%i", pTableLinkFound->m_TableEntryCount, MaxNumEntries); } else if (OutBufSize < pTableLinkFound->m_TableEntryCount * sizeof(DtTableEntry)) { DtDbgOut(ERR, TABLE, "Buffer smaller than indicated by MaxNumEntries"); Status = DT_STATUS_INVALID_PARAMETER; } else { // Copy table DtMemCopy(pTableEntry2, (void*)pTableLinkFound->m_pTableEntries, pTableLinkFound->m_TableEntryCount * sizeof(DtTableEntry)); } } return Status; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaNonIpTxIoctl -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtaNonIpTxIoctl( DtaDeviceData* pDvcData, DtFileObject* pFile, DtIoctlObject* pIoctl) { DtStatus Status = DT_STATUS_OK; char* pCmdStr; // Mnemonic string for Command UInt InReqSize = 0; // Required length of input buffer UInt OutReqSize = 0; // Required length of output buffer Int NonIpPortIndex; // Index in the nonip port struct DtaIoctlNonIpTxCmdInput* pNonIpTxCmdInput = (DtaIoctlNonIpTxCmdInput*)pIoctl->m_pInputBuffer; DtaIoctlNonIpTxCmdOutput* pNonIpTxCmdOutput = (DtaIoctlNonIpTxCmdOutput*)pIoctl->m_pOutputBuffer; // Default require at least the size of the header preceding the data InReqSize = OFFSETOF(DtaIoctlNonIpTxCmdInput, m_Data); OutReqSize = OFFSETOF(DtaIoctlNonIpTxCmdOutput, m_Data); // Check if we can read m_Cmd / m_PortIndex if (pIoctl->m_InputBufferSize < InReqSize) return DT_STATUS_INVALID_PARAMETER; // Validate port index if (!DT_SUCCESS(DtaGetNonIpPortIndex(pDvcData, pNonIpTxCmdInput->m_PortIndex, &NonIpPortIndex))) return DT_STATUS_INVALID_PARAMETER; // Determine final required output/input sizes switch (pNonIpTxCmdInput->m_Cmd) { case DTA_NONIP_TX_CMD_GET_FLAGS: pCmdStr = "DTA_NONIP_TX_CMD_GET_FLAGS"; OutReqSize += sizeof(DtaIoctlNonIpTxCmdGetFlagsOutput); // We expect no additional data in the input buffer InReqSize += 0; break; case DTA_NONIP_TX_CMD_CLEAR_FLAGS: pCmdStr = "DTA_NONIP_TX_CMD_CLEAR_FLAGS"; InReqSize += sizeof(DtaIoctlNonIpTxCmdClearFlagsInput); // We expect no output buffer at all OutReqSize = 0; break; case DTA_NONIP_TX_CMD_SET_FAILSAFE_CFG: pCmdStr = "DTA_NONIP_TX_CMD_SET_FAILSAFE_CFG"; InReqSize += sizeof(DtaIoctlNonIpTxCmdSetFailsafeCfgInput); // We expect no output buffer at all OutReqSize = 0; break; case DTA_NONIP_TX_CMD_SET_FAILSAFE_ALIVE: pCmdStr = "DTA_NONIP_TX_CMD_SET_FAILSAFE_ALIVE"; // We expect no additional data in the input buffer InReqSize += 0; // We expect no output buffer at all OutReqSize = 0; break; case DTA_NONIP_TX_CMD_GET_FAILSAFE_INFO: pCmdStr = "DTA_NONIP_TX_CMD_GET_FAILSAFE_INFO"; OutReqSize += sizeof(DtaIoctlNonIpTxCmdGetFailsafeInfoOutput); // We expect no additional data in the input buffer InReqSize += 0; break; default: pCmdStr = "??UNKNOWN VPDCMD CODE??"; Status = DT_STATUS_NOT_SUPPORTED; } if (DT_SUCCESS(Status)) { // Check buffer sizes if (pIoctl->m_InputBufferSize < InReqSize) { DtDbgOut(ERR, NONIP, "%s: INPUT BUFFER TOO SMALL Size=%d Req=%d", pCmdStr, pIoctl->m_InputBufferSize, InReqSize); return DT_STATUS_INVALID_PARAMETER; } if (pIoctl->m_OutputBufferSize < OutReqSize) { DtDbgOut(ERR, NONIP, "%s: OUTPUT BUFFER TOO SMALL Size=%d Req=%d", pCmdStr, pIoctl->m_OutputBufferSize, OutReqSize); return DT_STATUS_INVALID_PARAMETER; } DtDbgOut(MAX, NONIP, "%s: In=%d (Rq=%d), Out=%d (Rq=%d)", pCmdStr, pIoctl->m_InputBufferSize, InReqSize, pIoctl->m_OutputBufferSize, OutReqSize); } // The bytes written will be updated if needed. Set the default value here. pIoctl->m_OutputBufferBytesWritten = OutReqSize; if (DT_SUCCESS(Status)) { // Execute cmd switch (pNonIpTxCmdInput->m_Cmd) { case DTA_NONIP_TX_CMD_GET_FLAGS: Status = DtaNonIpTxGetFlags(&pDvcData->m_pNonIpPorts[NonIpPortIndex], &pNonIpTxCmdOutput->m_Data.m_GetFlags.m_Status, &pNonIpTxCmdOutput->m_Data.m_GetFlags.m_Latched); break; case DTA_NONIP_TX_CMD_CLEAR_FLAGS: Status = DtaNonIpTxClearFlags(&pDvcData->m_pNonIpPorts[NonIpPortIndex], pNonIpTxCmdInput->m_Data.m_ClearFlags.m_FlagsToClear); break; case DTA_NONIP_TX_CMD_SET_FAILSAFE_CFG: Status = DtaNonIpTxSetFailsafeCfg(&pDvcData->m_pNonIpPorts[NonIpPortIndex], pNonIpTxCmdInput->m_Data.m_SetFailsafeCfg.m_Enable, pNonIpTxCmdInput->m_Data.m_SetFailsafeCfg.m_Timeout); break; case DTA_NONIP_TX_CMD_SET_FAILSAFE_ALIVE: Status = DtaNonIpTxSetFailsafeAlive(&pDvcData->m_pNonIpPorts[NonIpPortIndex]); break; case DTA_NONIP_TX_CMD_GET_FAILSAFE_INFO: Status = DtaNonIpTxGetFailsafeInfo(&pDvcData->m_pNonIpPorts[NonIpPortIndex], &pNonIpTxCmdOutput->m_Data.m_GetFailsafeInfo.m_Enable, &pNonIpTxCmdOutput->m_Data.m_GetFailsafeInfo.m_Timeout, &pNonIpTxCmdOutput->m_Data.m_GetFailsafeInfo.m_Alive); 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, NONIP, "NonIpTxCmd=0x%x: NOT SUPPORTED", pNonIpTxCmdInput->m_Cmd); else DtDbgOut(MIN, NONIP, "%s: ERROR %xh", pCmdStr, Status); } return Status; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtPropertiesFind -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtPropertiesFind(DtPropertyData* pPropData, const char* pName, Int PortIndex, const DtProperty** ppProperty, Int DtapiMaj, Int DtapiMin, Int DtapiBugfix) { DtStatus Status = DT_STATUS_OK; const DtPropertyStore* pStore = (DtPropertyStore*)pPropData->m_pPropertyStore; const DtPropertyHashSet* pHashSets = (DtPropertyHashSet*)pStore->m_pPropertyHashSets; UInt HashSetCount = pStore->m_PropertyHashSetCount; Int FwVersion = pPropData->m_FirmwareVersion; Int HwRevision = pPropData->m_HardwareRevision; Int FwVariant = pPropData->m_FirmwareVariant; UInt Hash = 0; Int Index; Int FindCount = 0; Bool PropertyNameFound = FALSE; const DtPropertyHashSet* pHashSet = NULL; Int PropertyCount = 0; *ppProperty = NULL; // For devices with no 'EC' VPD resource and no registry key which forces the // hardware revision, treat the hardware revision as 0 if (HwRevision < 0) HwRevision = 0; // Determine the name hash Hash = DtDjb2(pName) % HashSetCount; // Get correct hash set (if it exists) if (DT_SUCCESS(Status)) { pHashSet = &pHashSets[Hash]; PropertyCount = pHashSets[Hash].m_PropertyCount; // Check if a hash set was available for this hash value if (pHashSet == NULL) Status = DT_STATUS_NOT_FOUND; } if (DT_SUCCESS(Status)) { // If the property is not found for a specific fw-variant try a second time // without specifying a specific fw-variant for (FindCount=0; FindCount<2 && *ppProperty==NULL; FindCount++) { if (FindCount == 1) FwVariant = -1; // Get correct property entry within hash set PropertyNameFound = FALSE; // Search all properties for (Index=0; Index<PropertyCount; Index++) { const DtProperty* pProp = &pHashSet->m_pProperties[Index]; // Check the property name was already found if (PropertyNameFound) { // When the property name was found earlier, only accept entries // without a name. We just stop when (another) named entry is found. if (pProp->m_pName != NULL) break; } else { // Compare name to check if we found the first occurrence if (DtAnsiCharArrayIsEqual(pName, pProp->m_pName)) PropertyNameFound = TRUE; } if (PropertyNameFound) { // Check port number and firmware variant if (PortIndex==pProp->m_PortIndex && FwVariant==pProp->m_FwVariant) { // Check minimal firmware version and hardware version if (FwVersion>=pProp->m_MinFw && HwRevision>=pProp->m_MinHw && (pProp->m_MaxHw==-1 || HwRevision<pProp->m_MaxHw)) { Bool DtapiVerOk = FALSE; // -1 means the request came from the driver if (DtapiMaj==-1 && DtapiMin==-1 && DtapiBugfix==-1) DtapiVerOk = TRUE; else if (DtapiMaj > pProp->m_MinDtapiMaj) DtapiVerOk = TRUE; else if (DtapiMaj==pProp->m_MinDtapiMaj) { if (DtapiMin > pProp->m_MinDtapiMin) DtapiVerOk = TRUE; else if (DtapiMin==pProp->m_MinDtapiMin && DtapiBugfix>= pProp->m_MinDtapiBugfix) DtapiVerOk = TRUE; } // Check minimal DTAPI version if (DtapiVerOk) { *ppProperty = pProp; // We can stop here since the parser has ordered each // property by minimal firmware version/hardware version. // This means the first hit is the best one... break; } } } } } } if (!PropertyNameFound) { if (DtAnsiCharArrayStartsWith(pName, "CAP_")) DtDbgOut(AVG, PROP, "PropertyName(Capability) %s is not found at all for" " %s-%d", pName, pPropData->m_TypeName, pPropData->m_TypeNumber); else DtDbgOut(MIN, PROP, "PropertyName %s is not found at all for %s-%d", pName, pPropData->m_TypeName, pPropData->m_TypeNumber); } // Check if the property was found if (*ppProperty == NULL) { Status = DT_STATUS_NOT_FOUND; DtDbgOut(AVG, PROP, "Failed to find property %s for %s-%d, FW %d, HW %d" "VAR %d", pName, pPropData->m_TypeName, pPropData->m_TypeNumber, pPropData->m_FirmwareVersion, pPropData->m_HardwareRevision, pPropData->m_FirmwareVariant); } } 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; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtNonVolatileManufSettingsRead -.-.-.-.-.-.-.-.-.-.-.-.-.-. // // Read a registry key from the manufacturing section, e.g. from // ../Dta/Parameters/Settings/Manuf/2137/ForcedHardwareRevision // DtStatus DtNonVolatileManufSettingsRead( DtDrvObject* pSalDrvObj, Int Type, Char* pName, Int64* pBinValue) { DtStatus Status = DT_STATUS_OK; #ifdef WINBUILD // Windows uses the registry to store non volatile settings NTSTATUS NtStatus; DtString RegKeyName; DtString ValueName; // Allocate RegKeyName buffer Status = DtStringAlloc(&RegKeyName, 150); if (DT_SUCCESS(Status)) { Status = DtStringAlloc(&ValueName, 40); if (DT_SUCCESS(Status)) { // Create registry path string DT_STRING_DECL(SettingsStr, "Settings\\Manuf\\"); // Registry path starts with <\Settings\Manuf\> Status = DtStringAppendDtString(&RegKeyName, &SettingsStr); if (DT_SUCCESS(Status) && Type!=-1) // Convert type to unicode string and append to path Status = DtStringUIntegerToDtStringAppend(&RegKeyName, 10, (UInt)(Type)); if (DT_SUCCESS(Status)) { // Convert value name to DtString Status = DtStringAppendChars(&ValueName, pName); if (DT_SUCCESS(Status)) { // Read register binary value NtStatus = DriverParametersKeyRead(pSalDrvObj->m_WdfDriver, &RegKeyName, &ValueName, pBinValue, NULL); if (!NT_SUCCESS(NtStatus)) { Status = DT_STATUS_FAIL; // Be more specific if object name was not found if (NtStatus == STATUS_OBJECT_NAME_NOT_FOUND) Status = DT_STATUS_NOT_FOUND; } } } // Free ValueName DtStringFree(&ValueName); } // Free RegKeyName DtStringFree(&RegKeyName); } #else // Not yet implemented in Linux. Status = DT_STATUS_NOT_FOUND; #endif return Status; }