#include #include #include #include #include #include #include #include #include #include "defines.h" #include "sfsattrib.h" #include "kfirmware.h" #include "ksync.h" #include "kfile.h" #include "ktiva.h" ///////////////////////////////////////////////////////////////////////////// #ifndef __BIN_ATTR_WO #define __BIN_ATTR_WO(_name, _size) { \ .attr = { .name = __stringify(_name), .mode = S_IWUSR }, \ .write = _name##_write, \ .size = _size, \ } #endif // __BIN_ATTR_WO ///////////////////////////////////////////////////////////////////////////// int g_hw = -1, g_sw = -1; TIVA_ADC g_tadc; unsigned long long g_nUpTime = 0; TIVA_DCAP g_dcaps; TIVA_MEMORY_MAP g_tiMM[] = { { // Flash .baseAddr = KTIVA_FLASH_BASE_ADDRESS, .bIsRO = true }, { // SRAM .baseAddr = KTIVA_SRAM_BASE_ADDRESS, .bIsRO = false }, { // Bit banded SRAM .baseAddr = KTIVA_SRAM_BIT_BAND_BASE_ADDRESS, .bIsRO = false }, { // Peripherals .baseAddr = KTIVA_PERIPHERALS_BASE_ADDRESS, .size = KTIVA_PERIPHERALS_SIZE, .bIsRO = false }, { // Bit banded Peripherals .baseAddr = KTIVA_PERIPHERALS_BIT_BAND_BASE_ADDRESS, .size = KTIVA_PERIPHERALS_BIT_BAND_SIZE, .bIsRO = false } }; static void *g_pFwBuffer = NULL; static size_t g_nCbFwData = 0; static atomic_t g_flgFwLocked; static atomic_t g_flgBacklightChanged; static atomic_t g_valBacklightDutyCyclePercent; static atomic_t g_valBacklightPeriod; ///////////////////////////////////////////////////////////////////////////// void time64_to_tm(time64_t totalsecs, int offset, struct tm *result); ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// bool SfAttInit(void) { g_nCbFwData = 0; atomic_set(&g_flgBacklightChanged, 0); SfAttSetBacklightPeriod(_BACKLIGHT_PERIOD_DEFAULT); SfAttSetBacklightDutyCyclePercent(_BACKLIGHT_DUTY_CYCLE_PERC_DEF); if(krtc_init() < 0) { KALERT("%s: krtc_init failed!\n", __FUNCTION__); } memset(&g_dcaps, 0xFF, sizeof(g_dcaps)); g_pFwBuffer = (void*)__get_free_pages(GFP_KERNEL, _FIRMWARE_PAGES_COUNT); return !!g_pFwBuffer; } void SfAttExit(void) { g_nCbFwData = 0; if(g_pFwBuffer) { free_pages((unsigned long)g_pFwBuffer, _FIRMWARE_PAGES_COUNT); g_pFwBuffer = NULL; } } ///////////////////////////////////////////////////////////////////////////// static bool _AddressReadable(unsigned int nAddr, unsigned int nLength) { size_t i; LPCTIVA_MEMORY_MAP pmm = g_tiMM; for(i = 0; i < _countof(g_tiMM); ++i, ++pmm) { if( (nAddr < pmm->baseAddr + pmm->size) && (nAddr >= pmm->baseAddr)) { return (nAddr + nLength) <= pmm->baseAddr + pmm->size; } } return false; } static bool _AddressWriteable(unsigned int nAddr, unsigned int nLength) { size_t i; LPCTIVA_MEMORY_MAP pmm = g_tiMM; for(i = 0; i < _countof(g_tiMM); ++i, ++pmm) { if( !pmm->bIsRO && (nAddr < pmm->baseAddr + pmm->size) && (nAddr >= pmm->baseAddr)) { return (nAddr + nLength) <= pmm->baseAddr + pmm->size; } } return false; } ///////////////////////////////////////////////////////////////////////////// static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int hw, sw; ksync_lock(); hw = g_hw; sw = g_sw; ksync_unlock(); return sprintf(buf, "%d %d", hw, sw); } ///////////////////////////////////////////////////////////////////////////// static ssize_t did_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { TIVA_DCAP dcaps; ksync_lock(); dcaps = g_dcaps; ksync_unlock(); return sprintf(buf, "DID0: %08X\n" \ "DID1: %08X\n" \ "##############\n" \ "DID0Ver: %X\n" \ "Class: %X\n" \ "RevMaj: %X\n" \ "RevMin: %X\n" \ "##############\n" \ "DID1Ver: %X\n" \ "Family: %X\n" \ "PartNo: %X\n" \ "PinCnt: %X\n" \ "TempRange: %X\n" \ "PackageType: %X\n" \ "RoHSComp: %X\n" \ "QualStat: %X\n", \ dcaps.did0, dcaps.did1, dcaps.ver0, dcaps.cls, dcaps.maj, dcaps.min, dcaps.ver1, dcaps.fam, dcaps.partno, dcaps.pincnt, dcaps.temp, dcaps.pkg, dcaps.rohs, dcaps.qual); } static ssize_t uptime_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { unsigned long long nVal; ksync_lock(); nVal = g_nUpTime; ksync_unlock(); return sprintf(buf, "%llu", nVal); } ///////////////////////////////////////////////////////////////////////////// static ssize_t UVers_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int nVal; ksync_lock(); nVal = g_tadc.UVers + 40; ksync_unlock(); return sprintf(buf, "%d.%02d", nVal / 100, nVal % 100); } ///////////////////////////////////////////////////////////////////////////// static ssize_t UBatV3_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int nVal; ksync_lock(); nVal = g_tadc.UBatV3; ksync_unlock(); return sprintf(buf, "%d.%02d", nVal / 100, nVal % 100); } ///////////////////////////////////////////////////////////////////////////// static ssize_t TempBoard_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int nVal; ksync_lock(); nVal = g_tadc.Temp; ksync_unlock(); return sprintf(buf, "%d.%d0", nVal / 10, nVal % 10); } ///////////////////////////////////////////////////////////////////////////// static ssize_t UV5Vsys_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int nVal; ksync_lock(); nVal = g_tadc.UV5Vsys; ksync_unlock(); return sprintf(buf, "%d.%02d", nVal / 100, nVal % 100); } ///////////////////////////////////////////////////////////////////////////// static ssize_t UV3V6Bat_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int nVal; ksync_lock(); nVal = g_tadc.UV3V6Bat; ksync_unlock(); return sprintf(buf, "%d.%02d", nVal / 100, nVal % 100); } ///////////////////////////////////////////////////////////////////////////// static ssize_t TempTIVA_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { long nVal; ksync_lock(); nVal = 14750 - 18750 * g_tadc.TempTIVA / 4096; ksync_unlock(); 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; ksync_lock(); memcpy(buf, ((const unsigned char*)&g_tadc) + off, len); ksync_unlock(); return (ssize_t)len; } ///////////////////////////////////////////////////////////////////////////// static ssize_t dutycycle_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { ssize_t ret = -EINVAL; if(buf && count) { char szBuf[32]; long long val; if(count >= sizeof(szBuf)) return -ENOMEM; memcpy(szBuf, buf, count); szBuf[count] = '\0'; if(!(ret = kstrtoll(szBuf, 10, &val))) { SfAttSetBacklightDutyCyclePercent(val); atomic_set(&g_flgBacklightChanged, 1); ret = count; } } return ret; } ///////////////////////////////////////////////////////////////////////////// static ssize_t period_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { ssize_t ret = -EINVAL; if(buf && count) { char szBuf[32]; long long val; if(count >= sizeof(szBuf)) return -ENOMEM; memcpy(szBuf, buf, count); szBuf[count] = '\0'; if(!(ret = kstrtoll(szBuf, 10, &val))) { SfAttSetBacklightPeriod(val); atomic_set(&g_flgBacklightChanged, 1); ret = count; } } return ret; } ///////////////////////////////////////////////////////////////////////////// #if 0 static ssize_t image_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; ksync_lock(); memcpy(buf, ((char*)g_pFwBuffer) + off, len); ksync_unlock(); KALERT("%s buf: %p, off: %lld, len: %zu\n", __FUNCTION__, buf, off, len); return len;*/ } #endif // only works with image-version 0x144 or greater! static ssize_t image_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)); ksync_lock(); g_nCbFwData = 0; memset(g_pFwBuffer, 0xFF, _FIRMWARE_BUFFER_SIZE); ksync_unlock(); } nCbUbound = off + len; ksync_lock(); memcpy(((char*)g_pFwBuffer) + off, buf, len); if(g_nCbFwData < nCbUbound) g_nCbFwData = nCbUbound; ksync_unlock(); if((nRet = KfwOnDataDropped(g_pFwBuffer, g_nCbFwData, &dctx)) < 0) { ksync_lock(); g_nCbFwData = 0; ksync_unlock(); memset(&dctx, 0, sizeof(dctx)); SfAttLockFirmware(false); return nRet; } else if(nRet > 0) { ksync_lock(); g_nCbFwData = 0; ksync_unlock(); memset(&dctx, 0, sizeof(dctx)); } // KALERT("%s buf: %p, off: %lld, len: %zu\n", __FUNCTION__, buf, off, len); return len; } ///////////////////////////////////////////////////////////////////////////// static ssize_t mem_read(struct file *pf, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t len) { int ret; unsigned int val; struct file *pfSpiDev = NULL; if(SfAttIsFirmwareLocked()) return -EBUSY; if(off & 0x00000003) { KALERT("%s: Invalid address: %lld\n", __FUNCTION__, off); return -EFAULT; } if(len > sizeof(val)) len = sizeof(val); else if(len < sizeof(val)) { KALERT("%s: Buffer too small: %zu\n", __FUNCTION__, len); return -EINVAL; } if(!_AddressReadable(off, len)) { KALERT("%s: Invalid address (0x%llX) or length (%zu)\n", __FUNCTION__, off, len); return -EACCES; } // KALERT("%s: Try to read from 0x%08llX, length %zu Bytes.\n", __FUNCTION__, off, len); if((pfSpiDev = kf_open_locked(_SPI_DEVICE, O_RDWR, 0))) { if(KSpiInit(pfSpiDev)) { if(!(ret = TivaCmdGetAddress(pfSpiDev, (unsigned int)off, &val))) { memcpy(buf, &val, len); ret = (ssize_t)len; } else { KALERT("%s: TivaCmdGetAddress failed (%d)\n", __FUNCTION__, ret); ret = -EIO; } } else { KALERT("%s: KSpiInit failed\n", __FUNCTION__); ret = -EIO; } kf_close(pfSpiDev); } else { KALERT("%s: kf_open_locked failed\n", __FUNCTION__); ret = -EIO; } return ret; } static ssize_t mem_write(struct file *pf, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t len) { int ret; struct file *pfSpiDev = NULL; if(SfAttIsFirmwareLocked()) return -EBUSY; if(off & 0x00000003) { KALERT("%s: Invalid address: %lld\n", __FUNCTION__, off); return -EFAULT; } if(len != sizeof(unsigned int)) { KALERT("%s: Invalid buffer size: %zu (must be %zu)\n", __FUNCTION__, len, sizeof(unsigned int)); return -EINVAL; } if(!_AddressWriteable(off, len)) { KALERT("%s: Invalid address (0x%llX) or length (%zu) or range is read-only!\n", __FUNCTION__, off, len); return -EACCES; } if((pfSpiDev = kf_open_locked(_SPI_DEVICE, O_RDWR, 0))) { if(KSpiInit(pfSpiDev)) { unsigned int val; memcpy(&val, buf, sizeof(val)); if(!(ret = TivaCmdSetAddress(pfSpiDev, (unsigned int)off, val))) { ret = (ssize_t)len; } else { KALERT("%s: TivaCmdSetAddress failed (%d)\n", __FUNCTION__, ret); ret = -EIO; } } else { KALERT("%s: KSpiInit failed\n", __FUNCTION__); ret = -EIO; } kf_close(pfSpiDev); } else { KALERT("%s: kf_open_locked failed\n", __FUNCTION__); ret = -EIO; } return ret; } static ssize_t map_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "On-chip FLASH: %08X-%08X %7X %s\n" \ "On-chip SRAM: %08X-%08X %7X %s\n" \ "BBA SRAM: %08X-%08X %7X %s\n" \ "Peripheral: %08X-%08X %7X %s\n" \ "BBA Peripheral: %08X-%08X %7X %s\n", g_tiMM[0].baseAddr, g_tiMM[0].baseAddr + g_tiMM[0].size - 1, g_tiMM[0].size, g_tiMM[0].bIsRO ? "RO" : "RW", g_tiMM[1].baseAddr, g_tiMM[1].baseAddr + g_tiMM[1].size - 1, g_tiMM[1].size, g_tiMM[1].bIsRO ? "RO" : "RW", g_tiMM[2].baseAddr, g_tiMM[2].baseAddr + g_tiMM[2].size - 1, g_tiMM[2].size, g_tiMM[2].bIsRO ? "RO" : "RW", g_tiMM[3].baseAddr, g_tiMM[3].baseAddr + g_tiMM[3].size - 1, g_tiMM[3].size, g_tiMM[3].bIsRO ? "RO" : "RW", g_tiMM[4].baseAddr, g_tiMM[4].baseAddr + g_tiMM[4].size - 1, g_tiMM[4].size, g_tiMM[4].bIsRO ? "RO" : "RW"); } ///////////////////////////////////////////////////////////////////////////// static ssize_t iso8601_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int ret; struct tm tm; if(SfAttIsFirmwareLocked()) { KALERT("%s: Firmware update in progress!\n", __FUNCTION__); return -EBUSY; } SfAttLockFirmware(true); if((ret = krtc_get_date_time(&tm)) < 0) { SfAttLockFirmware(false); KALERT("%s: krtc_get_date_time failed!\n", __FUNCTION__); return ret; } SfAttLockFirmware(false); return sprintf(buf, "%04ld-%02d-%02dT%02d:%02d:%02d+00:00\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } static ssize_t uxts64bin_read(struct file *pf, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t len) { int ret; time64_t ts; struct tm tm; if(off != 0) { KALERT("%s: Offset must be 0!\n", __FUNCTION__); return -EINVAL; } if(len < sizeof(ts)) { KALERT("%s: Insufficient buffer size: %zu! At least %zu bytes are required!\n", __FUNCTION__, len, sizeof(time64_t)); return -ENOMEM; } if(SfAttIsFirmwareLocked()) { KALERT("%s: Firmware update in progress!\n", __FUNCTION__); return -EBUSY; } SfAttLockFirmware(true); if((ret = krtc_get_date_time(&tm)) < 0) { SfAttLockFirmware(false); KALERT("%s: krtc_get_date_time failed!\n", __FUNCTION__); return ret; } SfAttLockFirmware(false); ts = mktime64(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); memcpy(buf, &ts, sizeof(ts)); return sizeof(ts); } static ssize_t uxts64bin_write(struct file *pf, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t len) { int ret; time64_t ts; struct tm tm; if(off != 0 || len != sizeof(time64_t)) { KALERT("%s: Offset must be 0 and length must be %zu byte!\n", __FUNCTION__, sizeof(time64_t)); return -EINVAL; } memcpy(&ts, buf, sizeof(ts)); if((ts < KRTC_TIMESTAMP_2000_01_01) || (ts >= KRTC_TIMESTAMP_2100_01_01)) { KALERT("%s: Date/Time must be >= 2000-01-01 00:00:00 and < 2100-01-01 00:00:00!\n", __FUNCTION__); return -EINVAL; } time64_to_tm(ts, 0, &tm); if(SfAttIsFirmwareLocked()) { KALERT("%s: Firmware update in progress!\n", __FUNCTION__); return -EBUSY; } SfAttLockFirmware(true); if((ret = krtc_set_date_time(&tm)) < 0) { SfAttLockFirmware(false); KALERT("%s: krtc_set_date_time failed!\n", __FUNCTION__); return ret; } SfAttLockFirmware(false); return len; } ///////////////////////////////////////////////////////////////////////////// static ssize_t ctrl_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "SysToRtc > 1\n" \ "RtcToSys > 2\n" \ "TestI2C > 3\n"); } static ssize_t ctrl_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { int ret; time64_t ts; struct tm tm; struct timespec64 tp; if(SfAttIsFirmwareLocked()) { KALERT("%s: Firmware update in progress!\n", __FUNCTION__); return -EBUSY; } if(count == 2) { if(!isspace(buf[1]) && (buf[1] != 0)) { KALERT("%s: Invalid input: \"%s\"!\n", __FUNCTION__, buf); return -EINVAL; } } else if(count != 1) { KALERT("%s: Invalid input: \"%s\"!\n", __FUNCTION__, buf); return -EINVAL; } switch(*buf) { case 1: case '1': // KALERT("%s: Set System time to RTC\n", __FUNCTION__); SfAttLockFirmware(true); ts = ktime_get_real_seconds(); if((ts < KRTC_TIMESTAMP_2000_01_01) || (ts >= KRTC_TIMESTAMP_2100_01_01)) { SfAttLockFirmware(false); KALERT("%s: Date/Time must be >= 2000-01-01 00:00:00 and < 2100-01-01 00:00:00!\n", __FUNCTION__); return -EINVAL; } time64_to_tm(ts, 0, &tm); if((ret = krtc_set_date_time(&tm)) < 0) { SfAttLockFirmware(false); KALERT("%s: krtc_get_date_time failed!\n", __FUNCTION__); return ret; } SfAttLockFirmware(false); break; case 2: case '2': // KALERT("%s: Set RTC to System time\n", __FUNCTION__); SfAttLockFirmware(true); if((ret = krtc_get_date_time(&tm)) < 0) { SfAttLockFirmware(false); KALERT("%s: krtc_get_date_time failed!\n", __FUNCTION__); return ret; } ts = mktime64(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); tp.tv_sec = ts; tp.tv_nsec = 0; do_settimeofday64(&tp); SfAttLockFirmware(false); break; case 3: case '3': SfAttLockFirmware(true); if((ret = krtc_test_i2c())) { SfAttLockFirmware(false); KALERT("%s: I2C-Test error: %d!\n", __FUNCTION__, ret); if(ret == -ENOTSUPP) ret = -48; // ENOTSUP in userland return ret; } else KALERT("%s: I2C-Test success!\n", __FUNCTION__); SfAttLockFirmware(false); break; default: KALERT("%s: Invalid input: \"%c\"!\n", __FUNCTION__, *buf); return -EINVAL; } return count; } ///////////////////////////////////////////////////////////////////////////// static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { const char *pszType; RTCTypes type = krtc_get_type(); switch(type) { case RTCT_MCP7940: pszType = "MCP7940"; break; case RTCT_DS3231: pszType = "DS3231"; break; default: pszType = "Unknown"; break; } return sprintf(buf, "%s\n", pszType); } ///////////////////////////////////////////////////////////////////////////// bool SfAttIsFirmwareLocked(void) { return !!atomic_read(&g_flgFwLocked); } ///////////////////////////////////////////////////////////////////////////// void SfAttLockFirmware(bool bLock) { atomic_set(&g_flgFwLocked, bLock ? 1 : 0); } ///////////////////////////////////////////////////////////////////////////// unsigned int SfAttGetBacklightDutyCyclePercent(void) { return (unsigned int)atomic_read(&g_valBacklightDutyCyclePercent); } ///////////////////////////////////////////////////////////////////////////// void SfAttSetBacklightDutyCyclePercent(int val) { if(val < _BACKLIGHT_DUTY_CYCLE_PERC_MIN) val = _BACKLIGHT_DUTY_CYCLE_PERC_MIN; else if(val > _BACKLIGHT_DUTY_CYCLE_PERC_MAX) val = _BACKLIGHT_DUTY_CYCLE_PERC_MAX; atomic_set(&g_valBacklightDutyCyclePercent, val); } ///////////////////////////////////////////////////////////////////////////// unsigned int SfAttGetBacklightPeriod(void) { return (unsigned int)atomic_read(&g_valBacklightPeriod); } ///////////////////////////////////////////////////////////////////////////// void SfAttSetBacklightPeriod(int val) { if(val < _BACKLIGHT_PERIOD_MIN) val = _BACKLIGHT_PERIOD_MIN; else if(val > _BACKLIGHT_PERIOD_MAX) val = _BACKLIGHT_PERIOD_MAX; atomic_set(&g_valBacklightPeriod, val); } ///////////////////////////////////////////////////////////////////////////// bool SfAttBacklightChanged(void) { bool ret = !!atomic_read(&g_flgBacklightChanged); if(ret) atomic_set(&g_flgBacklightChanged, 0); return ret; } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // tiva generic struct kobj_attribute g_tivaDevIdAtt = __ATTR_RO(did); struct kobj_attribute g_tivaUptimeAtt = __ATTR_RO(uptime); ///////////////////////////////////////////////////////////////////////////// // backlight struct kobj_attribute g_tivaDutyCycleAtt = __ATTR_WO(dutycycle); struct kobj_attribute g_tivaPeriodAtt = __ATTR_WO(period); ///////////////////////////////////////////////////////////////////////////// // ADC struct kobj_attribute g_tivaUVersAtt = __ATTR_RO(UVers); struct kobj_attribute g_tivaUBatV3Att = __ATTR_RO(UBatV3); 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)); ///////////////////////////////////////////////////////////////////////////// // tiva firmware struct kobj_attribute g_tivaVersionAtt = __ATTR_RO(version); struct bin_attribute g_tivaFwImageAtt = __BIN_ATTR_WO(image, 0); ///////////////////////////////////////////////////////////////////////////// // tiva memory struct bin_attribute g_tivaMemory = __BIN_ATTR_RW(mem, 0); struct kobj_attribute g_tivaMemMap = __ATTR_RO(map); ///////////////////////////////////////////////////////////////////////////// // tiva RTC struct kobj_attribute g_tivaRtcIso8601 = __ATTR_RO(iso8601); struct bin_attribute g_tivaRtcUnTsBin64 = __BIN_ATTR_RW(uxts64bin, sizeof(time64_t)); struct kobj_attribute g_tivaRtcCtrl = __ATTR_RW(ctrl); struct kobj_attribute g_tivaRtcType = __ATTR_RO(type);