/* * Video On Demand Samples * * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * You may also obtain this software under a propriety license from Microchip. * Please contact Microchip for further information. * */ #include #include #include #include #include #include "DriverConfiguration.h" #include "Console.h" static bool WriteCharactersToFile( const char *pFileName, const char *pString ) { bool success = false; FILE *fh = fopen( pFileName, "a" ); if( NULL != fh ) { int result = fputs( pString, fh ); if( result >= 0 ) fputc( '\n', fh ); if( result >= 0 ) success = true; fclose( fh ); } if( success ) ConsolePrintf( PRIO_MEDIUM, "*** configured device: '%s = %s', success:%d\n", pFileName, pString, success ); else ConsolePrintf( PRIO_ERROR, RED"DriverConfiguration.WriteCharactersToFile failed for file '%s', errno:'%s'"RESETCOLOR"\n", pFileName, GetErrnoString() ); return success; } static bool WriteIntegerToFile( const char *pFileName, int intValue ) { char tempBuffer[16]; snprintf( tempBuffer, sizeof( tempBuffer ), "%d", intValue ); return WriteCharactersToFile( pFileName, tempBuffer ); } static bool ReadFromFile( const char *pFileName, char *pString, uint16_t bufferLen ) { bool success = false; if( NULL == pString || 0 == bufferLen ) return success; FILE *fh = fopen( pFileName, "r" ); if( NULL != fh ) { success = ( NULL != fgets( pString, bufferLen, fh ) ); fclose( fh ); } if( !success ) ConsolePrintf( PRIO_ERROR, RED"DriverConfiguration.ReadFromFile failed for file '%s', errno:'%s'"RESETCOLOR"\n", pFileName, GetErrnoString() ); return success; } static bool ExistsDevice( const char *pDeviceName ) { struct stat buffer; return ( stat( pDeviceName, &buffer ) == 0 ); } static bool WaitForDevice( const char *pDeviceName ) { int timeout; bool deviceExists = false; for( timeout = 0; timeout < 40; timeout++ ) { deviceExists = ExistsDevice( pDeviceName ); if( deviceExists ) { break; } else { usleep( 2500 ); } } if( !deviceExists ) ConsolePrintf( PRIO_ERROR, RED"Waiting for device '%s' to appear, timed out"RESETCOLOR"\n", pDeviceName ); return deviceExists; } static bool GetDeviceDescription( uint8_t deviceInstance, char *deviceString, uint32_t stringLen ) { bool descriptionFound = false; char descriptionPath[64]; char descriptionValue[32]; if( NULL == deviceString ) return descriptionFound; snprintf( descriptionPath, sizeof( descriptionPath ), "/sys/devices/virtual/most/mostcore/devices/mdev%d/description", deviceInstance ); if( !ExistsDevice( descriptionPath ) ) return descriptionFound; descriptionFound = ReadFromFile( descriptionPath, descriptionValue, sizeof( descriptionValue ) ); if( descriptionFound ) { strncpy( deviceString, descriptionValue, stringLen ); } return descriptionFound; } static bool ExistsDeviceWithType( uint8_t deviceInstance, const char *deviceString, uint32_t stringLen ) { bool deviceFound = false; char interfacePath[64]; char interfaceValue[32]; if( NULL == deviceString ) return deviceFound; snprintf( interfacePath, sizeof( interfacePath ), "/sys/devices/virtual/most/mostcore/devices/mdev%d/interface", deviceInstance ); if( !ExistsDevice( interfacePath ) ) return deviceFound; deviceFound = ReadFromFile( interfacePath, interfaceValue, sizeof( interfaceValue ) ); if( deviceFound ) { deviceFound = ( 0 == strncmp( interfaceValue, deviceString, stringLen ) ); } return deviceFound; } static bool GetAlsaConfiguration( uint16_t subBufferSize, uint8_t *amountOfChannels, uint8_t *bitDepth ) { if( NULL == amountOfChannels || NULL == bitDepth ) { ConsolePrintf( PRIO_ERROR, RED"GetAlsaConfiguration was called with invalid parameters"RESETCOLOR"\n" ); return false; } switch( subBufferSize ) { case 2: *amountOfChannels = 1; *bitDepth = 16; break; case 4: *amountOfChannels = 2; *bitDepth = 16; break; case 6: *amountOfChannels = 2; *bitDepth = 24; break; case 8: *amountOfChannels = 2; *bitDepth = 32; break; case 12: *amountOfChannels = 6; *bitDepth = 16; break; case 18: *amountOfChannels = 6; *bitDepth = 24; break; case 16: *amountOfChannels = 8; *bitDepth = 16; break; case 24: *amountOfChannels = 8; *bitDepth = 24; break; default: ConsolePrintf( PRIO_ERROR, RED"Configure ALSA device was called"\ " with unknown sub-buffer size: %d"RESETCOLOR"\n", subBufferSize ); return false; } return true; } bool ExistsUsbDeviceInstance( uint8_t deviceInstance ) { uint32_t i; bool found = false; uint8_t curDevInst = 0; char lastDescr[64]; lastDescr[0] = '\0'; for( i = 0; i < 12; i++ ) { uint32_t curDescrLen; char curDescr[64]; if( !ExistsDeviceWithType( i, "usb", 3 ) ) continue; if( !GetDeviceDescription( i, curDescr, sizeof( curDescr ) ) ) continue; curDescrLen = strnlen( curDescr, sizeof( curDescr ) ); if( curDescrLen <= 2 ) continue; //Cut away the last two characters, as they are different for the 3 interfaces of INIC curDescrLen -= 2; if( 0 == strncmp( curDescr, lastDescr, curDescrLen ) ) continue; strncpy( lastDescr, curDescr, curDescrLen ); lastDescr[curDescrLen] = '\0'; if( curDevInst++ != deviceInstance ) continue; found = true; break; } return found; } bool ExistsMlbDeviceInstance( uint8_t deviceInstance ) { return ExistsDeviceWithType( deviceInstance, "mlb", 3 ); } bool ExistsI2CDeviceInstance( uint8_t deviceInstance ) { return ExistsDeviceWithType( deviceInstance, "i2c", 3 ); } bool GetUsbDeviceNames( uint8_t deviceInstance, uint8_t endpointAddress, char *deviceName, uint16_t deviceNameLength, char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) { uint32_t i; bool systemFound = false; uint8_t curDevInst = 0; char lastDescr[64]; lastDescr[0] = '\0'; char endpointBuffer[16]; char systemSourceDir[64]; DIR *d; struct dirent *dir; if( NULL == deviceName || NULL == systemName || NULL == linkName ) return false; deviceName[0] = '\0'; systemName[0] = '\0'; for( i = 0; !systemFound && i < 12; i++ ) { uint32_t curDescrLen; char curDescr[64]; if( !ExistsDeviceWithType( i, "usb", 3 ) ) continue; if( !GetDeviceDescription( i, curDescr, sizeof( curDescr ) ) ) continue; curDescrLen = strnlen( curDescr, sizeof( curDescr ) ); if( curDescrLen <= 2 ) continue; //Cut away the last two characters, as they are different for the 3 interfaces of INIC curDescrLen -= 2; if( ( '\0' != lastDescr[0] ) && ( 0 != strncmp( curDescr, lastDescr, curDescrLen ) ) ) { ++curDevInst; } strncpy( lastDescr, curDescr, curDescrLen ); lastDescr[curDescrLen] = '\0'; if( curDevInst < deviceInstance ) continue; else if( curDevInst > deviceInstance ) break; snprintf( endpointBuffer, sizeof( endpointBuffer ), "ep%02x", endpointAddress ); snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", i ); d = opendir( systemSourceDir ); if( d ) { while( ( dir = readdir( d ) ) != NULL ) { if( strstr( dir->d_name, endpointBuffer ) ) { snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", i, dir->d_name, deviceInstance, dir->d_name ); systemFound = true; break; } } closedir( d ); } } return systemFound; } bool GetMlbDeviceNames( uint8_t deviceInstance, uint8_t mlbChannelAddress, char *deviceName, uint16_t deviceNameLength, char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) { bool systemFound = false; char channelBuffer[16]; char systemSourceDir[64]; DIR *d; struct dirent *dir; if( NULL == deviceName || NULL == systemName || NULL == linkName ) return false; deviceName[0] = '\0'; systemName[0] = '\0'; snprintf( channelBuffer, sizeof( channelBuffer ), "ca%d", mlbChannelAddress ); snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", deviceInstance ); d = opendir( systemSourceDir ); if( d ) { while( ( dir = readdir( d ) ) != NULL ) { if( strstr( dir->d_name, channelBuffer ) ) { snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", deviceInstance, dir->d_name, deviceInstance, dir->d_name ); systemFound = true; break; } } closedir( d ); } return systemFound; } bool GetI2CDeviceNames( uint8_t deviceInstance, bool isTx, char *deviceName, uint16_t deviceNameLength, char *systemName, uint16_t systemNameLength, char *linkName, uint16_t linkNameLength ) { bool systemFound = false; char systemSourceDir[64]; DIR *d; struct dirent *dir; if( NULL == deviceName || NULL == systemName || NULL == linkName ) return false; deviceName[0] = '\0'; systemName[0] = '\0'; snprintf( systemSourceDir, sizeof( systemSourceDir ), "/sys/devices/virtual/most/mostcore/devices/mdev%d", deviceInstance ); d = opendir( systemSourceDir ); if( d ) { while( ( dir = readdir( d ) ) != NULL ) { if( strstr( dir->d_name, ( isTx ? "tx" : "rx" ) ) ) { snprintf( systemName, systemNameLength, "%s/%s", systemSourceDir, dir->d_name ); snprintf( deviceName, deviceNameLength, "/dev/mdev%d-%s", deviceInstance, dir->d_name ); snprintf( linkName, linkNameLength, "mdev%d:%s:mdev%d-%s", deviceInstance, dir->d_name, deviceInstance, dir->d_name ); systemFound = true; break; } } closedir( d ); } return systemFound; } bool CloseMostChannel( const char *device ) { return true; } bool ConfigureMostChannel( const char *device, EPDataType_t mostType, EPDirection_t direction, uint32_t numBuf, uint32_t bufSize ) { static const char *controlType = "control"; static const char *asyncType = "async"; static const char *syncType = "sync"; static const char *isocType = "isoc_avp"; static const char *rxDirection = "dir_rx"; static const char *txDirection = "dir_tx"; bool success = true; char tempBuffer[128]; const char *typeString = NULL; const char *directionString = NULL; switch( mostType ) { case EP_Control: typeString = controlType; break; case EP_Asynchron: typeString = asyncType; break; case EP_Synchron: typeString = syncType; break; case EP_Isochron: typeString = isocType; break; default: return false; } switch( direction ) { case EPDIR_IN: directionString = txDirection; break; case EPDIR_OUT: directionString = rxDirection; break; default: return false; } snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_datatype", device ); /// Setting data type success = WriteCharactersToFile( tempBuffer, typeString ); if( success ) { snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_direction", device ); /// Setting direction success = WriteCharactersToFile( tempBuffer, directionString ); } if( success ) { snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_number_of_buffers", device ); /// Setting amount of buffers success = WriteIntegerToFile( tempBuffer, numBuf ); } if( success ) { snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_buffer_size", device ); /// Setting amount of buffers success = WriteIntegerToFile( tempBuffer, bufSize ); } return success; } bool ConfigureIsocChannel( const char *device, uint32_t subbufferSize, uint32_t packetsPerTransaction ) { char tempBuffer[128]; bool success; snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_subbuffer_size", device ); /// Setting the subbuffer size in bytes success = WriteIntegerToFile( tempBuffer, subbufferSize ); snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_packets_per_xact", device ); /// Setting the packets per transaction success = WriteIntegerToFile( tempBuffer, ( packetsPerTransaction & 0xFF ) ); return success; } bool ConfigureSyncChannel( const char *device, uint32_t syncBlockWidth, uint32_t amounOfSyncFrames ) { char tempBuffer[128]; bool success; snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_packets_per_xact", device ); /// Setting the amount of frames in one USB frame success = WriteIntegerToFile( tempBuffer, amounOfSyncFrames ); snprintf( tempBuffer, sizeof( tempBuffer ), "%s/set_subbuffer_size", device ); /// Setting the blockwidth of a single frame success = WriteIntegerToFile( tempBuffer, syncBlockWidth ); return success; } bool LinkToCharacterDevice( const char *linkName, const char *deviceName ) { bool success = WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/cdev/add_link", linkName ); if( success ) { success = WaitForDevice( deviceName ); } if( success ) { chmod( deviceName, ( S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ) ); } return success; } bool LinkToAudioDevice( const char *linkName, uint16_t subBufferSize ) { char tempBuffer[128]; uint8_t amountOfChannels; uint8_t bitDepth; if( !GetAlsaConfiguration( subBufferSize, &amountOfChannels, &bitDepth ) ) return false; snprintf( tempBuffer, sizeof( tempBuffer ), "%s.%dx%d", linkName, amountOfChannels, bitDepth ); /// Add the channel information behind the Link Name //Be compatible to all versions of MOST Linux Driver. The name was changed of Sound AIM. bool success = WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/sound/add_link", tempBuffer ); if( !success ) success = WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/audio/add_link", tempBuffer ); return success; } bool LinkToVideoForLinuxDevice( const char *linkName ) { bool success = WriteCharactersToFile( "/sys/devices/virtual/most/mostcore/aims/v4l/add_link", linkName ); return success; } const char *GetErrnoString() { switch( errno ) { case 0: return "Nothing stored in errno"; case 1: return "Operation not permitted"; case 2: return "No such file or directory"; case 3: return "No such process"; case 4: return "Interrupted system call"; case 5: return "I/O error"; case 6: return "No such device or address"; case 7: return "Argument list too long"; case 8: return "Exec format error"; case 9: return "Bad file number"; case 10: return "No child processes"; case 11: return "Try again"; case 12: return "Out of memory"; case 13: return "Permission denied"; case 14: return "Bad address"; case 15: return "Block device required"; case 16: return "Device or resource busy"; case 17: return "File exists"; case 18: return "Cross-device link"; case 19: return "No such device"; case 20: return "Not a directory"; case 21: return "Is a directory"; case 22: return "Invalid argument"; case 23: return "File table overflow"; case 24: return "Too many open files"; case 25: return "Not a typewriter"; case 26: return "Text file busy"; case 27: return "File too large"; case 28: return "No space left on device"; case 29: return "Illegal seek"; case 30: return "Read-only file system"; case 31: return "Too many links"; case 32: return "Broken pipe"; case 33: return "Math argument out of domain of func"; case 34: return "Math result not representable"; default: break; } return "Unknown"; }