소스 검색

Zwischensicherung

Rind 5 년 전
부모
커밋
5b8d46d6b3
13개의 변경된 파일2116개의 추가작업 그리고 635개의 파일을 삭제
  1. 1 1
      Makefile
  2. 106 0
      defines.h
  3. 485 102
      drvmain.c
  4. 1 0
      kfile.c
  5. 227 0
      kfirmware.c
  6. 31 0
      kfirmware.h
  7. 119 288
      kspi.c
  8. 13 15
      kspi.h
  9. 640 0
      ktiva.c
  10. 79 0
      ktiva.h
  11. 149 19
      sfsattrib.c
  12. 17 3
      sfsattrib.h
  13. 248 207
      test/main.c

+ 1 - 1
Makefile

@@ -2,7 +2,7 @@
 TARGET_MODULE:=gfaspi
 PWD := $(shell pwd)
 
-$(TARGET_MODULE)-objs := drvmain.o kfile.o kspi.o sfsattrib.o
+$(TARGET_MODULE)-objs := drvmain.o kfile.o sfsattrib.o kspi.o ktiva.o kfirmware.o
 obj-m := $(TARGET_MODULE).o
 
 

+ 106 - 0
defines.h

@@ -0,0 +1,106 @@
+// defines.h :
+//
+
+#if !defined(AGD_DEFINES_H__C7EAD575_99C7_4047_8E24_F5887CACEC73__INCLUDED_)
+#define AGD_DEFINES_H__C7EAD575_99C7_4047_8E24_F5887CACEC73__INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// defines.h - Declarations:
+
+
+#define _EXTENDED_ERROR_CHECK			1
+#define _SUPPORT_LEGACY_UPTIME			0
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define KFW_MAX_IMG_MATERIAL_NUM_LENGTH							16	// including the zero terminator
+#define KFW_MAX_IMG_SERIAL_NUM_LENGTH							16	// including the zero terminator
+#define KFW_MAX_IMG_NAME_BUILD_LENGTH							24	// including the zero terminator
+
+#define KFW_IMG_HEADER_PREFIX_0									((unsigned int)0xFF01FF02)
+#define KFW_IMG_HEADER_PREFIX_1									((unsigned int)0xFF03FF04)
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+typedef struct _TIVA_ADC
+{
+	int UVers;
+	int UBatV3;
+	int Temp;
+	int UV5Vsys;
+	int UV3V6Bat;
+	int TempTIVA;
+}TIVA_ADC, *LPTIVA_ADC;
+typedef const TIVA_ADC *LPCTIVA_ADC;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _KFW_IMG_HEADER
+{
+	const unsigned int	nPrefix0;
+	const unsigned int	nPrefix1;
+	const unsigned int	nImgLength;
+	const unsigned int	nImgCRC32;
+	const unsigned int	nReserved[4];
+	union
+	{
+		struct
+		{
+			const char * const	pszImgMaterialNum;
+			const char * const	pszImgNameBuild;
+		}app;
+		struct
+		{
+			const char szImgMaterialNum[KFW_MAX_IMG_MATERIAL_NUM_LENGTH];
+			const char szImgNameBuild[KFW_MAX_IMG_NAME_BUILD_LENGTH];
+		}bl;
+	};
+}KFW_IMG_HEADER, *LPKFW_IMG_HEADER;
+typedef const KFW_IMG_HEADER *LPCKFW_IMG_HEADER;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _TIVA_UPLOAD_INFO
+{
+	const void *pData;
+	size_t nCbData;
+	LPCKFW_IMG_HEADER  pkih;
+	const char *pszMat;
+	const char *pszBld;
+}TIVA_UPLOAD_INFO, *LPTIVA_UPLOAD_INFO;
+typedef const TIVA_UPLOAD_INFO *LPCTIVA_UPLOAD_INFO;
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+#define _countof(a)						(sizeof(a) / sizeof(*a))
+#define _JIFFY_DIFF(a, b)				((long)((unsigned long)(a) - (unsigned long)(b)))
+#define KALERT(...)						printk(KERN_ALERT __VA_ARGS__)
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+#define _SPI_SPEED_HZ					1000000
+#define _SPI_BITS_PER_WORD				8
+#define _SPI_DEVICE						"/dev/spidev1.0"
+#define _TIMER_INTERVAL					(jiffies + HZ) // 1 sec
+#define _FIRMWARE_PAGES_COUNT			6
+#define _FIRMWARE_BUFFER_SIZE			(64 * PAGE_SIZE) // = 2 ^ 6 * PAGE_SIZE
+
+#define KFW_DEFAULT_BASE_ADDRESS		0 // 0x2000
+#define KFW_DEFAULT_UPLOAD_BLOCKSIZE	8
+#define KFW_MIN_HAS_MATERIAL_NR_VERSION	0x0201
+
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_DEFINES_H__C7EAD575_99C7_4047_8E24_F5887CACEC73__INCLUDED_)

+ 485 - 102
drvmain.c

@@ -10,37 +10,97 @@
 #include <linux/workqueue.h>
 #include <asm/ioctls.h>
 #include <linux/spi/spidev.h>
+#include "defines.h"
 #include "kfile.h"
 #include "kspi.h"
+#include "ktiva.h"
 #include "sfsattrib.h"
-
-#define _TIMER_INTERVAL				(jiffies + 3 * HZ)
+#include "kfirmware.h"
 
 /////////////////////////////////////////////////////////////////////////////
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("GfA");
 
-/////////////////////////////////////////////////////////////////////////////
+#define _THREAD_DELAY_JIFFIES				5
+#define _IS_REVIVE_STATE(ret)				((ret) != -ECOMM)
 
-#define _SPI_DEVICE				"/dev/spidev1.0"
+/////////////////////////////////////////////////////////////////////////////
+// sys fs
 
-static void work_queue_func(struct work_struct *work);
 static struct kobject *g_pKoGfa = NULL, *g_pKoTiva = NULL;
+static bool g_bHasFwVersion = false;
 
 /////////////////////////////////////////////////////////////////////////////
-// timer
+// worker threads
+
+static void _SysFsWorkProc(struct work_struct *work);
+static void _FwUploadWorkProc(struct work_struct *work);
 
 static struct workqueue_struct *g_pwq = NULL;
-static DECLARE_WORK(g_wo, work_queue_func);
+static DECLARE_WORK(g_sysFsWorkObj, _SysFsWorkProc);
+static DECLARE_WORK(g_fwUploadWorkObj, _FwUploadWorkProc);
+
+/////////////////////////////////////////////////////////////////////////////
+// timer
 
 static volatile bool g_bTimerRunning = false;
 static struct timer_list g_jiq_timer;
 
