/*
* 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 3 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";
}