nxdrvlinux/plugins/netx-spm/libsdpm.c
Sebastian Doell ac2f4d1789 Add initial driver source based on svn versions:
- toolkit V2.8.0.1@14806
 - BSL V1.8.0.0@14590
 - tcpserver: V1.4.3.0@14676 (marshaller V2.4.0.1@14551)
2024-02-05 09:23:09 +01:00

663 lines
26 KiB
C

/**************************************************************************************
*
* Copyright (c) 2024, Hilscher Gesellschaft fuer Systemautomation mbH. All Rights Reserved.
*
* Description: This plugin library can be used to initialize and use a spidev as a "common"
* cifX device. The access is based on the cifX toolkit's 'HW-access' functions.
*
* Changes:
*
* Version Date Author Description
* ----------------------------------------------------------------------------------
* 1 02.01.24 SD changed licensing terms
*
**************************************************************************************/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include <errno.h>
#include <pthread.h>
#include "cifxlinux.h"
/******************************************************************************/
/*** GLOBAL DEFINITIONS *******************************************************/
/******************************************************************************/
#if defined(VERBOSE) || defined(DEBUG)
#define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define DBG(fmt, ...)
#endif
#define CHECK_STATE /* enable error message in case of dpm status changes to != 0x11 (printed to stderr) */
/******************************************************************************/
/*** STRUCTURE DEFINITIONS ****************************************************/
/******************************************************************************/
/* states of the SPI interface */
typedef enum ESPI_IF_STATE_E {
eNotInitialized,
eInitialized,
} ESPI_IF_STATE;
/* Example structure containing information of the SPI interface (passed as user parameter -> see tSPIDev.userparam) */
struct SPI_PARAM_T {
char szName[256]; /* Name of the SPI interface (e.g. /dev/spidev1.0) */
int iSPIFD; /* File desc of the SPI interface */
void* pvSerDPMLock; /* lock required to synchronize SPI access */
int iError; /* Error status of SPI interface */
ESPI_IF_STATE eState; /* Current interface status */
/* The following parameter are related to the linux kernel 'spidev' interface */
uint32_t ulUDelay; /* SPI param: If nonzero, how long to delay after the last bit transfer */
/* before optionally deselecting the device before the next transfer */
uint32_t ulSpeed; /* SPI param: see SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ */
uint8_t bBits; /* SPI param: see SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD */
uint8_t bMode; /* SPI param: see SPI_IOC_RD_MODE, SPI_IOC_WR_MODE */
uint8_t* pabTXBuffer;
uint8_t* pabRXBuffer;
uint32_t ulChunkSize;
uint8_t bCSChange;
};
/* Internal structures required for read/write transactions */
/* SPI Read Transfer Structure */
struct SPI_RD_MSG_T {
uint8_t abSPIHeader[4];
uint8_t abData[1];
};
/* SPI Write Transfer Structure */
struct SPI_WR_MSG_T {
uint8_t abSPIHeader[3];
uint8_t abData[1];
};
/******************************************************************************/
/*** Global variables *********************************************************/
/******************************************************************************/
#define DEFAULT_BUFFER_SIZE (8*1024)
/*****************************************************************************/
/*! Create a lock
* \return Lock Handle */
/*****************************************************************************/
static void* CreateLock(void) {
pthread_mutexattr_t mta;
pthread_mutex_t *mutex;
int iRet;
pthread_mutexattr_init(&mta);
if( (iRet = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE)) != 0 )
return NULL;
mutex = malloc( sizeof(pthread_mutex_t) );
if( mutex == NULL )
return NULL;
if( (iRet = pthread_mutex_init(mutex, &mta)) != 0 )
goto err_out;
return mutex;
err_out:
free(mutex);
return NULL;
}
/*****************************************************************************/
/*! Acquire a lock
* \param pvLock Handle to lock */
/*****************************************************************************/
static void EnterLock(void* pvLock) {
pthread_mutex_t *mutex = (pthread_mutex_t *) pvLock;
int iRet;
if( (iRet = pthread_mutex_lock(mutex)) != 0)
{
fprintf( stderr, "Locking failed: %s\n", strerror(iRet));
}
}
/*****************************************************************************/
/*! Release a lock
* \param pvLock Handle to lock */
/*****************************************************************************/
static void LeaveLock(void* pvLock) {
pthread_mutex_t *mutex = (pthread_mutex_t *) pvLock;
int iRet;
if( (iRet = pthread_mutex_unlock(mutex)) != 0)
{
fprintf( stderr, "Unlock failed: %s\n", strerror(iRet));
}
}
/*****************************************************************************/
/*! Delete a lock
* \param pvLock Handle to lock */
/*****************************************************************************/
static void DeleteLock(void* pvLock) {
pthread_mutex_t *mutex = (pthread_mutex_t *) pvLock;
pthread_mutex_destroy(mutex);
free(mutex);
}
/******************************************************************************/
/*! Helper function, transfers SPI message.
* \param ptSPIParam Pointer to interface specific parameter
* \param pbData Pointer to SPI message
* \param pbData length of SPI message
* \param fCSChange */
/******************************************************************************/
static int SPITransferMessage(struct SPI_PARAM_T* ptSPIParam, uint8_t *pbData, uint32_t ulLen, uint8_t fCSChange)
{
int ret = 0;
struct spi_ioc_transfer tSPITransfer = {0};
DBG("++SPITransferMessage\n");
tSPITransfer.tx_buf = (uint64_t)pbData;
tSPITransfer.rx_buf = (uint64_t)pbData;
tSPITransfer.len = ulLen;
tSPITransfer.cs_change = fCSChange;
if(0 > (ret = ioctl( ptSPIParam->iSPIFD, SPI_IOC_MESSAGE(1), &tSPITransfer)))
fprintf(stderr, "SPITransferMessage: Failed to transfer message on SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
#ifdef CHECK_STATE
if (0x11 != pbData[0]) {
ret = -EAGAIN;
fprintf(stderr, "DPM status changed 0x%X (OK => 0x11)!\n", pbData[0]);
}
#endif
DBG("--SPITransferMessage\n");
return ret;
}
/******************************************************************************/
/*! Helper function, reading data via SPI interface.
* Translate read request into SPI read message.
* \param ptSPIParam Pointer to interface specific parameter
* \param ulDpmAddr Address offset in DPM to read data from
* \param pbData Pointer to Buffer to store read data
* \param ulLen Number of bytes to read */
/******************************************************************************/
static void SPIReadChunk( struct SPI_PARAM_T* ptSPIParam, uint32_t ulDpmAddr, uint8_t *pbData, uint32_t ulLen)
{
struct SPI_RD_MSG_T* ptSPIRDMsg = NULL;
int ret = 0;
DBG("++SPIReadChunk\n");
/* Check buffer size */
if(*(uint16_t*)ptSPIParam->pabRXBuffer < ulLen) {
fprintf(stderr, "SPIReadChunk: RX SPI buffer is too small\n");
return;
}
ptSPIRDMsg = (struct SPI_RD_MSG_T*)(ptSPIParam->pabRXBuffer+sizeof(uint16_t));
/* prepare SPI message */
ptSPIRDMsg->abSPIHeader[0] = 0x80 + (uint8_t)((ulDpmAddr >> 16) & 0x0F);
ptSPIRDMsg->abSPIHeader[1] = (uint8_t)((ulDpmAddr >> 8) & 0xFF);
ptSPIRDMsg->abSPIHeader[2] = (uint8_t)((ulDpmAddr) & 0xFF);
ptSPIRDMsg->abSPIHeader[3] = 0x00;
/* transfer message */
ret = SPITransferMessage(ptSPIParam, (uint8_t*)ptSPIRDMsg, ulLen+4, ptSPIParam->bCSChange);
#ifdef CHECK_STATE
if (0>ret) {
fprintf(stderr, "Error SPIReadChunk: DPM Addr=0x%X / Len=0x%X\n", ulDpmAddr, ulLen) ;
}
#endif
/* return read data */
memcpy(pbData, ptSPIRDMsg->abData, ulLen);
DBG("--SPIReadChunk\n");
}
/******************************************************************************/
/*! Helper function, writing data via SPI interface
* Translate write request into SPI write message
* \param ptSPIParam Pointer to interface specific parameter
* \param ulDpmAddr Offset in DPM where data to write to
* \param pbData Pointer to Buffer pointing to write data
* \param ulLen Number of bytes to write */
/******************************************************************************/
static void SPIWriteChunk(struct SPI_PARAM_T* ptSPIParam, uint32_t ulDpmAddr, uint8_t *pbData, uint32_t ulLen)
{
struct SPI_WR_MSG_T* ptSPIWRMsg = NULL;
int ret = 0;
DBG("++SPIWriteChunk\n");
/* Check buffer size */
if(*(uint16_t*)ptSPIParam->pabTXBuffer < ulLen) {
fprintf(stderr, "SPIWriteChunk: TX SPI buffer is too small\n");
return;
}
ptSPIWRMsg = (struct SPI_WR_MSG_T*)(ptSPIParam->pabTXBuffer+sizeof(uint16_t));
/* prepare SPI message */
ptSPIWRMsg->abSPIHeader[0] = (uint8_t)((ulDpmAddr >> 16) & 0x0F);
ptSPIWRMsg->abSPIHeader[1] = (uint8_t)((ulDpmAddr >> 8) & 0xFF);
ptSPIWRMsg->abSPIHeader[2] = (uint8_t)((ulDpmAddr) & 0xFF);
memcpy(ptSPIWRMsg->abData, pbData, ulLen);
/* transfer message */
ret = SPITransferMessage(ptSPIParam, (uint8_t*)ptSPIWRMsg, ulLen+3, ptSPIParam->bCSChange);
#ifdef CHECK_STATE
if (0>ret) {
fprintf(stderr, "Error SPIWriteChunk: DPM Addr=0x%X / Len=0x%X\n", ulDpmAddr, ulLen) ;
}
#endif
DBG("--SPIWriteChunk\n");
}
/******************************************************************************/
/*! Read a number of bytes via the custom hardware interface function
* \param ptDevice Pointer to the custom device
* \param pvDpmAddr Address offset in DPM to read data from
* \param pvDst Buffer to store read data
* \param ulLen Number of bytes to read */
/******************************************************************************/
static void* SPIHWIFRead(struct CIFX_DEVICE_T* ptDevice, void* pvDpmAddr, void* pvDst, uint32_t ulLen)
{
struct SPI_PARAM_T* ptSPIParam = (struct SPI_PARAM_T*)ptDevice->userparam;
DBG("++SPIHWIFRead\n");
/* check if interface is correctly configured */
if ((NULL != ptSPIParam) && (ptSPIParam->eState == eInitialized)) {
/* enter SPI access lock */
EnterLock(ptSPIParam->pvSerDPMLock);
/* read data from DPM */
SPIReadChunk(ptSPIParam, (uint32_t)(uintptr_t)pvDpmAddr, (uint8_t*)pvDst, ulLen);
LeaveLock(ptSPIParam->pvSerDPMLock);
}
DBG("--SPIHWIFRead\n");
return pvDst;
}
static void* SPIHWIFRead_ext(struct CIFX_DEVICE_T* ptDevice, void* pvDpmAddr, void* pvDst, uint32_t ulLen)
{
struct SPI_PARAM_T* ptSPIParam = (struct SPI_PARAM_T*)ptDevice->userparam;
int reads = ulLen/ptSPIParam->ulChunkSize;
void* ret = NULL;
while(reads>0) {
ret = SPIHWIFRead(ptDevice,pvDpmAddr,pvDst,ptSPIParam->ulChunkSize);
pvDpmAddr = (void*)((uintptr_t)pvDpmAddr + ptSPIParam->ulChunkSize);
pvDst = (void*)((uintptr_t)pvDst + ptSPIParam->ulChunkSize);
reads--;
}
if (ulLen%ptSPIParam->ulChunkSize)
ret = SPIHWIFRead(ptDevice,pvDpmAddr,pvDst,ulLen%ptSPIParam->ulChunkSize);
return ret;
}
/******************************************************************************/
/*! Read a number of bytes via the custom hardware interface function
* \param ptDevice Pointer to the custom device
* \param pvDpmAddr Address offset in DPM to write data to
* \param pvSrc Buffer to data to be written
* \param ulLen Number of bytes to writ */
/******************************************************************************/
static void* SPIHWIFWrite(struct CIFX_DEVICE_T* ptDevice, void* pvDpmAddr, void* pvSrc, uint32_t ulLen)
{
struct SPI_PARAM_T* ptSPIParam = (struct SPI_PARAM_T*)ptDevice->userparam;
DBG("++SPIHWIFWrite\n");
/* check if interface is correctly configured */
if ((NULL != ptSPIParam) && (ptSPIParam->eState == eInitialized)) {
/* enter SPI access lock */
EnterLock(ptSPIParam->pvSerDPMLock);
/* write data to DPM */
SPIWriteChunk(ptSPIParam, (uint32_t)(uintptr_t)pvDpmAddr, (uint8_t*)pvSrc, ulLen);
LeaveLock(ptSPIParam->pvSerDPMLock);
}
DBG("--SPIHWIFWrite\n");
return pvDpmAddr;
}
/* */
static void* SPIHWIFWrite_ext(struct CIFX_DEVICE_T* ptDevice, void* pvDpmAddr, void* pvSrc, uint32_t ulLen)
{
struct SPI_PARAM_T* ptSPIParam = (struct SPI_PARAM_T*)ptDevice->userparam;
int writes = ulLen/ptSPIParam->ulChunkSize;
void* ret = NULL;
while(writes>0) {
ret = SPIHWIFWrite(ptDevice,pvDpmAddr,pvSrc,ptSPIParam->ulChunkSize);
pvDpmAddr = (void*)((uintptr_t)pvDpmAddr + ptSPIParam->ulChunkSize);
pvSrc = (void*)((uintptr_t)pvSrc + ptSPIParam->ulChunkSize);
writes--;
}
if (ulLen%ptSPIParam->ulChunkSize)
ret = SPIHWIFWrite(ptDevice,pvDpmAddr,pvSrc,ulLen%ptSPIParam->ulChunkSize);
return ret;
}
/******************************************************************************/
/*! De-initializes SPI interface of device pointed by ptDevice.
* \param ptDevice Pointer to the custom device */
/******************************************************************************/
static void SPIHWIFDeInit(struct CIFX_DEVICE_T* ptDevice)
{
struct SPI_PARAM_T* ptSPIParam = (struct SPI_PARAM_T*)ptDevice->userparam;
DBG("++SPIHWIFDeInit\n");
if(ptSPIParam->pvSerDPMLock) {
DeleteLock(ptSPIParam->pvSerDPMLock);
ptSPIParam->pvSerDPMLock = NULL;
}
close(ptSPIParam->iSPIFD);
ptSPIParam->eState = eNotInitialized;
DBG("--SPIHWIFDeInit\n");
}
int32_t DoDummyRead( struct SPI_PARAM_T* ptSPIParam)
{
struct spi_ioc_transfer tSPITransfer = {0};
uint8_t abData[8] = {0};
uint8_t bRetry = 0;
int32_t lRet = 0;
/* Do dummy read (required on netX51) */
tSPITransfer.tx_buf = (unsigned long)abData;
tSPITransfer.rx_buf = (unsigned long)abData;
tSPITransfer.len = sizeof(abData);
tSPITransfer.cs_change = ptSPIParam->bCSChange;
do {
memset(abData, 0, sizeof(abData));
abData[0] = 0x80; /* set read request, cmd, A19:16 */
abData[1] = 0xff; /* A15:8 */
abData[2] = 0xfc; /* A7:0 */
abData[3] = 0; /* length */
/* issue dummy transfer */
if(0 > (lRet = ioctl(ptSPIParam->iSPIFD, SPI_IOC_MESSAGE(1), &tSPITransfer))) {
fprintf( stderr, "SPIHWIFInit: Failed to send message on SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
ptSPIParam->iError = errno;
} else {
if(bRetry == 0) {
/* skip first result since this is not valid on netX51 */
DBG("SPI dummy read: Header(0x%02x 0x%02x 0x%02x 0x%02x) Data(0x%02x%02x%02x%02x)\n"
, abData[0], abData[1], abData[2], abData[3], abData[4], abData[5],abData[6], abData[7]);
}
else if(bRetry == 1) {
DBG("SPI read access: Header(0x%02x 0x%02x 0x%02x 0x%02x) Data(0x%02x%02x%02x%02x)\n"
, abData[0], abData[1], abData[2], abData[3], abData[4], abData[5],abData[6], abData[7]);
/* check if DPM is in the correct status (serial DPM enabled and unlocked) */
if(abData[0] != 0x11) {
lRet = CIFX_FUNCTION_FAILED;
fprintf( stderr, "SPIHWIFInit: Failed to read from serial DPM. Incorrect DPM status of SPI device '%s' (0x%X).\n", ptSPIParam->szName, abData[0]);
fprintf( stderr, "SPIHWIFInit: Check the SPI connection and the serial DPM configuration of the device connected on '%s'.\n", ptSPIParam->szName);
} else {
ptSPIParam->ulUDelay = 0;
ptSPIParam->eState = eInitialized;
}
break;
}
bRetry++;
}
} while(0 <= lRet);
return lRet;
}
/******************************************************************************/
/*! Initializes SPI interface of device pointed by ptDevice.
* \param ptDevice Pointer to the custom device */
/******************************************************************************/
static int32_t SPIHWIFInit(struct CIFX_DEVICE_T* ptDevice)
{
int32_t lRet = 0;
struct SPI_PARAM_T* ptSPIParam = (struct SPI_PARAM_T*)ptDevice->userparam;
DBG("++SPIHWIFInit\n");
if (NULL == ptSPIParam) {
fprintf(stderr, "SPIHWIFInit: Invalid initialization parameter for SPI device '%s'\n", ptSPIParam->szName);
DBG("--SPIHWIFInit\n");
return CIFX_INVALID_PARAMETER;
}
DBG("SPIHWIFInit: SPI Setup: %s, mode %d, %d bits/w, %d Hz\n",ptSPIParam->szName, ptSPIParam->bMode, ptSPIParam->bBits, ptSPIParam->ulSpeed);
if (0 > (ptSPIParam->iSPIFD = open(ptSPIParam->szName, O_RDWR))) {
ptSPIParam->iError = errno;
fprintf( stderr, "SPIHWIFInit: Failed to open SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
DBG("--SPIHWIFInit\n");
return CIFX_FILE_OPEN_FAILED;
} else if (0 > (lRet = ioctl(ptSPIParam->iSPIFD, SPI_IOC_WR_MODE, &ptSPIParam->bMode))) {
ptSPIParam->iError = errno;
fprintf( stderr, "SPIHWIFInit: Failed to set 'SPI_IOC_WR_MODE' on SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
} else if (0 > (lRet = ioctl(ptSPIParam->iSPIFD, SPI_IOC_RD_MODE, &ptSPIParam->bMode))) {
ptSPIParam->iError = errno;
fprintf( stderr, "SPIHWIFInit: Failed to set 'SPI_IOC_RD_MODE' on SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
} else if (0 > (lRet = ioctl(ptSPIParam->iSPIFD, SPI_IOC_WR_BITS_PER_WORD, &ptSPIParam->bBits))) {
ptSPIParam->iError = errno;
fprintf( stderr, "SPIHWIFInit: Failed to set 'SPI_IOC_WR_BITS_PER_WORD' on SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
} else if (0 > (lRet = ioctl(ptSPIParam->iSPIFD, SPI_IOC_RD_BITS_PER_WORD, &ptSPIParam->bBits))) {
ptSPIParam->iError = errno;
fprintf( stderr, "SPIHWIFInit: Failed to set 'SPI_IOC_RD_BITS_PER_WORD' on SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
} else if (0 > (lRet = ioctl(ptSPIParam->iSPIFD, SPI_IOC_WR_MAX_SPEED_HZ, &ptSPIParam->ulSpeed))) {
ptSPIParam->iError = errno;
fprintf( stderr, "SPIHWIFInit: Failed to set 'SPI_IOC_WR_MAX_SPEED_HZ' on SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
} else if (0 > (lRet = ioctl(ptSPIParam->iSPIFD, SPI_IOC_RD_MAX_SPEED_HZ, &ptSPIParam->ulSpeed))) {
ptSPIParam->iError = errno;
fprintf( stderr, "SPIHWIFInit: Failed to set 'SPI_IOC_RD_MAX_SPEED_HZ' on SPI device '%s' - '%s'.\n", ptSPIParam->szName, strerror(errno));
} else {/* successfuly initialized SPI interface */
/* create SPI access lock */
if (NULL != (ptSPIParam->pvSerDPMLock = (void*)CreateLock())) {
/* Do dummy read (required on netX51) */
lRet = DoDummyRead(ptSPIParam);
}
}
if(0 > lRet)
SPIHWIFDeInit(ptDevice);
DBG("--SPIHWIFInit\n");
if(0 > lRet) {
return CIFX_FUNCTION_FAILED;
}
else {
ptSPIParam->iError = 0;
return CIFX_NO_ERROR;
}
}
void StatusCB(struct CIFX_DEVICE_T* ptDevice, CIFX_NOTIFY_E eEvent)
{
struct SPI_PARAM_T* ptSPIParam = ptDevice->userparam;
if (eCIFX_EVENT_POSTRESET == eEvent) {
/* we have to do a dummy read since netX device was reset */
DoDummyRead(ptSPIParam);
}
}
void SDPMDeInit(struct CIFX_DEVICE_T* ptDevice)
{
struct SPI_PARAM_T* ptSPIParam = ptDevice->userparam;
free(ptSPIParam->pabTXBuffer);
free(ptSPIParam->pabRXBuffer);
free(ptSPIParam);
free(ptDevice);
}
/******************************************************************************/
/*! Initializes a cifX device for SDPM (usage of SPI).
* \param pszSPIDevice Name of spidev device file (optional)
* \param bMode SPI mode
* \param bBits Bits per SPI word
* \param ulFrequency SPI frequency
* \param pszIRQFile Name of IRQ trigger file (optional)
* \return Pointer to initialized cifX device on success
* NULL on error */
/******************************************************************************/
struct CIFX_DEVICE_T* SDPMInit(uint8_t *pszSPIDevice, uint8_t bMode, uint8_t bBits, uint32_t ulFrequency, uint8_t *pszIRQFile, uint32_t ulChunkSize, uint8_t bCSChange)
{
struct CIFX_DEVICE_T* ptSPIDev = NULL;
struct SPI_PARAM_T* ptSPIParam = NULL;
uint8_t szSPIDevice[261];
int32_t lFd;
DBG("++SDPMInit\n");
DBG("Running SPI plugin on \"%s\" (mode=%d,bits=%d,freq=%u,chunk=%d,cs-change=%d)!\n", pszSPIDevice, bMode, bBits, ulFrequency, ulChunkSize, bCSChange);
/* Allocate memory for the cifX device */
ptSPIDev = calloc( 1, sizeof(*ptSPIDev));
if(ptSPIDev == NULL) {
fprintf(stderr, "SDPMInit: Allocate memory for the cifX device\n");
goto error_out;
}
/* Allocate zero initialized memory for the SPI device */
ptSPIParam = calloc(1, sizeof(*ptSPIParam));
if(ptSPIParam == NULL) {
fprintf(stderr, "SDPMInit: Allocate memory for SPI parameters\n");
goto error_out;
}
/* Check for a valid SPI device */
if(pszSPIDevice == NULL) {
struct dirent* entry;
DIR* dir = opendir("/sys/class/spidev");
if(NULL != dir) {
while((entry = readdir(dir)) != NULL) {
if((0 == strncmp(entry->d_name, "spidev", 6))) {
snprintf(szSPIDevice, sizeof(szSPIDevice), "/dev/%s", entry->d_name);
pszSPIDevice = szSPIDevice;
break;
}
}
}
}
lFd = open(pszSPIDevice, O_RDWR);
if (lFd < 0) {
fprintf(stderr, "SDPMInit: Invalid or missing SPI device(%s)\n", pszSPIDevice);
goto error_out;
}
close(lFd);
/* Check for a valid SPI mode */
if((bMode < SPI_MODE_0) || (SPI_MODE_3 < bMode)) {
fprintf(stderr, "SDPMInit: Invalid SPI mode (%d <= x <= %u)\n", SPI_MODE_0, SPI_MODE_3);
goto error_out;
}
/* Check for a valid IRQ file (optional) */
lFd = -1;
if(pszIRQFile != NULL) {
lFd = open(pszIRQFile, O_RDWR|O_NONBLOCK);
if(lFd < 0) {
fprintf(stderr, "SDPMInit: Invalid SPI IRQ file (%s). Fallback to polling!\n", pszIRQFile);
}
}
/* Configure the SPI device parameter */
strncpy(ptSPIParam->szName, pszSPIDevice, sizeof(ptSPIParam->szName));
ptSPIParam->ulUDelay = 0;
ptSPIParam->bMode = bMode;
ptSPIParam->bBits = bBits;
ptSPIParam->ulSpeed = ulFrequency;
ptSPIParam->ulChunkSize = ulChunkSize;
ptSPIParam->bCSChange = bCSChange;
/* Configuration of a SPI device */
ptSPIDev->dpm = NULL; /*!< set to 'NULL' since the SPI device is not memory mapped */
ptSPIDev->dpmaddr = 0x0; /*!< set to '0x00' since there is no direct address to the physical DPM */
ptSPIDev->dpmlen = 0x10000; /*!< set to length of dpm (depends on the device) */
/* Since device is not a uio device and no pci card invalidate all parameter */
ptSPIDev->uio_num = -1; /*!< set to '-1' since it is no 'uio-devices' */
ptSPIDev->uio_fd = (lFd >= 0) ? lFd : -1; /*!< set to '-1' since it is no 'uio-devices' */
ptSPIDev->pci_card = 0; /*!< set to 0 since it is no pci card */
ptSPIDev->force_ram = 0; /*!< Force usage of RAM instead of flash. Card will always be reset and all
files are downloaded again (0 => autodetect) */
/* In this example we are not interrested in any configuration state, so set parameter to NULL */
ptSPIDev->notify = StatusCB; /*!< Function to call, after the card has passed several stages (usually needed on RAM based
devices, that change DPM configuration during initialization) */
/* Append any custom parameter */
ptSPIDev->userparam = ptSPIParam; /*!< Use this parameter to pass SPI interface specific information */
/* There is no extra memory */
ptSPIDev->extmem = NULL; /*!< virtual pointer to extended memory */
ptSPIDev->extmemaddr = 0x00; /*!< physical address to extended memory */
ptSPIDev->extmemlen = 0; /*!< Length of extended memory in bytes */
/* NOTE: The following parameter are SPI specific */
/* Hardware access functions, required to read or write to the hardware */
ptSPIDev->hwif_init = SPIHWIFInit; /*!< Function initializes SPI hw-function interface (need to be implemented) */
ptSPIDev->hwif_deinit = SPIHWIFDeInit; /*!< Function de-initializes SPI hw-function interface (need to be implemented) */
if (0 != ptSPIParam->ulChunkSize) {
ptSPIDev->hwif_read = SPIHWIFRead_ext; /*!< Function realize DPM read access via SPI transfers (need to be implemented) */
ptSPIDev->hwif_write = SPIHWIFWrite_ext; /*!< Function realize DPM write access via SPI transfers (need to be implemented) */
} else {
ptSPIDev->hwif_read = SPIHWIFRead; /*!< Function realize DPM read access via SPI transfers (need to be implemented) */
ptSPIDev->hwif_write = SPIHWIFWrite; /*!< Function realize DPM write access via SPI transfers (need to be implemented) */
}
/* Allocate buffer for TX SPI-transfers */
ptSPIParam->pabTXBuffer = malloc(2+DEFAULT_BUFFER_SIZE+3); /* Length field (required by SPIWriteChunk) and SPI header are included */
if(ptSPIParam->pabTXBuffer == NULL) {
fprintf(stderr, "SDPMInit: Allocate memory for the TX buffer\n");
goto error_out;
}
*(uint16_t*)ptSPIParam->pabTXBuffer = DEFAULT_BUFFER_SIZE; /* store buffer length */
/* Allocate buffer for RX SPI-transfers */
ptSPIParam->pabRXBuffer = malloc(2+DEFAULT_BUFFER_SIZE+4); /* Length field (required by SPIReadChunk) and SPI header are included */
if(ptSPIParam->pabRXBuffer == NULL) {
fprintf(stderr, "SDPMInit: Allocate memory for the RX buffer\n");
goto error_out;
}
*(uint16_t*)ptSPIParam->pabRXBuffer = DEFAULT_BUFFER_SIZE; /* store buffer length */
DBG("--SDPMInit\n");
return ptSPIDev;
error_out:
if (ptSPIParam) {
free(ptSPIParam->pabTXBuffer);
free(ptSPIParam->pabRXBuffer);
}
free(ptSPIParam);
free(ptSPIDev);
close(lFd);
DBG("--SDPMInit\n");
return NULL;
}