+/////////////////////////////////////////////////////////////////////////////
+
+typedef enum _WorkerState
+{
+	WS_SysFs,
+	WS_FwUpload
+}WorkerState;
+
+static TIVA_UPLOAD_INFO g_tui;
+
+/////////////////////////////////////////////////////////////////////////////
+
 static void OnJigTimer(unsigned long ptr)
 {
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-	queue_work(g_pwq, &g_wo);
+	static unsigned int nPass = 0;
+	static WorkerState ws = WS_SysFs;
+
+//	KALERT("%s: %d, %p\n", __FUNCTION__, g_bTimerRunning ? 1 : 0, g_pwq);
+
+	if(g_bTimerRunning && g_pwq)
+	{
+		if(KfwQueryUploadInfo(&g_tui))
+			ws = WS_FwUpload;
+
+		switch(ws)
+		{
+		case WS_SysFs:
+			if(++nPass == 3)
+			{
+				if(!queue_work(g_pwq, &g_sysFsWorkObj))
+				{
+					KALERT("%s: queue_work failed\n", __FUNCTION__);
+				}
+
+				nPass = 0;
+			}
+			else
+			{
+				mutex_lock(&g_mutex);
+				mod_timer(&g_jiq_timer, _TIMER_INTERVAL);
+				mutex_unlock(&g_mutex);
+			}
+			break;
+		case WS_FwUpload:
+			if(!queue_work(g_pwq, &g_fwUploadWorkObj))
+			{
+				KALERT("%s: queue_work failed\n", __FUNCTION__);
+			}
+			ws = WS_SysFs;
+//			nPass = 2;
+			nPass = 1;
+			break;
+		}
+	}
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -49,119 +109,393 @@ static void OnJigTimer(unsigned long ptr)
 // https://stackoverflow.com/questions/16367623/using-the-linux-sysfs-notify-call
 //
 
-static void work_queue_func(struct work_struct *work)
+static void _FwUploadWorkProc(struct work_struct *work)
 {
-	TIVA_ADC tadc;
 	struct file *pfSpiDev = NULL;
-	uint8_t mode = SPI_MODE_3;
-	uint8_t bits = 8;
-	uint32_t speed = 1000000;
-	unsigned long start = jiffies;
-
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-//	CmdGetFirmwareVersion(pfSpiDev, &g_hw, &g_sw);
-//	sysfs_notify(g_pKoTiva, NULL, "firmware");
+	uint8_t mode	= 0;
+	uint8_t bits	= 0;
+	uint32_t speed	= 0;
 
 	if((pfSpiDev = kf_open(_SPI_DEVICE, O_RDWR, 0)))
 	{
-		if(kf_ioctl(pfSpiDev, SPI_IOC_WR_MODE, (unsigned long)&mode) < 0)
+		do
 		{
-			printk(KERN_ALERT "can't set spi mode\n");
-//			break;
-		}
+			unsigned char stat = 0xFF;
 
-		if(kf_ioctl(pfSpiDev, SPI_IOC_RD_MODE, (unsigned long)&mode) < 0)
-		{
-			printk(KERN_ALERT "can't get spi mode\n");
-//			break;
-		}
+			if(kspi_write_mode(pfSpiDev, SPI_MODE_3) < 0)
+			{
+				KALERT("%s: kspi_write_mode failed!\n", __FUNCTION__);
+				break;
+			}
 
-		/////////////////////////////////////////////////////////////////////
+			if(kspi_read_mode(pfSpiDev, &mode) < 0)
+			{
+				KALERT("%s: kspi_read_mode failed!\n", __FUNCTION__);
+				break;
+			}
 
-		if(kf_ioctl(pfSpiDev, SPI_IOC_WR_BITS_PER_WORD, (unsigned long)&bits) < 0)
-		{
-			printk(KERN_ALERT "can't set bits per word\n");
-//			break;
-		}
+			if(mode != SPI_MODE_3)
+			{
+				KALERT("%s: Invalid mode!\n", __FUNCTION__);
+				break;
+			}
 
-		if(kf_ioctl(pfSpiDev, SPI_IOC_RD_BITS_PER_WORD, (unsigned long)&bits) < 0)
-		{
-			printk(KERN_ALERT "can't get bits per word\n");
-//			break;
-		}
+			/////////////////////////////////////////////////////////////////
 
-		/////////////////////////////////////////////////////////////////////
+			if(kspi_write_bits_per_word(pfSpiDev, _SPI_BITS_PER_WORD) < 0)
+			{
+				KALERT("%s: kspi_write_bits_per_word failed!\n", __FUNCTION__);
+				break;
+			}
 
-		if(kf_ioctl(pfSpiDev, SPI_IOC_WR_MAX_SPEED_HZ, (unsigned long)&speed) < 0)
-		{
-			printk(KERN_ALERT "can't set max speed hz\n");
-//			break;
-		}
+			if(kspi_read_bits_per_word(pfSpiDev, &bits) < 0)
+			{
+				KALERT("%s: kspi_read_bits_per_word failed!\n", __FUNCTION__);
+				break;
+			}
 
-		if(kf_ioctl(pfSpiDev, SPI_IOC_RD_MAX_SPEED_HZ, (unsigned long)&speed) < 0)
-		{
-			printk(KERN_ALERT "can't get max speed hz\n");
-//			break;
+			if(bits != _SPI_BITS_PER_WORD)
+			{
+				KALERT("%s: Invalid bits per word!\n", __FUNCTION__);
+				break;
+			}
+
+			/////////////////////////////////////////////////////////////////
+
+			if(kspi_write_max_speed_hz(pfSpiDev, _SPI_SPEED_HZ) < 0)
+			{
+				KALERT("%s: kspi_write_max_speed_hz failed!\n", __FUNCTION__);
+				break;
+			}
+
+			if(kspi_read_max_speed_hz(pfSpiDev, &speed) < 0)
+			{
+				KALERT("%s: kspi_read_max_speed_hz failed!\n", __FUNCTION__);
+				break;
+			}
+
+			if(speed != _SPI_SPEED_HZ)
+			{
+				KALERT("%s: Invalid max. speed!\n", __FUNCTION__);
+				break;
+			}
+
+			/////////////////////////////////////////////////////////////////
+
+			if(g_sw >= KFW_MIN_HAS_MATERIAL_NR_VERSION)
+			{
+			}
+
+			if(TivaCmdStartBootloader(pfSpiDev) < 0)
+			{
+				KALERT("%s: TivaCmdStartBootloader failed!\n", __FUNCTION__);
+				break;
+			}
+
+			g_hw = -1;
+			g_sw = -1;
+			g_bHasFwVersion = false;
+			sysfs_notify(g_pKoTiva, NULL, "version");
+
+			KALERT("%s: Started bootloader!\n", __FUNCTION__);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(_THREAD_DELAY_JIFFIES);
+
+			if(TivaCmdGetBootloaderStatus(pfSpiDev, &stat) < 0)
+			{
+				KALERT("%s: TivaCmdGetStatus failed!\n", __FUNCTION__);
+				break;
+			}
+
+			KALERT("%s: Status: 0x%02hhX\n", __FUNCTION__, stat);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(_THREAD_DELAY_JIFFIES);
+
+			if(TivaCmdPing(pfSpiDev) < 0)
+			{
+				KALERT("%s: TivaCmdPing failed!\n", __FUNCTION__);
+				break;
+			}
+
+			KALERT("%s: Ping success!\n", __FUNCTION__);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(_THREAD_DELAY_JIFFIES);
+
+			if(TivaCmdGetBootloaderStatus(pfSpiDev, &stat) < 0)
+			{
+				KALERT("%s: TivaCmdGetStatus failed!\n", __FUNCTION__);
+				break;
+			}
+
+			KALERT("%s: Status: 0x%02hhX\n", __FUNCTION__, stat);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(_THREAD_DELAY_JIFFIES);
+
+			if(TivaCmdReset(pfSpiDev) < 0)
+			{
+				KALERT("%s: TivaCmdReset failed!\n", __FUNCTION__);
+				break;
+			}
+
+			KALERT("%s: Started firmware!\n", __FUNCTION__);
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(_THREAD_DELAY_JIFFIES);
+
+			if(TivaCmdGetStatus(pfSpiDev, &stat) < 0)
+			{
+				KALERT("%s: TivaCmdGetStatus failed!\n", __FUNCTION__);
+				break;
+			}
+
+			KALERT("%s: Status: 0x%02hhX\n", __FUNCTION__, stat);
+
+//			KALERT("%s: data: 0x%p, cb: %zu, mat: %s, bld: %s\n", __FUNCTION__, g_tui.pData, g_tui.nCbData, g_tui.pszMat, g_tui.pszBld);
 		}
+		while(0);
+
+		SfAttLockFirmware(false);
+		kf_close(pfSpiDev);
+	}
+	else
+	{
+		KALERT("%s: kf_open failed\n", __FUNCTION__);
+	}
+
+	if(g_bTimerRunning)
+	{
+		mutex_lock(&g_mutex);
+		mod_timer(&g_jiq_timer, _TIMER_INTERVAL);
+		mutex_unlock(&g_mutex);
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static void _SysFsWorkProc(struct work_struct *work)
+{
+	TIVA_ADC tadc;
+	unsigned char stat;
+	int hw, sw, ret;
+	unsigned long long nUpTime;
+	struct file *pfSpiDev = NULL;
+	uint8_t mode	= 0;
+	uint8_t bits	= 0;
+	uint32_t speed	= 0;
+//	unsigned long start = jiffies;
+
+//	KALERT("%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
 
-		if(CmdGetADC(pfSpiDev, &tadc) == 0)
+	if((pfSpiDev = kf_open(_SPI_DEVICE, O_RDWR, 0)))
+	{
+		do
 		{
-			if(g_tadc.UVers != tadc.UVers)
+			if(kspi_write_mode(pfSpiDev, SPI_MODE_3) < 0)
+			{
+				KALERT("%s: kspi_write_mode failed!\n", __FUNCTION__);
+				break;
+			}
+
+			if(kspi_read_mode(pfSpiDev, &mode) < 0)
+			{
+				KALERT("%s: kspi_read_mode failed!\n", __FUNCTION__);
+				break;
+			}
+
+			if(mode != SPI_MODE_3)
+			{
+				KALERT("%s: Invalid mode!\n", __FUNCTION__);
+				break;
+			}
+
+			/////////////////////////////////////////////////////////////////
+
+			if(kspi_write_bits_per_word(pfSpiDev, _SPI_BITS_PER_WORD) < 0)
+			{
+				KALERT("%s: kspi_write_bits_per_word failed!\n", __FUNCTION__);
+				break;
+			}
+
+			if(kspi_read_bits_per_word(pfSpiDev, &bits) < 0)
+			{
+				KALERT("%s: kspi_read_bits_per_word failed!\n", __FUNCTION__);
+				break;
+			}
+
+			if(bits != _SPI_BITS_PER_WORD)
 			{
-				g_tadc.UVers = tadc.UVers;
-				sysfs_notify(g_pKoTiva, NULL, "UVers");
-//				printk(KERN_ALERT "Update UVers.\n");
+				KALERT("%s: Invalid bits per word!\n", __FUNCTION__);
+				break;
 			}
-			
-			if(g_tadc.UBatV3 != tadc.UBatV3)
+
+			/////////////////////////////////////////////////////////////////
+
+			if(kspi_write_max_speed_hz(pfSpiDev, _SPI_SPEED_HZ) < 0)
 			{
-				g_tadc.UBatV3 = tadc.UBatV3;
-				sysfs_notify(g_pKoTiva, NULL, "UBatV3");
-//				printk(KERN_ALERT "Update UBatV3.\n");
+				KALERT("%s: kspi_write_max_speed_hz failed!\n", __FUNCTION__);
+				break;
 			}
-			
-			if(g_tadc.Temp != tadc.Temp)
+
+			if(kspi_read_max_speed_hz(pfSpiDev, &speed) < 0)
 			{
-				g_tadc.Temp = tadc.Temp;
-				sysfs_notify(g_pKoTiva, NULL, "Temp");
-//				printk(KERN_ALERT "Update Temp.\n");
+				KALERT("%s: kspi_read_max_speed_hz failed!\n", __FUNCTION__);
+				break;
 			}
-			
-			if(g_tadc.UV5Vsys != tadc.UV5Vsys)
+
+			if(speed != _SPI_SPEED_HZ)
 			{
-				g_tadc.UV5Vsys = tadc.UV5Vsys;
-				sysfs_notify(g_pKoTiva, NULL, "UV5Vsys");
-//				printk(KERN_ALERT "Update UV5Vsys.\n");
+				KALERT("%s: Invalid max. speed!\n", __FUNCTION__);
+				break;
 			}
-			
-			if(g_tadc.UV3V6Bat != tadc.UV3V6Bat)
+
+			/////////////////////////////////////////////////////////////////
+
+			if(	(ret = TivaCmdPing(pfSpiDev)) < 0 &&
+				_IS_REVIVE_STATE(ret))
 			{
-				g_tadc.UV3V6Bat = tadc.UV3V6Bat;
-				sysfs_notify(g_pKoTiva, NULL, "UV3V6Bat");
-//				printk(KERN_ALERT "Update UV3V6Bat.\n");
+				KALERT("%s: TivaCmdPing failed: %d - call TivaRevive\n", __FUNCTION__, ret);
+				TivaRevive(pfSpiDev);
 			}
-			
-			if(g_tadc.TempTIVA != tadc.TempTIVA)
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(_THREAD_DELAY_JIFFIES);
+
+			/////////////////////////////////////////////////////////////////
+
+			if(!g_bHasFwVersion)
 			{
-				g_tadc.TempTIVA = tadc.TempTIVA;
-				sysfs_notify(g_pKoTiva, NULL, "TempTIVA");
-//				printk(KERN_ALERT "Update TempTIVA.\n");
+				if((ret = TivaCmdGetFirmwareVersion(pfSpiDev, &hw, &sw)) == 0)
+				{
+					if((g_hw != hw) || (g_sw != sw))
+					{
+						g_hw = hw;
+						g_sw = sw;
+						sysfs_notify(g_pKoTiva, NULL, "version");
+					}
+
+					g_bHasFwVersion = true;
+				}
+				else if(_IS_REVIVE_STATE(ret))
+				{
+					KALERT("%s: TivaCmdGetFirmwareVersion failed: %d - call TivaRevive\n", __FUNCTION__, ret);
+					TivaRevive(pfSpiDev);
+					break;
+				}
+
+				set_current_state(TASK_INTERRUPTIBLE);
+				schedule_timeout(_THREAD_DELAY_JIFFIES);
 			}
+
+			/////////////////////////////////////////////////////////////////
+
+			if((ret = TivaCmdGetADC(pfSpiDev, &tadc)) == 0)
+			{
+				bool bModified = false;
+
+				if(g_tadc.UVers != tadc.UVers)
+				{
+					g_tadc.UVers = tadc.UVers;
+					bModified = true;
+					sysfs_notify(g_pKoTiva, NULL, "UVers");
+				}
+
+				if(g_tadc.UBatV3 != tadc.UBatV3)
+				{
+					g_tadc.UBatV3 = tadc.UBatV3;
+					bModified = true;
+					sysfs_notify(g_pKoTiva, NULL, "UBatV3");
+				}
+
+				if(g_tadc.Temp != tadc.Temp)
+				{
+					g_tadc.Temp = tadc.Temp;
+					bModified = true;
+					sysfs_notify(g_pKoTiva, NULL, "TempBoard");
+				}
+
+				if(g_tadc.UV5Vsys != tadc.UV5Vsys)
+				{
+					g_tadc.UV5Vsys = tadc.UV5Vsys;
+					bModified = true;
+					sysfs_notify(g_pKoTiva, NULL, "UV5Vsys");
+				}
+
+				if(g_tadc.UV3V6Bat != tadc.UV3V6Bat)
+				{
+					g_tadc.UV3V6Bat = tadc.UV3V6Bat;
+					bModified = true;
+					sysfs_notify(g_pKoTiva, NULL, "UV3V6Bat");
+				}
+
+				if(g_tadc.TempTIVA != tadc.TempTIVA)
+				{
+					g_tadc.TempTIVA = tadc.TempTIVA;
+					bModified = true;
+					sysfs_notify(g_pKoTiva, NULL, "TempTIVA");
+				}
+
+				if(bModified) // if any of the ADC values have changed, signal the binary file
+				{
+					sysfs_notify(g_pKoTiva, NULL, "AdcBin");
+				}
+			}
+			else if(_IS_REVIVE_STATE(ret))
+			{
+				KALERT("%s: TivaCmdGetADC failed: %d - call TivaRevive\n", __FUNCTION__, ret);
+				TivaRevive(pfSpiDev);
+			}
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(_THREAD_DELAY_JIFFIES);
+
+			/////////////////////////////////////////////////////////////////
+
+			if((ret = TivaCmdGetUptime(pfSpiDev, &nUpTime)) == 0)
+			{
+				if(g_nUpTime != nUpTime)
+				{
+					g_nUpTime = nUpTime;
+					sysfs_notify(g_pKoTiva, NULL, "Uptime");
+				}
+			}
+			else if(_IS_REVIVE_STATE(ret))
+			{
+				KALERT("%s: TivaCmdGetUptime failed: %d - call TivaRevive\n", __FUNCTION__, ret);
+				TivaRevive(pfSpiDev);
+			}
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(_THREAD_DELAY_JIFFIES);
+
+			/////////////////////////////////////////////////////////////////
+
+			if((ret = TivaCmdGetStatus(pfSpiDev, &stat)) == 0)
+			{
+			}
+			else if(_IS_REVIVE_STATE(ret))
+			{
+				KALERT("%s: TivaCmdGetStatus failed: %d - call TivaRevive\n", __FUNCTION__, ret);
+				TivaRevive(pfSpiDev);
+			}
+
+			/////////////////////////////////////////////////////////////////
+
+//			KALERT("Worker pass - jiffies: %ld - status: 0x%02hhX\n", _JIFFY_DIFF(jiffies, start), stat);
 		}
+		while(0);
 
 		kf_close(pfSpiDev);
 	}
 	else
 	{
-		printk(KERN_ALERT "file_open failed\n");
+		KALERT("%s: kf_open failed\n", __FUNCTION__);
 	}
 
 	if(g_bTimerRunning)
 	{
+		mutex_lock(&g_mutex);
 		mod_timer(&g_jiq_timer, _TIMER_INTERVAL);
+		mutex_unlock(&g_mutex);
 	}
-	
-	printk(KERN_ALERT "Worker pass jiffies: %lu\n", ((long)jiffies - (long)start));
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -174,65 +508,87 @@ static int drv_init(void)
 	{
 		if(!(g_pKoGfa = kobject_create_and_add("gfa", NULL)))
 		{
-			printk(KERN_ALERT "kobject_create_and_add failed\n");
+			KALERT("kobject_create_and_add failed\n");
 			break;
 		}
 
 		if(!(g_pKoTiva = kobject_create_and_add("tiva", g_pKoGfa)))
 		{
-			printk(KERN_ALERT "kobject_create_and_add failed\n");
+			KALERT("kobject_create_and_add failed\n");
 			break;
 		}
 
 		/////////////////////////////////////////////////////////////////////
 
-		if(sysfs_create_file(g_pKoTiva, &g_tivaFirmwareAtt.attr))
+		if(sysfs_create_file(g_pKoTiva, &g_tivaVersionAtt.attr))
 		{
-			printk(KERN_ALERT "sysfs_create_file failed\n");
+			KALERT("sysfs_create_file failed\n");
+			break;
+		}
+
+		if(sysfs_create_file(g_pKoTiva, &g_tivaUptimeAtt.attr))
+		{
+			KALERT("sysfs_create_file failed\n");
 			break;
 		}
 
 		if(sysfs_create_file(g_pKoTiva, &g_tivaUVersAtt.attr))
 		{
-			printk(KERN_ALERT "sysfs_create_file failed\n");
+			KALERT("sysfs_create_file failed\n");
 			break;
 		}
 
 		if(sysfs_create_file(g_pKoTiva, &g_tivaUBatV3Att.attr))
 		{
-			printk(KERN_ALERT "sysfs_create_file failed\n");
+			KALERT("sysfs_create_file failed\n");
 			break;
 		}
 
 		if(sysfs_create_file(g_pKoTiva, &g_tivaTempAtt.attr))
 		{
-			printk(KERN_ALERT "sysfs_create_file failed\n");
+			KALERT("sysfs_create_file failed\n");
 			break;
 		}
 
 		if(sysfs_create_file(g_pKoTiva, &g_tivaUV5VsysAtt.attr))
 		{
-			printk(KERN_ALERT "sysfs_create_file failed\n");
+			KALERT("sysfs_create_file failed\n");
 			break;
 		}
 
 		if(sysfs_create_file(g_pKoTiva, &g_tivaUV3V6BatAtt.attr))
 		{
-			printk(KERN_ALERT "sysfs_create_file failed\n");
+			KALERT("sysfs_create_file failed\n");
 			break;
 		}
 
 		if(sysfs_create_file(g_pKoTiva, &g_tivaTempTIVAAtt.attr))
 		{
-			printk(KERN_ALERT "sysfs_create_file failed\n");
+			KALERT("sysfs_create_file failed\n");
+			break;
+		}
+
+		if(sysfs_create_bin_file(g_pKoTiva, &g_tivaAdcBinAtt))
+		{
+			KALERT("sysfs_create_file failed\n");
 			break;
 		}
 
+		g_nCbFwData = 0;
+		if((g_pFwBuffer = (void*)__get_free_pages(GFP_KERNEL, _FIRMWARE_PAGES_COUNT)))
+		{
+			if(sysfs_create_bin_file(g_pKoTiva, &g_tivaFirmwareAtt))
+			{
+				KALERT("sysfs_create_file failed\n");
+				break;
+			}
+		}
+
 		/////////////////////////////////////////////////////////////////////
 
 		if(!(g_pwq = create_workqueue("GfaWrk")))
 		{
-			printk(KERN_ALERT "create_workqueue failed!\n");
+			KALERT("create_workqueue failed!\n");
 			break;
 		}
 
@@ -247,21 +603,21 @@ static int drv_init(void)
 
 		/////////////////////////////////////////////////////////////////////
 
-		if(!queue_work(g_pwq, &g_wo))
+		if(!queue_work(g_pwq, &g_sysFsWorkObj))
 		{
-			printk(KERN_ALERT "queue_work failed\n");
+			KALERT("%s: queue_work failed\n", __FUNCTION__);
 			break;
 		}
 
 		/////////////////////////////////////////////////////////////////////
 
-		printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
+		KALERT("%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
 		return 0;
 	}
 	while(0);
 
 	/////////////////////////////////////////////////////////////////////////
-	
+
 	if(g_bTimerRunning)
 	{
 		g_bTimerRunning = false;
@@ -269,17 +625,31 @@ static int drv_init(void)
 	}
 
 	if(g_pwq)
-		destroy_workqueue(g_pwq);                           
+	{
+		destroy_workqueue(g_pwq);
+		g_pwq = NULL;
+	}
+
+	if(g_pFwBuffer)
+	{
+		free_pages((unsigned long)g_pFwBuffer, _FIRMWARE_PAGES_COUNT);
+		g_pFwBuffer = NULL;
+		g_nCbFwData = 0;
+	}
 
 	if(g_pKoTiva)
 	{
-		sysfs_remove_file(g_pKoTiva, &g_tivaFirmwareAtt.attr);
+		sysfs_remove_file(g_pKoTiva, &g_tivaVersionAtt.attr);
+		sysfs_remove_file(g_pKoTiva, &g_tivaUptimeAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaUVersAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaUBatV3Att.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaTempAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaUV5VsysAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaUV3V6BatAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaTempTIVAAtt.attr);
+		sysfs_remove_bin_file(g_pKoTiva, &g_tivaAdcBinAtt);
+		sysfs_remove_bin_file(g_pKoTiva, &g_tivaFirmwareAtt);
+
 		kobject_put(g_pKoTiva);
 		g_pKoTiva = NULL;
 	}
@@ -301,24 +671,37 @@ static void drv_exit(void)
 	del_timer_sync(&g_jiq_timer);
 
 	if(g_pwq)
-		destroy_workqueue(g_pwq);                           
+	{
+		destroy_workqueue(g_pwq);
+		g_pwq = NULL;
+	}
+
+	if(g_pFwBuffer)
+	{
+		free_pages((unsigned long)g_pFwBuffer, _FIRMWARE_PAGES_COUNT);
+		g_pFwBuffer = NULL;
+		g_nCbFwData = 0;
+	}
 
 	if(g_pKoTiva)
 	{
-		sysfs_remove_file(g_pKoTiva, &g_tivaFirmwareAtt.attr);
+		sysfs_remove_file(g_pKoTiva, &g_tivaVersionAtt.attr);
+		sysfs_remove_file(g_pKoTiva, &g_tivaUptimeAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaUVersAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaUBatV3Att.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaTempAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaUV5VsysAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaUV3V6BatAtt.attr);
 		sysfs_remove_file(g_pKoTiva, &g_tivaTempTIVAAtt.attr);
+		sysfs_remove_bin_file(g_pKoTiva, &g_tivaFirmwareAtt);
+
 		kobject_put(g_pKoTiva);
 	}
 
 	if(g_pKoGfa)
 		kobject_put(g_pKoGfa);
 
-	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
+	KALERT("%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
 }
 
 /////////////////////////////////////////////////////////////////////////////

+ 1 - 0
kfile.c

@@ -1,5 +1,6 @@
 #include <linux/kernel.h>    // printk()
 #include <linux/syscalls.h>
+#include "defines.h"
 #include "kfile.h"
 
 /////////////////////////////////////////////////////////////////////////////

+ 227 - 0
kfirmware.c

@@ -0,0 +1,227 @@
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/errno.h>
+#include <linux/sysfs.h>
+#include <linux/syscalls.h>
+#include "defines.h"
+#include "kfirmware.h"
+#include "sfsattrib.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+static unsigned int g_pdw32CRC32Table[] =
+{
+	0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+	0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+	0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+	0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+	0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+	0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+	0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+	0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+	0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+	0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+	0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+	0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+	0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+	0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+	0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+	0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+	0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+	0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+	0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+	0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+	0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+	0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+	0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+	0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+	0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+	0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+	0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+	0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+	0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+	0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+	0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+	0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+static TIVA_UPLOAD_INFO g_tui;
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+static unsigned int _CalcCRC32(const void *pData, size_t nCbData, unsigned int dwCRC32)
+{
+    unsigned char ui8Char;
+    const unsigned char *pbData = (const unsigned char*)pData;
+
+    while(nCbData--)
+    {
+        ui8Char = *pbData++;
+        dwCRC32 = (dwCRC32 >> 8) ^ g_pdw32CRC32Table[(dwCRC32 & 0xFF) ^ ui8Char];
+    }
+
+    return dwCRC32;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static uint32_t _CalcImgCRC32(const void *pImg, LPCKFW_IMG_HEADER paih)
+{
+	const void *pSection1 = pImg;
+	const void *pSection2 = paih->nReserved;
+	size_t nCbSection1 = (void*)&paih->nImgCRC32 - pSection1;
+	size_t nCbSection2 = paih->nImgLength - nCbSection1 - 4;
+
+	uint32_t nCRC32 = 0xffffffff;
+	nCRC32 = _CalcCRC32(pSection1, nCbSection1, nCRC32);
+	nCRC32 = _CalcCRC32(pSection2, nCbSection2, nCRC32);
+	nCRC32 ^= 0xffffffff;
+	return nCRC32;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static bool _MatchWildcardStrings(const char *pszMatNumEEPROM, const char *pszMatNumImg, size_t nRequiredLength)
+{
+	size_t nLen = 0;
+	char cEEPROM, cImg;
+
+	while(*pszMatNumEEPROM)
+	{
+		cImg	= *pszMatNumImg++;
+		cEEPROM	= *pszMatNumEEPROM++;
+		if((cImg != cEEPROM) && (cImg != '*'))
+			return false;
+		++nLen;
+	}
+
+	return nLen == nRequiredLength;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool KfwMatchMaterialNum(const char *pszMatNumEEPROM, const char *pszMatNumImg)
+{
+	if(pszMatNumEEPROM && pszMatNumImg)
+		return _MatchWildcardStrings(pszMatNumEEPROM, pszMatNumImg, KFW_MAX_IMG_MATERIAL_NUM_LENGTH - 1);
+	return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+LPCKFW_IMG_HEADER KfwLookupImgHeader(const void *pData, size_t nCbData)
+{
+	int i;
+	const unsigned int *pImg = (const unsigned int*)pData;
+
+	if(nCbData > (257 * sizeof(unsigned int)))
+	{
+		for(i = 0; i < 257; ++i, nCbData -= sizeof(unsigned int))
+		{
+			LPKFW_IMG_HEADER paih = (LPKFW_IMG_HEADER)pImg++;
+
+			if(	(paih->nPrefix0 == KFW_IMG_HEADER_PREFIX_0) &&
+				(paih->nPrefix1 == KFW_IMG_HEADER_PREFIX_1))
+			{
+				if(nCbData >= sizeof(KFW_IMG_HEADER))
+					return paih;
+				break;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int KfwOnDataDropped(const void *pData, size_t nCbData, LPKFW_DROP_CTX pdc)
+{
+	mutex_lock(&g_mutex);
+	memset(&g_tui, 0, sizeof(g_tui));
+	mutex_unlock(&g_mutex);
+
+	if(nCbData > (257 * sizeof(unsigned int)))
+	{
+		unsigned int dwCRC32;
+		ssize_t nOffsetMat, nOffsetBld;
+
+		if(!pdc->pkih)
+		{
+			if(!(pdc->pkih = KfwLookupImgHeader(pData, nCbData)))
+			{
+				KALERT("%s: No Image header found!\n", __FUNCTION__);
+				return -EPERM;
+			}
+		}
+
+		if(nCbData == pdc->pkih->nImgLength)
+		{
+			dwCRC32 = _CalcImgCRC32(pData, pdc->pkih);
+//			KALERT("%s: DataLen: %zu, ImgLen: %zu\n", __FUNCTION__, nCbData, pdc->pkih->nImgLength);
+//			KALERT("%s: DataCRC: %08X, ImgCRC: %08X\n", __FUNCTION__, dwCRC32, pdc->pkih->nImgCRC32);
+			
+			if(pdc->pkih->nImgCRC32 != dwCRC32)
+			{
+				KALERT("%s: Invalid CRC32: %08X\n", __FUNCTION__, pdc->pkih->nImgCRC32);
+				return -EPERM;
+			}
+
+			nOffsetMat = (ssize_t)pdc->pkih->app.pszImgMaterialNum - KFW_DEFAULT_BASE_ADDRESS;
+			nOffsetBld = (ssize_t)pdc->pkih->app.pszImgNameBuild   - KFW_DEFAULT_BASE_ADDRESS;
+
+			if(	(nOffsetMat > 0) && (((size_t)nOffsetMat + KFW_MAX_IMG_MATERIAL_NUM_LENGTH) <= nCbData) &&
+				(nOffsetBld > 0) && (((size_t)nOffsetBld + KFW_MAX_IMG_NAME_BUILD_LENGTH) <= nCbData))
+			{
+				const char *pszMat = ((const char*)pData) + nOffsetMat;
+				const char *pszBld = ((const char*)pData) + nOffsetBld;
+
+//				KALERT("%s: Material-Nr.: %s\n", __FUNCTION__, pszMat);
+//				KALERT("%s: Build-Nr.:    %s\n", __FUNCTION__, pszBld);
+
+				SfAttLockFirmware(true);
+
+				mutex_lock(&g_mutex);
+				g_tui.pData		= pData;
+				g_tui.nCbData	= nCbData;
+				g_tui.pkih		= pdc->pkih;
+				g_tui.pszMat	= pszMat;
+				g_tui.pszBld	= pszBld;
+				mutex_unlock(&g_mutex);
+				
+				return 1;
+			}
+		}
+		else if(nCbData > pdc->pkih->nImgLength)
+		{
+			KALERT("%s: Invalid Imgae-length: %u\n", __FUNCTION__, pdc->pkih->nImgLength);
+			return -EILSEQ;
+		}
+	}
+
+	return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool KfwQueryUploadInfo(LPTIVA_UPLOAD_INFO ptui)
+{
+	if(ptui)
+	{
+		bool bRet;
+		mutex_lock(&g_mutex);
+		memcpy(ptui, &g_tui, sizeof(g_tui));
+		mutex_unlock(&g_mutex);
+		if((bRet = !!ptui->pData && !!ptui->pkih && !!ptui->nCbData))
+			memset(&g_tui, 0, sizeof(g_tui));
+		return bRet;
+	}
+
+	return false;
+}
+

+ 31 - 0
kfirmware.h

@@ -0,0 +1,31 @@
+// kfirmware.h :
+//
+
+#if !defined(AGD_KFIRMWARE_H__F2361150_E2FE_4C33_B34E_CF3B6A70399E__INCLUDED_)
+#define AGD_KFIRMWARE_H__F2361150_E2FE_4C33_B34E_CF3B6A70399E__INCLUDED_
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// kfirmware.h - Declarations:
+
+typedef struct _KFW_DROP_CTX
+{
+	LPCKFW_IMG_HEADER  pkih;
+}KFW_DROP_CTX, *LPKFW_DROP_CTX;
+typedef const KFW_DROP_CTX *LPCKFW_DROP_CTX;
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool KfwMatchMaterialNum(const char *pszMatNumEEPROM, const char *pszMatNumImg);
+LPCKFW_IMG_HEADER KfwLookupImgHeader(const void *pData, size_t nCbData);
+int KfwOnDataDropped(const void *pData, size_t nCbData, LPKFW_DROP_CTX pdc);
+bool KfwQueryUploadInfo(LPTIVA_UPLOAD_INFO ptui);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_KFIRMWARE_H__F2361150_E2FE_4C33_B34E_CF3B6A70399E__INCLUDED_)

+ 119 - 288
kspi.c

@@ -1,345 +1,176 @@
 #include<linux/string.h>
+#include "defines.h"
 #include "kspi.h"
 #include "kfile.h"
+#include "ktiva.h"
 
-//uint8_t mode = SPI_MODE_3;
-//uint8_t bits = 8;
-//uint32_t speed = 1000000;
-#define CMD_ACK			0xcc
-#define CMD_NAK			0x33
-
-#define CMD_GET_FIRMWARE_VERSION 0x51
-#define CMD_GET_I2C 0x56
-#define CMD_SET_I2C 0x57
-#define CMD_GET_ADDRESS 0x58
-#define CMD_SET_ADDRESS 0x59
-#define CMD_SET_BACKLIGHT 0x5B
-#define CMD_GET_UPTIME 0x5C
-#define CMD_GET_ADC 0x5A
-
-static unsigned char transfer_1(struct file *pf, unsigned char Tx)
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+int kspi_write_mode(struct file *pf, unsigned char mode)
 {
 	int ret;
-	uint8_t tx = Tx;
-	uint8_t rx;
-
-	struct spi_ioc_transfer tr =
-	{
-		.tx_buf = (unsigned long) &tx,
-		.rx_buf = (unsigned long) &rx,
-		.len = 1,
-		.delay_usecs = 0,
-		.speed_hz = 1000000,
-		.bits_per_word = 8,
-	};
-
-	ret = kf_ioctl(pf, SPI_IOC_MESSAGE(1), (unsigned long)&tr);
 
-	if(ret < 0)
+	if((ret = kf_ioctl(pf, SPI_IOC_WR_MODE, (unsigned long)&mode)) < 0)
 	{
-		printk(KERN_ALERT "transfer_1 failed: %d\n", ret);
-	    return 0;
+		KALERT("%s: kf_ioctl failed: %d\n", __FUNCTION__, ret);
 	}
 
-    return rx;
+	return ret;
 }
 
-static int WaitACK(struct file *pf)
-{
-    unsigned char rcv = 0;
-    int i = 0;
+/////////////////////////////////////////////////////////////////////////////
 
-    // warten auf ACK
+int kspi_read_mode(struct file *pf, unsigned char *mode)
+{
+	int ret;
 
-    while ((rcv != CMD_ACK) && (rcv != CMD_NAK) && i < 1000/*(time(NULL) < endwait)*/)
-    {
-        rcv = transfer_1(pf, 0);
-        ++i;
-    }
+	if((ret = kf_ioctl(pf, SPI_IOC_RD_MODE, (unsigned long)mode)) < 0)
+	{
+		KALERT("%s: kf_ioctl failed: %d\n", __FUNCTION__, ret);
+	}
 
-    return rcv;
+	return ret;
 }
 
-int SendCMD(struct file *pf, unsigned char Cmd, unsigned char DataLen, unsigned char *Data)
+/////////////////////////////////////////////////////////////////////////////
+
+int kspi_write_bits_per_word(struct file *pf, unsigned char bits)
 {
-	unsigned char Len = DataLen + 3;
-	unsigned char Chk = Cmd;
-	int i;
+	int ret;
+
+	if((ret = kf_ioctl(pf, SPI_IOC_WR_BITS_PER_WORD, (unsigned long)&bits)) < 0)
+	{
+		KALERT("%s: kf_ioctl failed: %d\n", __FUNCTION__, ret);
+	}
 
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
+	return ret;
+}
 
-	for (i = 0; i < DataLen; i++)
-	    Chk += *(Data + i);
+/////////////////////////////////////////////////////////////////////////////
 
-	transfer_1(pf, Len);
-	transfer_1(pf, Chk);
-	transfer_1(pf, Cmd);
+int kspi_read_bits_per_word(struct file *pf, unsigned char *bits)
+{
+	int ret;
 
-	for (i = 0; i < DataLen; i++) {
-	    transfer_1(pf, *(Data + i));
+	if((ret = kf_ioctl(pf, SPI_IOC_RD_BITS_PER_WORD, (unsigned long)bits)) < 0)
+	{
+		KALERT("%s: kf_ioctl failed: %d\n", __FUNCTION__, ret);
 	}
-	return WaitACK(pf);
+
+	return ret;
 }
 
-int ReadCmd(struct file *pf, int MaxLen, unsigned char *Data)
+/////////////////////////////////////////////////////////////////////////////
+
+int kspi_write_max_speed_hz(struct file *pf, unsigned int speed)
 {
-    unsigned char rcv = 0;
-    int i = 0;
-    int len;
-    unsigned char chksum = 0, chkval = 0;
-    int ret = 0;
-
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-
-    // warten auf längenbyte der Antwort
-    while((rcv == 0) && (i < 2000))
-    {
-        rcv = transfer_1(pf, 0);
-        ++i;
-    }
-
-    // daten einlesen
-    len = rcv;
-    for(i = 0; i < (len - 1); ++i)
-    {
-        rcv = transfer_1(pf, 0);
-        //printf("%2.2X-", rcv);
-
-        if(i == 0) //CHKSUM
-        {
-            chkval = 0;
-            chksum = rcv;
-        }
-        else
-        {
-            chkval += rcv;
-            if((i - 1) < MaxLen)
-                *(Data + i - 1) = rcv;
-        }
-    }
-
-    if(chksum != chkval)
-    {
-        ret = -1;
-    }
-    else
-    {
-        ret = len - 2;
-    }
+	int ret;
 
-    return ret;
+	if((ret = kf_ioctl(pf, SPI_IOC_WR_MAX_SPEED_HZ, (unsigned long)&speed)) < 0)
+	{
+		KALERT("%s: kf_ioctl failed: %d\n", __FUNCTION__, ret);
+	}
+
+	return ret;
 }
 
-int CmdGetFirmwareVersion(struct file *pf, int *Hw, int *Sw)
-{
-    int ret = -1;
-    int len = 0;
+/////////////////////////////////////////////////////////////////////////////
 
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
+int kspi_read_max_speed_hz(struct file *pf, unsigned int *speed)
+{
+	int ret;
 
-    ret = SendCMD(pf, CMD_GET_FIRMWARE_VERSION , 0, NULL);
-    if(ret == CMD_ACK)
-    {
-        unsigned char Data[255];
-        memset(Data, 0, sizeof(Data));
+	if((ret = kf_ioctl(pf, SPI_IOC_RD_MAX_SPEED_HZ, (unsigned long)speed)) < 0)
+	{
+		KALERT("%s: kf_ioctl failed: %d\n", __FUNCTION__, ret);
+	}
 
-        if((len = ReadCmd(pf, sizeof(Data), Data)) == 9)
-        {
-            int HW_Version, SW_Version;
+	return ret;
+}
 
-            HW_Version = (Data[1] << 24) + (Data[2] << 16) + (Data[3] << 8) + Data[4];
-            SW_Version = (Data[5] << 24) + (Data[6] << 16) + (Data[7] << 8) + Data[8];
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
 
-            if(Hw != NULL) *Hw = HW_Version;
-            if(Sw != NULL) *Sw = SW_Version;
-            ret = 0;
-        } else {
-            printk(KERN_ALERT "LEN = %d\n", len);
-        }
-    }
+int kspi_tx(struct file *pf, const void *pData, size_t nCbData)
+{
+	int ret;
 
-    transfer_1(pf, CMD_ACK); /* Testweise immer ACK */
+	struct spi_ioc_transfer tr =
+	{
+		.tx_buf			= (unsigned long)pData,
+		.rx_buf			= 0,
+		.len			= nCbData,
+		.delay_usecs	= 0,
+		.speed_hz		= _SPI_SPEED_HZ,
+		.bits_per_word	= _SPI_BITS_PER_WORD,
+	};
 
+	if((ret = kf_ioctl(pf, SPI_IOC_MESSAGE(1), (unsigned long)&tr)) < 0)
+		KALERT("%s failed: %d\n", __FUNCTION__, ret);
     return ret;
 }
 
-unsigned long long CmdGetUptime(struct file *pf)
-{
-    unsigned long long ret = 0;
-    int len = 0;
-
-    ret = SendCMD(pf, CMD_GET_UPTIME , 0, NULL);
-    if(ret == CMD_ACK)
-    {
-        unsigned char Data[255];
-        ret = 0; //ACK erhalten soweit gut
-        memset(Data, 0, sizeof(Data));
-
-        if((len = ReadCmd(pf, sizeof(Data), Data)) == 9)
-        {
-            ret = (unsigned long long)(Data[1]) << 56 |
-                  (unsigned long long)(Data[2]) << 48 |
-                  (unsigned long long)(Data[3]) << 40 |
-                  (unsigned long long)(Data[4]) << 32 |
-                  (unsigned long long)(Data[5]) << 24 |
-                  (unsigned long long)(Data[6]) << 16 |
-                  (unsigned long long)(Data[7]) << 8 |
-                  (unsigned long long)(Data[8]);
-        }
-
-        transfer_1(pf, CMD_ACK); /**< ACK */
-    }
-    return ret;
-}
+/////////////////////////////////////////////////////////////////////////////
 
-int CmdGetAddress(struct file *pf, unsigned int Addr, unsigned int *Value)
+int kspi_rx(struct file *pf, void *pData, size_t nCbData)
 {
-    int ret = -1;
-    int len = 0;
-    unsigned char ReadADDRESS[4];
-    unsigned char DestData[10];
-    int DestLen = sizeof(DestData);
-
-    ReadADDRESS[0] = (unsigned char)((Addr >> 24) & 0xff);
-    ReadADDRESS[1] = (unsigned char)((Addr >> 16) & 0xff);
-    ReadADDRESS[2] = (unsigned char)((Addr >> 8) & 0xff);
-    ReadADDRESS[3] = (unsigned char)(Addr & 0xff);
-
-    ret = SendCMD(pf, CMD_GET_ADDRESS , sizeof(ReadADDRESS), ReadADDRESS);
-    if(ret == CMD_ACK) {
-        unsigned char Data[255];
-
-        ret = 0; //ACK erhalten soweit gut
-        memset(Data, 0, sizeof(Data));
-        if((len = ReadCmd(pf, sizeof(Data), Data)) > 0) {
-            memcpy(DestData, Data + 1, ((len - 1) <= DestLen)?(len - 1):DestLen);
-            ret = len - 1;
-        }
-        transfer_1(pf, CMD_ACK); /**< ACK */
-    }
-
-    if(Value)
-        *Value = (unsigned int)(DestData[0]) << 24 |
-                 (unsigned int)(DestData[1]) << 16 |
-                 (unsigned int)(DestData[2]) << 8 |
-                 (unsigned int)(DestData[3]);
+	int ret;
+
+	struct spi_ioc_transfer tr =
+	{
+		.tx_buf			= 0,
+		.rx_buf			= (unsigned long)pData,
+		.len			= nCbData,
+		.delay_usecs	= 0,
+		.speed_hz		= _SPI_SPEED_HZ,
+		.bits_per_word	= _SPI_BITS_PER_WORD,
+	};
+
+	if((ret = kf_ioctl(pf, SPI_IOC_MESSAGE(1), (unsigned long)&tr)) < 0)
+		KALERT("%s failed: %d\n", __FUNCTION__, ret);
     return ret;
 }
 
-void getUPTIME(struct file *pf, unsigned int Addr, int nFwVersion)
-{
-    unsigned int dd;
-    int day, hour, min;
-
-    if(nFwVersion >= 0x113 )
-    {
-        unsigned long long Data;
-        Data = CmdGetUptime(pf);
-        day = Data / 86400000;
-        dd = Data - day * 86400000;
-        hour = dd / 3600000;
-        dd -= hour * 3600000;
-        min = dd / 60000;
-
-    }
-    else
-    {
-        unsigned int Data = 0xFFFFFFFF;
-
-        CmdGetAddress(pf, Addr, &Data);
-        day = Data / 86400000;
-        dd = Data - day * 86400000;
-        hour = dd / 3600000;
-        dd -= hour * 3600000;
-        min = dd / 60000;
-    }
-    
-    
-//    printf("%d d %2.2d:%2.2d\n", day, hour, min);
-}
+/////////////////////////////////////////////////////////////////////////////
 
-static const int g_kty_tab[][2] =
-{
-  {199, 1250},
-  {351, 1000},
-  {643, 750},
-  {1185, 500},
-  {2048, 250},
-  {3025,  0},
-  {3705, -250}
-};
-
-#define KTY_TAB_LEN				((sizeof g_kty_tab / sizeof g_kty_tab[0]) - 1)
-
-int lin_kty(int widerstand)
+int kspi_tx_rx(struct file *pf, const void *pTx, void *pRx, size_t nCb)
 {
-	int i;
-
-	if(widerstand <= g_kty_tab[0][0])
-		return(g_kty_tab[0][1]);
+	int ret;
 
-	if(widerstand >= g_kty_tab[KTY_TAB_LEN][0])
-		return(g_kty_tab[KTY_TAB_LEN][1]);
+	struct spi_ioc_transfer tr =
+	{
+		.tx_buf			= (unsigned long)pTx,
+		.rx_buf			= (unsigned long)pRx,
+		.len			= nCb,
+		.delay_usecs	= 0,
+		.speed_hz		= _SPI_SPEED_HZ,
+		.bits_per_word	= _SPI_BITS_PER_WORD,
+	};
 
-	/* Suchen des nächsten Tabelleneintrags */
+	if((ret = kf_ioctl(pf, SPI_IOC_MESSAGE(1), (unsigned long)&tr)) < 0)
+		KALERT("%s failed: %d\n", __FUNCTION__, ret);
+    return ret;
+}
 
-	for(i=1; i<=KTY_TAB_LEN; i++)
-	{
-		if(g_kty_tab[i][0] >= widerstand)
-		{
-			break;
-		}
-	}
+/////////////////////////////////////////////////////////////////////////////
 
-	/* Linear interpolieren */
-	return 	(long)g_kty_tab[i-1][1] +                            /* y1 */
-			(((long)g_kty_tab[i][1] - (long)g_kty_tab[i-1][1]) *   /* y2 - y1 */
-			((long)widerstand - (long)g_kty_tab[i-1][0]) /       /* x - x1 */
-			((long)g_kty_tab[i][0] - (long)g_kty_tab[i-1][0]));    /* x2 - x1 */
+int kspi_rx_byte(struct file *pf, unsigned char *rx)
+{
+	return kspi_rx(pf, rx, 1);
 }
 
-static int scale (int in_min, int in_max, int out_min, int out_max, int wert)
+/////////////////////////////////////////////////////////////////////////////
+
+int kspi_tx_byte(struct file *pf, unsigned char tx)
 {
-	int abc;
-	abc = (((long)out_max - (long)out_min) * (long)wert) / ( (long)in_max - (long)in_min);
-	abc = abc + out_min;
-	return abc;
+	return kspi_tx(pf, &tx, 1);
 }
 
-int CmdGetADC(struct file *pf, LPTIVA_ADC padc)
+/////////////////////////////////////////////////////////////////////////////
+
+int kspi_tx_rx_byte(struct file *pf, unsigned char tx, unsigned char *rx)
 {
-    int ret;
-    int len = 0;
-
-    ret = SendCMD(pf, CMD_GET_ADC , 0, NULL);
-
-    if(ret == CMD_ACK)
-    {
-		unsigned short data[128];
-		memset(data, 0, sizeof(data));
-
-        if((len = ReadCmd(pf, sizeof(data) - 1, ((unsigned char*)data) + 1)) == 13)
-        {
-            padc->UVers		= scale(0, 4096, 0, 4375, ntohs(data[1]));	// val / 100.0 + 0.4
-            padc->UBatV3	= scale(0, 4096, 0, 500, ntohs(data[2]));	// val / 100.0
-            padc->Temp		= lin_kty(ntohs(data[3]));					// val / 10.0
-            padc->UV5Vsys	= scale(0, 4096, 0, 570, ntohs(data[4]));	// val / 100.0
-            padc->UV3V6Bat	= scale(0, 4096, 0, 500, ntohs(data[5]));	// val / 100.0
-            padc->TempTIVA	= ntohs(data[6]);							// 147.5 - 187.5 * val / 4096.0
-            ret = 0;
-        }
-        else
-        {
-            printk(KERN_ALERT "CmdGetADC - ReadCmd - LEN = %d\n", len);
-	    	ret = -1;
-        }
-    }
-    else
-    {
-		printk(KERN_ALERT "CmdGetADC - SendCMD - ret = %d\n", ret);
-    	ret = -1;
-    }
-
-	transfer_1(pf, CMD_ACK); /* Testweise immer ACK */
-    return ret;
+	return kspi_tx_rx(pf, &tx, rx, 1);
 }

+ 13 - 15
kspi.h

@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/spi/spidev.h>
 #include <linux/syscalls.h>
+#include "defines.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -15,24 +16,21 @@ extern "C" {
 /////////////////////////////////////////////////////////////////////////////
 // kspi.h - Declarations:
 
-typedef struct _TIVA_ADC
-{
-	int UVers;
-	int UBatV3;
-	int Temp;
-	int UV5Vsys;
-	int UV3V6Bat;
-	int TempTIVA;
-}TIVA_ADC, *LPTIVA_ADC;
-typedef const TIVA_ADC *LPCTIVA_ADC;
+int kspi_write_mode			(struct file *pf, unsigned char mode);
+int kspi_read_mode			(struct file *pf, unsigned char *mode);
+int kspi_write_bits_per_word(struct file *pf, unsigned char bits);
+int kspi_read_bits_per_word	(struct file *pf, unsigned char *bits);
+int kspi_write_max_speed_hz	(struct file *pf, unsigned int speed);
+int kspi_read_max_speed_hz	(struct file *pf, unsigned int *speed);
 
 /////////////////////////////////////////////////////////////////////////////
 
-int SendCMD(struct file *pf, unsigned char Cmd, unsigned char DataLen, unsigned char *Data);
-int ReadCmd(struct file *pf, int MaxLen, unsigned char *Data);
-int CmdGetFirmwareVersion(struct file *pf, int *Hw, int *Sw);
-void getUPTIME(struct file *pf, unsigned int Addr, int nFwVersion);
-int CmdGetADC(struct file *pf, LPTIVA_ADC padc);
+int kspi_tx			(struct file *pf, const void *pData, size_t nCbData);
+int kspi_rx			(struct file *pf, void *pData, size_t nCbData);
+int kspi_tx_rx		(struct file *pf, const void *pTx, void *pRx, size_t nCb);
+int kspi_rx_byte	(struct file *pf, unsigned char *rx);
+int kspi_tx_byte	(struct file *pf, unsigned char tx);
+int kspi_tx_rx_byte	(struct file *pf, unsigned char tx, unsigned char *rx);
 
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus

+ 640 - 0
ktiva.c

@@ -0,0 +1,640 @@
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include "ktiva.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+extern int g_sw;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static const long g_kty_tab[][2] =
+{
+  {199,  1250},
+  {351,  1000},
+  {643,   750},
+  {1185,  500},
+  {2048,  250},
+  {3025,    0},
+  {3705, -250}
+};
+
+#define KTY_TAB_LEN				_countof(g_kty_tab)
+
+/////////////////////////////////////////////////////////////////////////////
+
+static int _lin_kty(int resistance)
+{
+	int i;
+
+	if(resistance <= g_kty_tab[0][0])
+		return(g_kty_tab[0][1]);
+	else if(resistance >= g_kty_tab[KTY_TAB_LEN - 1][0])
+		return(g_kty_tab[KTY_TAB_LEN - 1][1]);
+
+	for(i = 1; i < KTY_TAB_LEN; i++)
+	{
+		if(g_kty_tab[i][0] >= resistance)
+			break;
+	}
+
+	// linear interpolation
+	return 	g_kty_tab[i - 1][1]							+	// y1 +
+			(												// (
+				(g_kty_tab[i][1] - g_kty_tab[i - 1][1])	*	//    (y2 - y1)	*
+				(resistance - g_kty_tab[i - 1][0])		/	//    (x  - x1)	/
+				(g_kty_tab[i][0] - g_kty_tab[i - 1][0])		//    (x2 - x1)
+			);												// )
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static int _scale (int in_min, int in_max, int out_min, int out_max, int wert)
+{
+	int abc;
+	abc = (((long)out_max - (long)out_min) * (long)wert) / ( (long)in_max - (long)in_min);
+	abc = abc + out_min;
+	return abc;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+int ktiva_wait_ack(struct file *pf)
+{
+	int ret, i = 0;
+	unsigned char c = 0;
+//    unsigned long start = jiffies;
+    unsigned long timeout = jiffies + 2 *HZ; // 2 sec. timeout
+
+	while(c != CMD_ACK)
+	{
+		if((ret = kspi_rx_byte(pf, &c)) < 0)
+			return ret;
+		else if(c == CMD_NAK)
+		{
+			KALERT("%s: received NAK!\n", __FUNCTION__);
+			return -ECOMM;
+		}
+		else if(c != CMD_ACK)
+		{
+			++i;
+
+			if(time_is_before_eq_jiffies(timeout))
+			{
+				KALERT("%s: timeout!\n", __FUNCTION__);
+				return -ETIME;
+			}
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+		}
+	}
+
+//	KALERT("ktiva_wait_ack: jiffies: %lu, loops: %d\n", ((long)jiffies - (long)start), i);
+	return (c == CMD_ACK) ? 0 : -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int ktiva_send_frame(struct file *pf, unsigned char cmd, const void *pData, size_t nCbData)
+{
+	int ret;
+	size_t i, j = 0;
+	unsigned char buf[KTIVA_MAX_BUFFER_SIZE];
+	const unsigned char *pdat = (const unsigned char*)pData;
+
+#if _EXTENDED_ERROR_CHECK
+	if(nCbData > (sizeof(buf) - 3))
+	{
+		KALERT("%s: Invalid data length: %zu!\n", __FUNCTION__, nCbData);
+		return -ENOMEM;
+	}
+	else if(nCbData && !pData)
+	{
+		KALERT("%s: Invalid data pointer!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+#endif	//	_EXTENDED_ERROR_CHECK
+
+	buf[0] = (unsigned char)nCbData + 3;
+	buf[1] = cmd; // init checksum
+	buf[2] = cmd;
+
+	for(i = 0, j = 3; i < nCbData; ++i, ++j)
+	{
+		buf[1] += pdat[i]; // calc checksum
+		buf[j]  = pdat[i]; // fill in data
+	}
+
+	if((ret = kspi_tx(pf, buf, j)) < 0) // send data frame
+		return ret;
+
+	if((ret = ktiva_wait_ack(pf)) == 0) // wait for ACK
+		ret = (int)nCbData;
+	return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int ktiva_recv_frame(struct file *pf, unsigned char cmd, void *pData, size_t nCbData)
+{
+	int ret, i;
+	unsigned char chk = 0, len = 0;
+	unsigned char buf[KTIVA_MAX_BUFFER_SIZE];
+//    unsigned long start = jiffies;
+    unsigned long timeout = jiffies + HZ; // 1 sec. timeout
+
+#if _EXTENDED_ERROR_CHECK
+	if(nCbData && !pData)
+	{
+		KALERT("%s: Invalid data pointer!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+#endif	//	_EXTENDED_ERROR_CHECK
+
+	do
+	{
+		if((ret = kspi_rx_byte(pf, &len)) < 0) // receive length byte
+			return ret;
+
+		if(!len)
+		{
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+
+			if(time_is_before_eq_jiffies(timeout))
+			{
+				KALERT("%s: timeout!\n", __FUNCTION__);
+				return -ETIME;
+			}
+		}
+	}
+	while(!len);
+
+	if(len > (int)(nCbData + 3))
+	{
+		KALERT("%s: Insufficient buffer length: %zu - need %hhu!\n", __FUNCTION__, nCbData, len - 3);
+		return -ENOMEM;
+	}
+	else if(len < 2)
+	{
+		KALERT("%s: received invalid lenght: %hhu!\n", __FUNCTION__, len);
+		return -EPROTO;
+	}
+
+	if((ret = kspi_rx(pf, buf, len - 1)) < 0) // receive checksum, cmd + data
+		return ret;
+	else if(ret != (len - 1))
+	{
+		KALERT("%s: kspi_rx returned invalid lenght: %d!\n", __FUNCTION__, ret);
+		return -EPROTO;
+	}
+	else if(buf[1] != cmd)
+	{
+		KALERT("%s: invalid command: %hhu!\n", __FUNCTION__, buf[1]);
+		return -EPROTO;
+	}
+
+//	KALERT("ktiva_recv_frame: ordered: %hhu, received: %d!\n", len - 1, ret);
+
+	for(i = 1; i < ret; ++i)
+	{
+		chk += buf[i]; // calc checksum
+	}
+
+	if(buf[0] != chk)
+	{
+		KALERT("%s: checksum error: recv: %02hhX, calc: %02hhX!\n", __FUNCTION__, buf[0], chk);
+		return -EPROTO;
+	}
+
+	if(nCbData)
+		memcpy(pData, &buf[2], ret - 2);
+
+//	KALERT("%s: jiffies: %lu\n", __FUNCTION__, ((long)jiffies - (long)start));
+	return ret - 2;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int ktiva_recv_bootloader_frame(struct file *pf, unsigned char cmd, void *pData, size_t nCbData)
+{
+	int ret, i;
+	unsigned char chk = 0, len = 0;
+	unsigned char buf[KTIVA_MAX_BUFFER_SIZE];
+//    unsigned long start = jiffies;
+    unsigned long timeout = jiffies + HZ; // 1 sec. timeout
+
+#if _EXTENDED_ERROR_CHECK
+	if(nCbData && !pData)
+	{
+		KALERT("%s: Invalid data pointer!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+#endif	//	_EXTENDED_ERROR_CHECK
+
+	do
+	{
+		if((ret = kspi_rx_byte(pf, &len)) < 0) // receive length byte
+			return ret;
+
+		if(!len)
+		{
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+
+			if(time_is_before_eq_jiffies(timeout))
+			{
+				KALERT("%s: timeout!\n", __FUNCTION__);
+				return -ETIME;
+			}
+		}
+	}
+	while(!len);
+
+	if(len > (int)(nCbData + 3))
+	{
+		KALERT("%s: Insufficient buffer length: %zu - need %hhu!\n", __FUNCTION__, nCbData, len - 3);
+		return -ENOMEM;
+	}
+	else if(len < 2)
+	{
+		KALERT("%s: received invalid lenght: %hhu!\n", __FUNCTION__, len);
+		return -EPROTO;
+	}
+
+	if((ret = kspi_rx(pf, buf, len - 1)) < 0) // receive checksum + data
+		return ret;
+	else if(ret != (len - 1))
+	{
+		KALERT("%s: kspi_rx returned invalid lenght: %d!\n", __FUNCTION__, ret);
+		return -EPROTO;
+	}
+
+	for(i = 1; i < ret; ++i)
+	{
+		chk += buf[i]; // calc checksum
+	}
+
+	if(buf[0] != chk)
+	{
+		KALERT("%s: checksum error: recv: %02hhX, calc: %02hhX!\n", __FUNCTION__, buf[0], chk);
+		return -EPROTO;
+	}
+
+	if(nCbData)
+		memcpy(pData, &buf[1], ret - 1);
+
+	return ret - 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaRevive(struct file *pf)
+{
+	int ret, i = 0;
+	unsigned char c = 0;
+
+	for(i = 0; i < 256; ++i)
+	{
+		if((ret = kspi_rx_byte(pf, &c)) < 0)
+		{
+            KALERT("%s - kspi_rx_byte failed: %d\n", __FUNCTION__, ret);
+			return ret;
+		}
+		else if(c == CMD_ACK)
+			break;
+		else if(c == CMD_NAK)
+		{
+			KALERT("%s: received NAK\n", __FUNCTION__);
+			break;
+		}
+
+		if(i && !(i % 8))
+		{
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+		}
+	}
+
+	if(i == 256)
+	{
+		if((ret = kspi_tx_byte(pf, CMD_ACK)) < 0)
+		{
+            KALERT("%s - kspi_tx_byte failed: %d\n", __FUNCTION__, ret);
+			return ret;
+		}
+	}
+
+	KALERT("%s: loops: %d\n\n", __FUNCTION__, i);
+	return (c == CMD_ACK) ? 0 : -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdGetFirmwareVersion(struct file *pf, int *Hw, int *Sw)
+{
+    int ret;
+
+    if((ret = ktiva_send_frame(pf, COMMAND_GET_HWSW_REV, NULL, 0)) == 0)
+    {
+        int data[2];
+
+		if((ret = ktiva_recv_frame(pf, COMMAND_GET_HWSW_REV, data, sizeof(data))) == sizeof(data))
+        {
+            if(Hw)
+            	*Hw = ntohl(data[0]);
+            if(Sw)
+            	*Sw = ntohl(data[1]);
+
+			kspi_tx_byte(pf, CMD_ACK);
+            ret = 0;
+        }
+        else
+        {
+            KALERT("%s - ktiva_recv_frame failed: %d\n", __FUNCTION__, ret);
+        }
+    }
+    else
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdGetADC(struct file *pf, LPTIVA_ADC padc)
+{
+    int ret;
+
+#if _EXTENDED_ERROR_CHECK
+	if(!padc)
+	{
+		KALERT("%s: Invalid struct pointer!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+#endif	//	_EXTENDED_ERROR_CHECK
+
+    if((ret = ktiva_send_frame(pf, COMMAND_GET_ADC, NULL, 0)) == 0)
+    {
+		unsigned short data[6];
+
+		if((ret = ktiva_recv_frame(pf, COMMAND_GET_ADC, data, sizeof(data))) == sizeof(data))
+        {
+            padc->UVers		= _scale(0, 4096, 0, 4375, ntohs(data[0]));	// val / 100.0 + 0.4 (Versorgungsspannung skaliert)
+            padc->UBatV3	= _scale(0, 4096, 0, 500, ntohs(data[1]));	// val / 100.0 (Spannung Pufferbatterie skaliert)
+            padc->Temp		= _lin_kty(ntohs(data[2]));					// val / 10.0 (Boardtemperatur linear interpoliert)
+            padc->UV5Vsys	= _scale(0, 4096, 0, 570, ntohs(data[3]));	// val / 100.0 (interne 5V Hauptversorgungsspannung skaliert)
+            padc->UV3V6Bat	= _scale(0, 4096, 0, 500, ntohs(data[4]));	// val / 100.0 (interne 3V Akkuspannung skaliert)
+            padc->TempTIVA	= ntohs(data[5]);							// 147.5 - 187.5 * val / 4096.0 (TIVA-Temperatur)
+
+			kspi_tx_byte(pf, CMD_ACK);
+            ret = 0;
+        }
+        else
+        {
+            KALERT("%s - ktiva_recv_frame failed: %d\n", __FUNCTION__, ret);
+        }
+    }
+    else
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdGetUptime(struct file *pf, unsigned long long *put)
+{
+    int ret;
+
+    if(g_sw < 0x113)
+    {
+#if _SUPPORT_LEGACY_UPTIME
+	    unsigned int ut;
+		if((ret = TivaCmdGetAddress(pf, KTIVA_UPTIME_ADDRESS, &ut)) == 0)
+			*put = ut;
+		return ret;
+#else 	//	_SUPPORT_LEGACY_UPTIME
+		return -EPERM;
+#endif	// _SUPPORT_LEGACY_UPTIME
+	}
+
+#if _EXTENDED_ERROR_CHECK
+	if(!put)
+	{
+		KALERT("%s: Invalid data pointer!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+#endif	//	_EXTENDED_ERROR_CHECK
+
+    if((ret = ktiva_send_frame(pf, COMMAND_GET_UPTIME, NULL, 0)) == 0)
+    {
+		unsigned long long data;
+
+		if((ret = ktiva_recv_frame(pf, COMMAND_GET_UPTIME, &data, sizeof(data))) == sizeof(data))
+        {
+        	*put = be64_to_cpu(data);
+			kspi_tx_byte(pf, CMD_ACK);
+            ret = 0;
+        }
+        else
+        {
+            KALERT("%s - ktiva_recv_frame failed: %d\n", __FUNCTION__, ret);
+        }
+    }
+    else
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdGetAddress(struct file *pf, unsigned int addr, unsigned int *val)
+{
+    int ret;
+    unsigned int data = cpu_to_be32(addr);
+
+#if _EXTENDED_ERROR_CHECK
+	if(!val)
+	{
+		KALERT("%s: Invalid data pointer!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+#endif	//	_EXTENDED_ERROR_CHECK
+
+    if((ret = ktiva_send_frame(pf, COMMAND_GET_ADDR, &data, sizeof(data))) == sizeof(data))
+	{
+		if((ret = ktiva_recv_frame(pf, COMMAND_GET_ADDR, &data, sizeof(data))) == sizeof(data))
+        {
+        	*val = be32_to_cpu(data);
+			kspi_tx_byte(pf, CMD_ACK);
+            ret = 0;
+        }
+        else
+        {
+            KALERT("%s - ktiva_recv_frame failed: %d\n", __FUNCTION__, ret);
+			if(ret > 0)
+		    	ret = -1;
+        }
+    }
+    else
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdPing(struct file *pf)
+{
+    int ret;
+
+    if((ret = ktiva_send_frame(pf, COMMAND_PING, NULL, 0)) != 0)
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdGetStatus(struct file *pf, unsigned char *stat)
+{
+    int ret;
+    unsigned char data;
+
+#if _EXTENDED_ERROR_CHECK
+	if(!stat)
+	{
+		KALERT("%s: Invalid data pointer!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+#endif	//	_EXTENDED_ERROR_CHECK
+
+    if((ret = ktiva_send_frame(pf, COMMAND_GET_STATUS, NULL, 0)) == 0)
+	{
+		if((ret = ktiva_recv_frame(pf, COMMAND_GET_STATUS, &data, sizeof(data))) == sizeof(data))
+        {
+        	*stat = data;
+			kspi_tx_byte(pf, CMD_ACK);
+            ret = 0;
+        }
+        else
+        {
+            KALERT("%s - ktiva_recv_frame failed: %d\n", __FUNCTION__, ret);
+        }
+    }
+    else
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdGetBootloaderStatus(struct file *pf, unsigned char *stat)
+{
+    int ret;
+    unsigned char data;
+
+#if _EXTENDED_ERROR_CHECK
+	if(!stat)
+	{
+		KALERT("%s: Invalid data pointer!\n", __FUNCTION__);
+		return -EINVAL;
+	}
+#endif	//	_EXTENDED_ERROR_CHECK
+
+    if((ret = ktiva_send_frame(pf, COMMAND_GET_STATUS, NULL, 0)) == 0)
+	{
+		if((ret = ktiva_recv_bootloader_frame(pf, COMMAND_GET_STATUS, &data, sizeof(data))) == sizeof(data))
+        {
+        	*stat = data;
+			kspi_tx_byte(pf, CMD_ACK);
+            ret = 0;
+        }
+        else
+        {
+            KALERT("%s - ktiva_recv_frame failed: %d\n", __FUNCTION__, ret);
+        }
+    }
+    else
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdStartBootloader(struct file *pf)
+{
+    int ret;
+
+    if((ret = ktiva_send_frame(pf, COMMAND_START_BOOTLOADER, NULL, 0)) != 0)
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdStartDownload(struct file *pf, unsigned int addr, size_t size)
+{
+    int ret;
+    unsigned int data[2] = {cpu_to_be32(addr), cpu_to_be32((unsigned int)size)};
+
+    if((ret = ktiva_send_frame(pf, COMMAND_DOWNLOAD, data, sizeof(data))) != sizeof(data))
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdSendDataBlock(struct file *pf, const void *pBlock, size_t nCbBlock)
+{
+    int ret;
+
+    if((ret = ktiva_send_frame(pf, COMMAND_DOWNLOAD, pBlock, nCbBlock)) != nCbBlock)
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdReset(struct file *pf)
+{
+    int ret;
+
+    if((ret = ktiva_send_frame(pf, COMMAND_RESET, NULL, 0)) != 0)
+    {
+		KALERT("%s - ktiva_send_frame failed: %d!\n", __FUNCTION__, ret);
+    }
+
+    return ret;
+}

+ 79 - 0
ktiva.h

@@ -0,0 +1,79 @@
+// ktiva.h :
+//
+
+#if !defined(AGD_KTIVA_H__4F0F73D0_4834_4018_9B16_27F1B78686DB__INCLUDED_)
+#define AGD_KTIVA_H__4F0F73D0_4834_4018_9B16_27F1B78686DB__INCLUDED_
+
+#include "defines.h"
+#include "kspi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif	//	__cplusplus
+
+/////////////////////////////////////////////////////////////////////////////
+// ktiva.h - Declarations:
+
+#define CMD_ACK										0xCC
+#define CMD_NAK										0x33
+
+#define COMMAND_PING								0x20
+#define COMMAND_DOWNLOAD							0x21
+#define COMMAND_RUN									0x22
+#define COMMAND_GET_STATUS							0x23
+#define COMMAND_SEND_DATA							0x24
+#define COMMAND_RESET								0x25
+
+#define COMMAND_IO_TRANSFER							0x50
+#define COMMAND_GET_HWSW_REV						0x51
+#define COMMAND_GET_TIVA_TYPE						0x52
+#define COMMAND_START_BOOTLOADER					0x53
+#define COMMAND_GET_MCP7940							0x54
+#define COMMAND_SET_MCP7940							0x55
+#define COMMAND_GET_I2C								0x56
+#define COMMAND_PUT_I2C								0x57
+#define COMMAND_GET_ADDR							0x58
+#define COMMAND_SET_ADDR							0x59
+#define COMMAND_GET_ADC								0x5A
+#define COMMAND_SET_BACKLIGHT						0x5B
+#define COMMAND_GET_UPTIME							0x5C
+//#define COMMAND_GET_MATERIAL_SERIAL_ID				0x5D
+
+#define COMMAND_RET_SUCCESS							0x40
+#define COMMAND_RET_UNKNOWN_CMD						0x41
+#define COMMAND_RET_INVALID_CMD						0x42
+#define COMMAND_RET_INVALID_ADR						0x43
+#define COMMAND_RET_FLASH_FAIL						0x44
+#define COMMAND_RET_CRC_FAIL						0x45
+
+
+#define KTIVA_MAX_BUFFER_SIZE						256
+#define KTIVA_MAX_WAIT_LOOPS						100
+#define KTIVA_UPTIME_ADDRESS						0x200003C0
+
+/////////////////////////////////////////////////////////////////////////////
+
+int ktiva_wait_ack	(struct file *pf);
+int ktiva_send_frame(struct file *pf, unsigned char cmd, const void *pData, size_t nCbData);
+int ktiva_recv_frame(struct file *pf, unsigned char cmd, void *pData, size_t nCbData);
+
+/////////////////////////////////////////////////////////////////////////////
+
+int TivaCmdPing					(struct file *pf);
+int TivaCmdGetFirmwareVersion	(struct file *pf, int *Hw, int *Sw);
+int TivaCmdGetADC				(struct file *pf, LPTIVA_ADC padc);
+int TivaCmdGetUptime			(struct file *pf, unsigned long long *put);
+int TivaCmdGetAddress			(struct file *pf, unsigned int addr, unsigned int *val);
+int TivaCmdGetStatus			(struct file *pf, unsigned char *stat);
+int TivaCmdGetBootloaderStatus	(struct file *pf, unsigned char *stat);
+int TivaCmdStartBootloader		(struct file *pf);
+int TivaCmdStartDownload		(struct file *pf, unsigned int addr, size_t size);
+int TivaCmdSendDataBlock		(struct file *pf, const void *pBlock, size_t nCbBlock);
+int TivaCmdReset				(struct file *pf);
+int TivaRevive					(struct file *pf);
+
+/////////////////////////////////////////////////////////////////////////////
+#ifdef __cplusplus
+}
+#endif	//	__cplusplus
+#endif	//	!defined(AGD_KTIVA_H__4F0F73D0_4834_4018_9B16_27F1B78686DB__INCLUDED_)

+ 149 - 19
sfsattrib.c

@@ -6,76 +6,206 @@
 #include <linux/errno.h>
 #include <linux/sysfs.h>
 #include <linux/syscalls.h>
+#include "defines.h"
 #include "sfsattrib.h"
+#include "kfirmware.h"
 
 /////////////////////////////////////////////////////////////////////////////
 
-int g_hw = 0, g_sw = 0;
+int g_hw = -1, g_sw = -1;
 TIVA_ADC g_tadc;
+unsigned long long g_nUpTime = 0;
+void *g_pFwBuffer = NULL;
+size_t g_nCbFwData = 0;
+
+static bool g_bFwWriteLock = false;
+DEFINE_MUTEX(g_mutex);
+
+/////////////////////////////////////////////////////////////////////////////
+
+static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	if(g_hw < 0 || g_sw < 0)
+		return -ENODATA;
+	return sprintf(buf, "%d %d", g_hw, g_sw);
+}
 
 /////////////////////////////////////////////////////////////////////////////
 
-static ssize_t firmware_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+static ssize_t Uptime_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-	return sprintf(buf, "HW: %08X SW: %08X", g_hw, g_sw);
+	return sprintf(buf, "%llu", g_nUpTime);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
 static ssize_t UVers_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-	return sprintf(buf, "%d", g_tadc.UVers);
+	int nVal = g_tadc.UVers + 40;
+	return sprintf(buf, "%d.%02d", nVal / 100, nVal % 100);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
 static ssize_t UBatV3_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-	return sprintf(buf, "%d", g_tadc.UBatV3);
+	int nVal = g_tadc.UBatV3;
+	return sprintf(buf, "%d.%02d", nVal / 100, nVal % 100);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
-static ssize_t Temp_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+static ssize_t TempBoard_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-	return sprintf(buf, "%d", g_tadc.Temp);
+	int nVal = g_tadc.Temp;
+	return sprintf(buf, "%d.%d0", nVal / 10, nVal % 10);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
 static ssize_t UV5Vsys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-	return sprintf(buf, "%d", g_tadc.UV5Vsys);
+	int nVal = g_tadc.UV5Vsys;
+	return sprintf(buf, "%d.%02d", nVal / 100, nVal % 100);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
 static ssize_t UV3V6Bat_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-	return sprintf(buf, "%d", g_tadc.UV3V6Bat);
+	int nVal = g_tadc.UV3V6Bat;
+	return sprintf(buf, "%d.%02d", nVal / 100, nVal % 100);
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
 static ssize_t TempTIVA_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
-//	printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid);
-	return sprintf(buf, "%d", g_tadc.TempTIVA);
+	long nVal = 14750 - 18750 * g_tadc.TempTIVA / 4096;
+	return sprintf(buf, "%ld.%02ld", nVal / 100, nVal % 100);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+static ssize_t AdcBin_read(struct file *pf, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t len)
+{
+	if(off >= sizeof(g_tadc))
+		return 0;
+	if((len + off) > sizeof(g_tadc))
+		len = sizeof(g_tadc) - off;
+
+	mutex_lock(&g_mutex);
+	memcpy(buf, ((const unsigned char*)&g_tadc) + off, len);
+	mutex_unlock(&g_mutex);
+//	KALERT("%s buf: %p, off: %lld, len: %zu\n", __FUNCTION__, buf, off, len);
+	return (ssize_t)len;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 
-struct kobj_attribute g_tivaFirmwareAtt = __ATTR_RO(firmware);
+static ssize_t firmware_read(struct file *pf, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t len)
+{
+	return -EACCES;
+/*	if(off >= g_nCbFwData)
+		return 0;
+	if((off + len) > g_nCbFwData)
+		len = g_nCbFwData - off;
+
+	mutex_lock(&g_mutex);
+	memcpy(buf, ((char*)g_pFwBuffer) + off, len);
+	mutex_unlock(&g_mutex);
+
+	KALERT("%s buf: %p, off: %lld, len: %zu\n", __FUNCTION__, buf, off, len);
+	return len;*/
+}
+
+static ssize_t firmware_write(struct file *pf, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t len)
+{
+	int nRet;
+	size_t nCbUbound;
+	static KFW_DROP_CTX dctx;
+
+	if(SfAttIsFirmwareLocked())
+		return -EBUSY;
+	else if(len == 0)
+		return 0;
+	else if(off < 0)
+		return -EFAULT;
+	else if(off >= _FIRMWARE_BUFFER_SIZE)
+		return -ENOMEM;
+	else if((off + len) > _FIRMWARE_BUFFER_SIZE)
+		len = _FIRMWARE_BUFFER_SIZE - off;
+	
+	if(off == 0) // first block of data
+	{
+		memset(&dctx, 0, sizeof(dctx));
+		mutex_lock(&g_mutex);
+		g_nCbFwData = 0;
+		memset(g_pFwBuffer, 0xFF, _FIRMWARE_BUFFER_SIZE);
+		mutex_unlock(&g_mutex);
+	}
+
+	nCbUbound = off + len;
+
+	mutex_lock(&g_mutex);
+	memcpy(((char*)g_pFwBuffer) + off, buf, len);
+	if(g_nCbFwData < nCbUbound)
+		g_nCbFwData = nCbUbound;
+	mutex_unlock(&g_mutex);
+	
+	if((nRet = KfwOnDataDropped(g_pFwBuffer, g_nCbFwData, &dctx)) < 0)
+	{
+		mutex_lock(&g_mutex);
+		g_nCbFwData = 0;
+		mutex_unlock(&g_mutex);
+		memset(&dctx, 0, sizeof(dctx));
+		SfAttLockFirmware(false);
+		return nRet;
+	}
+	else if(nRet > 0)
+	{
+		mutex_lock(&g_mutex);
+		g_nCbFwData = 0;
+		mutex_unlock(&g_mutex);
+		memset(&dctx, 0, sizeof(dctx));
+	}
+
+//	KALERT("%s buf: %p, off: %lld, len: %zu\n", __FUNCTION__, buf, off, len);
+	return len;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+bool SfAttIsFirmwareLocked(void)
+{
+	bool bRet;
+	mutex_lock(&g_mutex);
+	bRet = g_bFwWriteLock;
+	mutex_unlock(&g_mutex);
+	return bRet;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void SfAttLockFirmware(bool bLock)
+{
+	mutex_lock(&g_mutex);
+	g_bFwWriteLock = bLock;
+	mutex_unlock(&g_mutex);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+struct kobj_attribute g_tivaVersionAtt	= __ATTR_RO(version);
 
 struct kobj_attribute g_tivaUVersAtt	= __ATTR_RO(UVers);
 struct kobj_attribute g_tivaUBatV3Att	= __ATTR_RO(UBatV3);
-struct kobj_attribute g_tivaTempAtt		= __ATTR_RO(Temp);
+struct kobj_attribute g_tivaTempAtt		= __ATTR_RO(TempBoard);
 struct kobj_attribute g_tivaUV5VsysAtt	= __ATTR_RO(UV5Vsys);
 struct kobj_attribute g_tivaUV3V6BatAtt	= __ATTR_RO(UV3V6Bat);
 struct kobj_attribute g_tivaTempTIVAAtt	= __ATTR_RO(TempTIVA);
+struct bin_attribute g_tivaAdcBinAtt	= __BIN_ATTR_RO(AdcBin, sizeof(TIVA_ADC));
+
+struct kobj_attribute g_tivaUptimeAtt	= __ATTR_RO(Uptime);
+
+struct bin_attribute g_tivaFirmwareAtt	= __BIN_ATTR_RW(firmware, 0);

+ 17 - 3
sfsattrib.h

@@ -4,7 +4,8 @@
 #if !defined(AGD_SFSATTRIB_H__FA9B0DBB_F45F_475D_9C05_C528DA903997__INCLUDED_)
 #define AGD_SFSATTRIB_H__FA9B0DBB_F45F_475D_9C05_C528DA903997__INCLUDED_
 
-#include "kspi.h"
+#include <linux/mutex.h>
+#include "defines.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -15,14 +16,27 @@ extern "C" {
 
 extern int g_hw, g_sw;
 extern TIVA_ADC g_tadc;
-extern struct kobj_attribute g_tivaFirmwareAtt;
-extern struct kobj_attribute g_tivaFirmwareAtt;
+extern unsigned long long g_nUpTime;
+extern void *g_pFwBuffer;
+extern size_t g_nCbFwData;
+extern struct mutex g_mutex;
+
+extern struct kobj_attribute g_tivaVersionAtt;
+
 extern struct kobj_attribute g_tivaUVersAtt;
 extern struct kobj_attribute g_tivaUBatV3Att;
 extern struct kobj_attribute g_tivaTempAtt;
 extern struct kobj_attribute g_tivaUV5VsysAtt;
 extern struct kobj_attribute g_tivaUV3V6BatAtt;
 extern struct kobj_attribute g_tivaTempTIVAAtt;
+extern struct bin_attribute g_tivaAdcBinAtt;
+
+extern struct kobj_attribute g_tivaUptimeAtt;
+
+extern struct bin_attribute g_tivaFirmwareAtt;
+
+void SfAttLockFirmware(bool bLock);
+bool SfAttIsFirmwareLocked(void);
 
 /////////////////////////////////////////////////////////////////////////////
 #ifdef __cplusplus

+ 248 - 207
test/main.c

@@ -1,207 +1,248 @@
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/statvfs.h>
-#include <sys/statfs.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <poll.h>
-#include <fcntl.h>
-#include <errno.h>
-
-/////////////////////////////////////////////////////////////////////////////
-
-#ifdef _DEBUG
-#define TRACE(...)							fprintf(stdout, __VA_ARGS__), fflush(stdout)
-#else	//	_DEBUG
-#define TRACE(...)
-#endif	//	_DEBUG
-
-#define UNUSED(v)							(void)v
-#define _countof(a)							(sizeof(a) / sizeof(*a))
-
-#define _CYCLE_INTV							500
-
-static bool g_bRun = true;
-
-/////////////////////////////////////////////////////////////////////////////
-
-typedef struct _ATTRIBS
-{
-	const char *pszName;
-	double (*fmt)(const char*);
-}ATTRIBS, *LPATTRIBS;
-typedef const ATTRIBS *LPCATTRIBS;
-
-/////////////////////////////////////////////////////////////////////////////
-
-static void _SigHandler(int sig)
-{
-	UNUSED(sig);
-	g_bRun = false;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-static double _FmtUVers(const char *pszVal)
-{
-	int nVal = atoi(pszVal);
-	return (double)nVal / 100.0 + 0.4;
-}
-
-static double _FmtUBatV3(const char *pszVal)
-{
-	int nVal = atoi(pszVal);
-	return (double)nVal / 100.0;
-}
-
-static double _FmtTemp(const char *pszVal)
-{
-	int nVal = atoi(pszVal);
-	return (double)nVal / 10.0;
-}
-
-static double _FmtUV5Vsys(const char *pszVal)
-{
-	int nVal = atoi(pszVal);
-	return (double)nVal / 100.0;
-}
-
-static double _FmtUV3V6Bat(const char *pszVal)
-{
-	int nVal = atoi(pszVal);
-	return (double)nVal / 100.0;
-}
-
-static double _FmtTempTIVA(const char *pszVal)
-{
-	int nVal = atoi(pszVal);
-	return 147.5 - 187.5 * (double)nVal / 4096.0;
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-int main(int argc, char *argv[])
-{
-	static const ATTRIBS attribs[] =
-	{
-		{
-			.pszName = "UVers",
-			.fmt = _FmtUVers
-		},
-		{
-			.pszName = "UBatV3",
-			.fmt = _FmtUBatV3
-		},
-		{
-			.pszName = "Temp",
-			.fmt = _FmtTemp
-		},
-		{
-			.pszName = "UV5Vsys",
-			.fmt = _FmtUV5Vsys
-		},
-		{
-			.pszName = "UV3V6Bat",
-			.fmt = _FmtUV3V6Bat
-		},
-		{
-			.pszName = "TempTIVA",
-			.fmt = _FmtTempTIVA
-		}
-	};
-
-	const ATTRIBS *attribsCur[_countof(attribs)];
-
-	/////////////////////////////////////////////////////////////////////////
-
-	int nRet, nCntAtts, i;
-	char szBuf[256];
-	struct pollfd pfd[6];
-	struct sigaction sa;
-
-	memset(pfd, 0, sizeof(pfd));
-	memset(&sa, 0, sizeof(sa));
-	UNUSED(argc);
-	UNUSED(argv);
-
-	/////////////////////////////////////////////////////////////////////////
-
-	// handle signals
-	sa.sa_handler = _SigHandler;
-    sigaction(SIGHUP, &sa, NULL);	// handles user's terminal disconnect
-    sigaction(SIGQUIT, &sa, NULL);	// handles Ctrl + '\'
-	sigaction(SIGTERM, &sa, NULL);	// handles normal termination
-	sigaction(SIGABRT, &sa, NULL);	// handles abnormal termination (i.e. abort())
-	sigaction(SIGINT, &sa, NULL);	// handles Ctrl + 'C'
-
-	// ignore signals
-	sa.sa_handler = SIG_IGN;
-    sigaction(SIGTSTP, &sa, NULL);	// ignores Ctrl + 'Z'
-    sigaction(SIGCHLD, &sa, NULL);	// ignores child process termination
-    sigaction(0, &sa, NULL);		// ignores shell termination
-
-	/////////////////////////////////////////////////////////////////////////
-
-	for(i = 0, nCntAtts = 0; i < (int)_countof(attribs); ++i)
-	{
-		int fd;
-		char szDevNode[128];
-		sprintf(szDevNode, "/sys/gfa/tiva/%s", attribs[i].pszName);
-
-		if((fd = open(szDevNode, O_RDONLY, 0)) >= 0)
-		{
-			pfd[nCntAtts].fd = fd;
-			pfd[nCntAtts].events = POLLPRI;
-			attribsCur[nCntAtts] = &attribs[i];
-			++nCntAtts;
-		}
-	}
-
-	/////////////////////////////////////////////////////////////////////////
-	
-	if(nCntAtts > 0)
-	{
-		while(g_bRun && ((nRet = poll(pfd, nCntAtts, _CYCLE_INTV)) >= 0))
-		{
-			if(nRet > 0)
-			{
-				for(i = 0; i < nCntAtts; ++i)
-				{
-					if(pfd[i].revents & POLLPRI)
-					{
-						szBuf[0] = '\0';
-
-						if((nRet = read(pfd[i].fd, szBuf, sizeof(szBuf))) >= 0)
-						{
-							szBuf[nRet] = '\0';
-							lseek(pfd[i].fd, 0, SEEK_SET);
-							TRACE("%-8s: %.2f\n", attribsCur[i]->pszName, attribsCur[i]->fmt(szBuf));
-						}
-						else
-						{
-							g_bRun = false;
-							break;
-						}
-					}
-				}
-			}
-		}
-
-		if(nRet < 0)
-		{
-			TRACE("%s\n", strerror(errno));
-		}
-	}
-
-	for(i = 0; i < nCntAtts; ++i)
-	{
-		if(pfd[i].fd >= 0)
-			close(pfd[i].fd);
-	}
-
-	return 0;
-}
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/statvfs.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "../defines.h"
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define _USE_BIN_ADC						1
+
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef _DEBUG
+#define TRACE(...)							fprintf(stdout, __VA_ARGS__), fflush(stdout)
+#else	//	_DEBUG
+#define TRACE(...)
+#endif	//	_DEBUG
+
+#define UNUSED(v)							(void)v
+#define _countof(a)							(sizeof(a) / sizeof(*a))
+
+#define _CYCLE_INTV							500
+
+static bool g_bRun = true;
+
+/////////////////////////////////////////////////////////////////////////////
+
+typedef struct _ATTRIBS
+{
+	const char *pszName;
+	double (*fmt)(const char*);
+}ATTRIBS, *LPATTRIBS;
+typedef const ATTRIBS *LPCATTRIBS;
+
+/////////////////////////////////////////////////////////////////////////////
+
+static void _SigHandler(int sig)
+{
+	UNUSED(sig);
+	g_bRun = false;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+#if !_USE_BIN_ADC
+static double _FmtUVers(const char *pszVal)
+{
+	int nVal = atoi(pszVal);
+	return (double)nVal / 100.0 + 0.4;
+}
+
+static double _FmtUBatV3(const char *pszVal)
+{
+	int nVal = atoi(pszVal);
+	return (double)nVal / 100.0;
+}
+
+static double _FmtTemp(const char *pszVal)
+{
+	int nVal = atoi(pszVal);
+	return (double)nVal / 10.0;
+}
+
+static double _FmtUV5Vsys(const char *pszVal)
+{
+	int nVal = atoi(pszVal);
+	return (double)nVal / 100.0;
+}
+
+static double _FmtUV3V6Bat(const char *pszVal)
+{
+	int nVal = atoi(pszVal);
+	return (double)nVal / 100.0;
+}
+
+static double _FmtTempTIVA(const char *pszVal)
+{
+	int nVal = atoi(pszVal);
+	return 147.5 - 187.5 * (double)nVal / 4096.0;
+}
+#endif	//	_USE_BIN_ADC
+
+/////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char *argv[])
+{
+	static const ATTRIBS attribs[] =
+	{
+#if _USE_BIN_ADC
+		{
+			.pszName = "AdcBin"
+		}
+#else 
+{
+	//	_USE_BIN_ADC
+}
+		{
+			.pszName = "UVers",
+			.fmt = _FmtUVers
+		},
+		{
+			.pszName = "UBatV3",
+			.fmt = _FmtUBatV3
+		},
+		{
+            .pszName = "TempBoard",
+			.fmt = _FmtTemp
+		},
+		{
+			.pszName = "UV5Vsys",
+			.fmt = _FmtUV5Vsys
+		},
+		{
+			.pszName = "UV3V6Bat",
+			.fmt = _FmtUV3V6Bat
+		},
+		{
+			.pszName = "TempTIVA",
+			.fmt = _FmtTempTIVA
+		}
+#endif	//	_USE_BIN_ADC
+	};
+
+	const ATTRIBS *attribsCur[_countof(attribs)];
+
+	/////////////////////////////////////////////////////////////////////////
+
+#if _USE_BIN_ADC
+	TIVA_ADC tadc;
+#else	//	_USE_BIN_ADC
+	char szBuf[256];
+#endif	//	_USE_BIN_ADC
+	int nRet, nCntAtts, i;
+	struct pollfd pfd[6];
+	struct sigaction sa;
+
+	memset(pfd, 0, sizeof(pfd));
+	memset(&sa, 0, sizeof(sa));
+	UNUSED(argc);
+	UNUSED(argv);
+
+	/////////////////////////////////////////////////////////////////////////
+
+	// handle signals
+	sa.sa_handler = _SigHandler;
+    sigaction(SIGHUP, &sa, NULL);	// handles user's terminal disconnect
+    sigaction(SIGQUIT, &sa, NULL);	// handles Ctrl + '\'
+	sigaction(SIGTERM, &sa, NULL);	// handles normal termination
+	sigaction(SIGABRT, &sa, NULL);	// handles abnormal termination (i.e. abort())
+	sigaction(SIGINT, &sa, NULL);	// handles Ctrl + 'C'
+
+	// ignore signals
+	sa.sa_handler = SIG_IGN;
+    sigaction(SIGTSTP, &sa, NULL);	// ignores Ctrl + 'Z'
+    sigaction(SIGCHLD, &sa, NULL);	// ignores child process termination
+    sigaction(0, &sa, NULL);		// ignores shell termination
+
+	/////////////////////////////////////////////////////////////////////////
+
+	for(i = 0, nCntAtts = 0; i < (int)_countof(attribs); ++i)
+	{
+		int fd;
+		char szDevNode[128];
+		sprintf(szDevNode, "/sys/gfa/tiva/%s", attribs[i].pszName);
+
+		if((fd = open(szDevNode, O_RDONLY, 0)) >= 0)
+		{
+			pfd[nCntAtts].fd = fd;
+			pfd[nCntAtts].events = POLLPRI;
+			attribsCur[nCntAtts] = &attribs[i];
+			++nCntAtts;
+		}
+	}
+
+	/////////////////////////////////////////////////////////////////////////
+	
+	if(nCntAtts > 0)
+	{
+		while(g_bRun && ((nRet = poll(pfd, nCntAtts, _CYCLE_INTV)) >= 0))
+		{
+			if(nRet > 0)
+			{
+#if !_USE_BIN_ADC
+				for(i = 0; i < nCntAtts; ++i)
+				{
+					if(pfd[i].revents & POLLPRI)
+					{
+						szBuf[0] = '\0';
+
+						if((nRet = read(pfd[i].fd, szBuf, sizeof(szBuf))) >= 0)
+						{
+							szBuf[nRet] = '\0';
+							lseek(pfd[i].fd, 0, SEEK_SET);
+							TRACE("%-8s: %s\n", attribsCur[i]->pszName, szBuf);
+						}
+						else
+						{
+							g_bRun = false;
+							break;
+						}
+					}
+				}
+#else	//	_USE_BIN_ADC
+				if(pfd[0].revents & POLLPRI)
+				{
+					if((nRet = read(pfd[0].fd, &tadc, sizeof(tadc))) >= 0)
+					{
+						lseek(pfd[0].fd, 0, SEEK_SET);
+						TRACE("UVers   : %.2f V\n",  (double)tadc.UVers / 100.0 + 0.4);
+						TRACE("UBatV3  : %.2f V\n",  (double)tadc.UBatV3 / 100.0);
+						TRACE("Temp    : %.2f °C\n", (double)tadc.Temp / 10.0);
+						TRACE("UV5Vsys : %.2f V\n",  (double)tadc.UV5Vsys / 100.0);
+						TRACE("UV3V6Bat: %.2f V\n",  (double)tadc.UV3V6Bat / 100.0);
+						TRACE("TempTIVA: %.2f °C\n\n", 147.5 - 187.5 * (double)tadc.TempTIVA / 4096.0);
+					}
+					else
+					{
+						g_bRun = false;
+						break;
+					}
+				}
+#endif	//	_USE_BIN_ADC
+			}
+		}
+
+		if(nRet < 0)
+		{
+			TRACE("%s\n", strerror(errno));
+		}
+	}
+
+	for(i = 0; i < nCntAtts; ++i)
+	{
+		if(pfd[i].fd >= 0)
+			close(pfd[i].fd);
+	}
+
+	return 0;
+}