Commit 515823ea authored by Andrey Filippov's avatar Andrey Filippov

adding memory-only logger

parent dbe9d70b
......@@ -4579,7 +4579,7 @@ static void si5338_init_of(struct i2c_client *client)
return;
}
init_type=1;
/* falling to initialization */
// no break : falling to initialization */
case 1:
pre_init(client,1); // clear outputs and muxes - they will be programmed later
break;
......
......@@ -33,4 +33,5 @@ obj-$(CONFIG_ELPHEL393) += imu_log393.o
obj-$(CONFIG_ELPHEL393) += cxi2c.o
obj-$(CONFIG_ELPHEL393) += x393_videomem.o
obj-$(CONFIG_ELPHEL393) += detect_sensors.o
obj-$(CONFIG_ELPHEL393) += x393_fpga_functions.o
\ No newline at end of file
obj-$(CONFIG_ELPHEL393) += x393_fpga_functions.o
obj-$(CONFIG_ELPHEL393) += klogger_393.o
\ No newline at end of file
......@@ -66,15 +66,19 @@
#include "x393_macro.h"
#include "x393.h"
#include "sensor_i2c.h" // read_xi2c_frame()
#include "klogger_393.h"
/**
* \def MDF1(x) optional debug output
*/
#undef LOCK_BH_PROCESSPARS
#undef LOCK_BH_FRAMEPARS
//#undef LOCK_BH_FRAMEPARS
#define LOCK_BH_FRAMEPARS
#define USE_KLOG393
#ifdef LOCK_BH_FRAMEPARS
......@@ -332,7 +336,8 @@ void initFramePars(int sensor_port)
initMultiPars(sensor_port); // initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
frameParsInitialized[sensor_port] = 1;
UNLOCK_IBH(framepars_locks[sensor_port]);
dev_dbg(g_devfp_ptr,"%s port %d: DONE, frameParsInitialized[%d]=%ld\n",__func__, sensor_port, sensor_port, frameParsInitialized[sensor_port]);
dev_dbg(g_devfp_ptr,"%s port %d: DONE, frameParsInitialized[%d]=%d\n",
__func__, sensor_port, sensor_port, frameParsInitialized[sensor_port]);
}
/**
......@@ -806,35 +811,75 @@ inline void _processParsSeq(int sensor_port, ///< sensor port
//#define P_CALLASAP 107 // bitmask - what functions work only in the current frame (ASAP) mode
void _processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
{
#ifdef USE_KLOG393
char klog393_str [256];
#endif
frame16 &= PARS_FRAMES_MASK;
if (debug_flags)
if (debug_flags) {
dev_dbg(g_devfp_ptr,"port= %d, frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
#ifdef USE_KLOG393
sprintf(klog393_str,
"%s:%d:%s: "
"port= %d, frame16=%d, maxahead=%d\n",
__FILE__, __LINE__, __FUNCTION__,
sensor_port, frame16, maxahead);
klog393_ts(klog393_str);
#endif
}
dev_dbg(g_devfp_ptr,"port= %d, frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
if (!sensorproc){
dev_err(g_devfp_ptr,"port=%d frame16=%d sensorproc==NULL !!!! \n", sensor_port, frame16);
return;
}
// int spin_trylock(spinlock_t *lock);
// first - do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
// dev_dbg(g_devfp_ptr,"%s before first _processParsASAP\n",__func__);
// int spin_trylock(spinlock_t *lock);
// first - do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
// dev_dbg(g_devfp_ptr,"%s before first _processParsASAP\n",__func__);
_processParsASAP(sensor_port, sensorproc, frame16); // NC393: never gets here ? Only after _processParsSeq?
if (debug_flags)
if (debug_flags) {
#ifdef USE_KLOG393
sprintf(klog393_str,
"%s:%d:%s: "
"port= %d (after first _processParsASAP), frame16=%d, maxahead=%d\n",
__FILE__, __LINE__, __FUNCTION__,
sensor_port, frame16, maxahead);
klog393_ts(klog393_str);
#endif
dev_dbg(g_devfp_ptr,"port= %d (after first _processParsASAP), frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
}
dev_dbg(g_devfp_ptr,"port= %d (after first _processParsASAP), frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
// now - the rest commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
// for jobahead =0 it is still possible to have some functions in ASAP mode with non-zero latency
// dev_dbg(g_devfp_ptr,"%s before _processParsSeq\n",__func__);
// now - the rest commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
// for jobahead =0 it is still possible to have some functions in ASAP mode with non-zero latency
// dev_dbg(g_devfp_ptr,"%s before _processParsSeq\n",__func__);
_processParsSeq(sensor_port, sensorproc, frame16, maxahead);
if (debug_flags)
if (debug_flags) {
#ifdef USE_KLOG393
sprintf(klog393_str,
"%s:%d:%s: "
"port= %d (after _processParsSeq), frame16=%d, maxahead=%d\n",
__FILE__, __LINE__, __FUNCTION__,
sensor_port, frame16, maxahead);
klog393_ts(klog393_str);
#endif
dev_dbg(g_devfp_ptr,"port= %d (after _processParsSeq), frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
}
dev_dbg(g_devfp_ptr,"port= %d (after _processParsSeq), frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
// re-test ASAP tasks - they might appear as a result of other commands executed
// dev_dbg(g_devfp_ptr,"%s before second _processParsASAP\n",__func__);
// re-test ASAP tasks - they might appear as a result of other commands executed
// dev_dbg(g_devfp_ptr,"%s before second _processParsASAP\n",__func__);
_processParsASAP(sensor_port, sensorproc, frame16);
if (debug_flags)
if (debug_flags) {
#ifdef USE_KLOG393
sprintf(klog393_str,
"%s:%d:%s: "
"port= %d (after second _processParsASAP), frame16=%d, maxahead=%d\n",
__FILE__, __LINE__, __FUNCTION__,
sensor_port, frame16, maxahead);
klog393_ts(klog393_str);
#endif
dev_dbg(g_devfp_ptr,"port= %d (after second _processParsASAP), frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
}
dev_dbg(g_devfp_ptr,"port= %d (after second _processParsASAP), frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
if (debug_flags) debug_flags--;
......@@ -870,8 +915,23 @@ void processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16,
#else
void processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
{
#ifdef USE_KLOG393
char klog393_str [256];
#endif
FLAGS_IBH
frame16 &= PARS_FRAMES_MASK;
if (debug_flags) {
#ifdef USE_KLOG393
sprintf(klog393_str,
"%s:%d:%s: "
"==from tasklet: port= %d, frame16=%d, maxahead=%d\n",
__FILE__, __LINE__, __FUNCTION__,
sensor_port, frame16, maxahead);
klog393_ts(klog393_str);
#endif
dev_dbg(g_devfp_ptr,"==from tasklet: port= %d, frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
}
dev_dbg(g_devfp_ptr,"port= %d, frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
if (!sensorproc){
dev_err(g_devfp_ptr,"%s port=%d frame16=%d sensorproc==NULL !!!! \n", __func__, sensor_port, frame16);
......@@ -880,6 +940,17 @@ void processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16,
LOCK_IBH(framepars_locks[sensor_port]);
_processPars(sensor_port, sensorproc, frame16, maxahead);
UNLOCK_IBH(framepars_locks[sensor_port]);
if (debug_flags) {
#ifdef USE_KLOG393
sprintf(klog393_str,
"%s:%d:%s: "
"==Done from tasklet: port= %d, frame16=%d, maxahead=%d\n",
__FILE__, __LINE__, __FUNCTION__,
sensor_port, frame16, maxahead);
klog393_ts(klog393_str);
#endif
dev_dbg(g_devfp_ptr,"== Done from tasklet: port= %d, frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
}
}
#endif
......@@ -961,8 +1032,19 @@ int setFrameParsAtomic(int sensor_port, ///< sensor port number (0
struct framepars_t *framepars = aframepars[sensor_port];
unsigned long *funcs2call =afuncs2call[sensor_port];
int findex_this, findex_prev, findex_future, frame16;
dev_dbg(g_devfp_ptr,"port= %d, frameno=0x%lx, findex_this=%ld (0x%lx) maxLatency=%d, numPars=%d, frameParsInitialized[%d]=%d\n",
#ifdef USE_KLOG393
char klog393_str [256];
sprintf(klog393_str,
"%s:%d:%s: "
"frameno=0x%lx, findex_this=%ld (0x%lx) maxLatency=%d, numPars=%d, frameParsInitialized[%d]=%d\n",
__FILE__, __LINE__, __FUNCTION__,
sensor_port, frameno, findex_this, thisFrameNumber(sensor_port), maxLatency, numPars, sensor_port, frameParsInitialized[sensor_port]);
klog393_ts(klog393_str);
#endif
dev_dbg(g_devfp_ptr,"port= %d, frameno=0x%lx, findex_this=%d (0x%lx) maxLatency=%d, numPars=%d, frameParsInitialized[%d]=%d\n",
sensor_port, frameno, findex_this, thisFrameNumber(sensor_port), maxLatency, numPars, sensor_port, frameParsInitialized[sensor_port]);
//int klog393_ts(const char * str);
if (!frameParsInitialized[sensor_port]) {
initSequencers(sensor_port); // Will call initFramePars(); and initialize functions
}
......@@ -1056,13 +1138,30 @@ int setFrameParsAtomic(int sensor_port, ///< sensor port number (0
// Try to process parameters immediately after written. If 0, only non-ASAP will be processed to prevent
// effects of uncertainty of when was it called relative to frame sync
// Changed to all (don't care about uncertainty - they will trigger only if it is too late or during sensor detection/initialization)
debug_flags = 5; // enable debug print several times
debug_flags = 20; // enable debug print several times
if (!(get_globalParam(sensor_port, G_TASKLET_CTL) & (1 << TASKLET_CTL_NOSAME))) {
// _processParsSeq (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
dev_dbg(g_devfp_ptr,"G_TASKLET_CTL -> 0x%x (port = %d )\n", (int) get_globalParam(sensor_port, G_TASKLET_CTL),sensor_port);
// processPars(sensor_port, &asensorproc[sensor_port], thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
// Already having lock, call inner function. When called from tasklet, it will have to acquire lock
#ifdef USE_KLOG393
sprintf(klog393_str,
"%s:%d:%s: "
"G_TASKLET_CTL -> 0x%x (port = %d )\n",
__FILE__, __LINE__, __FUNCTION__,
(int) get_globalParam(sensor_port, G_TASKLET_CTL),sensor_port);
klog393_ts(klog393_str);
#endif
_processPars(sensor_port, &asensorproc[sensor_port], thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
#ifdef USE_KLOG393
sprintf(klog393_str,
"%s:%d:%s: "
"kthread _processPars(%d, .., 0x%x) DONE\n",
__FILE__, __LINE__, __FUNCTION__,
sensor_port, thisFrameNumber(sensor_port));
klog393_ts(klog393_str);
#endif
dev_dbg(g_devfp_ptr,"kthread _processPars(%d, .., 0x%x) DONE\n",sensor_port, thisFrameNumber(sensor_port));
} else {
dev_dbg(g_devfp_ptr,"kthread: NOT calling _processPars(%d, .., 0x%lx) DONE\n",sensor_port, thisFrameNumber(sensor_port));
......
/**
* @file klogger_393.c
* @brief Record strings with timestamps (using FPGA time) to a memory buffer (no I/O),
* Read the buffer as character device
* @copyright Copyright (C) 2016 Elphel, Inc.
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/platform_device.h> // For sysfs
#include <linux/fs.h>
#include <asm/uaccess.h> // copy_*_user
#include <linux/of.h> // Device Tree
#include <uapi/elphel/c313a.h> // PARS_FRAMES_MASK
#include <uapi/elphel/x393_devices.h> // For sysfs
#include "x393.h"
#include "x393_fpga_functions.h"
#include "klogger_393.h"
#define KLOGGER_BUFFER_ANY_SIZE 1 // any buffer size, use multiple subtractions to convert file pointer to buffer pointer
//#define DEV393_KLOGGER ("klogger_393", "klogger_393", 144, 1, "0666", "c") ///< kernel event logger to memory (no i/o)
static struct device *g_dev_ptr=NULL; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions
static u32 buffer_size = 0;
#ifndef KLOGGER_BUFFER_ANY_SIZE
static u32 buffer_size_order = 0;
#endif
static u32 buffer_wp = 0;
static loff_t file_size = 0; // write pointer, 64 bits
static char * klog393_buf = NULL;
const char klogger393_of_prop_name[] = "klogger-393,buffer_size";
const static u32 max_string_len = PAGE_SIZE; ///< maximal string length
int klogger393_open(struct inode *inode, struct file *filp);
int klogger393_release(struct inode *inode, struct file *filp);
loff_t klogger393_llseek(struct file * file, loff_t offset, int orig);
ssize_t klogger393_read (struct file * file, char * buf, size_t count, loff_t *off);
/** Put string into the logger buffer*/
int klog393_puts(const char * str) ///< String to log, limited by max_string_len (currently 4096 bytes)
///< @return 0 - OK, -EMSGSIZE - string too long
{
int sl = strlen(str);
u32 new_wp= buffer_wp+sl;
// u32 pl;
if (sl > max_string_len){
dev_err(g_dev_ptr,"%s: String too long (%d >%d)\n",
__func__,strlen(str), max_string_len );
return -EMSGSIZE;
}
// See if the string fits in the buffer
if (likely(new_wp < buffer_size)){
memcpy(klog393_buf+buffer_wp, str,sl);
buffer_wp = new_wp;
} else {
memcpy(klog393_buf+buffer_wp, str, buffer_size - buffer_wp);
memcpy(klog393_buf, str, sl - (buffer_size - buffer_wp));
buffer_wp = new_wp - buffer_size;
}
file_size += sl;
return 0;
}
/** Put string into the logger buffer, preceded by a timestamp "<sec>.<usec>: "*/
int klog393_ts(const char * str) ///< String to log, limited by max_string_len (currently 4096 bytes)
///< @return 0 - OK, -EMSGSIZE - string too long
{
sec_usec_t ts;
char buf[20]; // 18 enough
get_fpga_rtc(&ts);
sprintf(buf,"%ld.%06ld: ",ts.sec,ts.usec);
klog393_puts(buf);
return klog393_puts(str);
}
static struct file_operations framepars_fops = {
owner: THIS_MODULE,
open: klogger393_open,
llseek: klogger393_llseek,
read: klogger393_read,
release: klogger393_release
};
/** Driver OPEN method */
int klogger393_open(struct inode *inode, ///< inode pointer
struct file *filp) ///< file pointer
///< @return OK - 0, -EINVAL for wrong minor
{
int minor= MINOR(inode->i_rdev);
filp->private_data = (int *) minor; // store just minor there
dev_dbg(g_dev_ptr,"minor=0x%x\n", minor);
switch (minor) {
case DEV393_MINOR(DEV393_KLOGGER):
inode->i_size = file_size; //or return 8 - number of frame pages?
return 0;
default:
return -EINVAL;
}
}
/** Driver RELEASE method */
int klogger393_release(struct inode *inode, ///< inode pointer
struct file *filp) ///< file pointer
///< @return OK - 0, -EINVAL for wrong minor
{
int minor= MINOR(inode->i_rdev);
switch ( minor ) {
case DEV393_MINOR(DEV393_KLOGGER):
dev_dbg(g_dev_ptr,"Release DONE, minor=0x%x\n", minor);
break;
default: return -EINVAL;
}
return 0;
}
/** Driver LLSEEK method */
loff_t klogger393_llseek(struct file * file, ///< file structure pointer
loff_t offset, ///< 64-bit offset
int orig) ///< Offset origin (SEEK_SET==0, SEEK_CUR==1, SEEK_END==2 - see fs.h)
///< @return new file position or negative error
{
int minor=(int)file->private_data;
dev_dbg(g_dev_ptr,"file=%x, offset=%llx (%d), orig=%x\r\n", (int) file, offset,(int) offset, (int) orig);
switch (minor) {
case DEV393_MINOR(DEV393_KLOGGER):
switch (orig) {
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
file->f_pos += offset;
break;
case SEEK_END:
//!overload later?
if (offset<=0) {
file->f_pos = file_size + offset;
} else {
file->f_pos = file_size + offset; // Overload if needed as usual
}
break;
default:
dev_err(g_dev_ptr,"lseek: invalid orig=%d\n", orig);
return -EINVAL;
}
break;
default:
dev_err(g_dev_ptr,"lseek: invalid minor=%d\n", minor);
return -EINVAL;
}
/** truncate position */
if (file->f_pos < 0) {
dev_err(g_dev_ptr,"negative position: minor=%d, file->f_pos=0x%llx\n", minor, file->f_pos);
file->f_pos = 0;
return (-EOVERFLOW);
}
// No sense to output overwritten data in the buffer
if (file->f_pos < (file_size - buffer_size))
file->f_pos = (file_size - buffer_size);
// enable seeking beyond buffer - it now is absolute position in the data stream
if (file->f_pos > file_size) {
file->f_pos = file_size;
return (-EOVERFLOW);
}
return (file->f_pos);
}
ssize_t klogger393_read (struct file * file, ///< file structure pointer
char * buf, ///< user buffer to get data
size_t count, ///< number of bytes to read
loff_t *off) ///< start/current position to read from
///< @return number of bytes placed in the buffer
{
int minor=(int)file->private_data;
off_t buffer_rp;
u32 len;
u32 not_copied;
switch (minor) {
case DEV393_MINOR(DEV393_KLOGGER):
// Increase *off if it points to already overwritten data
if (*off < (file_size - buffer_size)) {
*off = (file_size - buffer_size);
// Keep count the same?
}
// Truncate count if it exceeds remaining size in buffer
if (count > (file_size - *off))
count = file_size - *off;
#ifdef KLOGGER_BUFFER_ANY_SIZE
for (buffer_rp = *off; buffer_rp >= buffer_size; buffer_rp -= buffer_size);
#else
buffer_rp = *offt & buffer_size - 1; // buffer_size should be power of 2
#endif
len = count;
// first (usually the only) buffer copy
if (len > (buffer_size - buffer_rp))
len = (buffer_size - buffer_rp);
not_copied=copy_to_user(buf, klog393_buf + buffer_rp, len); // returns number of bytes not copied
if (not_copied) {
dev_err(g_dev_ptr,"1. tried to copy 0x%x bytes to offset 0x%llx, not copied =0x%x bytes\n", count, *off,not_copied);
return -EFAULT;
}
if (len < count) { // wrapping around the buffer
not_copied=copy_to_user(buf+len, klog393_buf, count - len); // returns number of bytes not copied
if (not_copied) {
dev_err(g_dev_ptr,"2. tried to copy 0x%x bytes to offset 0x%llx, not copied =0x%x bytes\n", count, *off,not_copied);
return -EFAULT;
}
}
*off += count;
// should we update file->f_pos=*off here too?)
return count;
break;
default:
dev_err(g_dev_ptr," Wrong minor=0x%x\n",minor);
return -EINVAL;
}
}
int klogger_393_probe(struct platform_device *pdev)
{
int res;
struct device *dev = &pdev->dev;
const char * config_string;
struct device_node *node = pdev->dev.of_node;
g_dev_ptr = dev;
buffer_wp = 0;
if (node) {
if (of_property_read_string(node, klogger393_of_prop_name, &config_string)) {
dev_err(dev,"%s: Device tree has entry for "DEV393_NAME(DEV393_KLOGGER)", but no '%s' property is provided\n",
__func__,klogger393_of_prop_name);
return -EINVAL;
}
if (!sscanf(config_string,"%i", &buffer_size)){
dev_err(dev,"%s: Invalid buffer size for "DEV393_NAME(DEV393_KLOGGER)".%s - %s\n",
__func__,klogger393_of_prop_name,config_string);
return -EINVAL;
}
//__builtin_clz
#ifndef KLOGGER_BUFFER_ANY_SIZE
buffer_size_order = 31 - __builtin_clz(buffer_size);
if (buffer_size & (( 1 << buffer_size_order) -1)){
buffer_size_order++;
buffer_size = 1 << buffer_size_order;
dev_warn(dev,"%s: Increased buffer size to %d (0x%x) to make it a power of 2 bytes\n",
__func__,buffer_size,buffer_size);
}
#endif
klog393_buf = devm_kzalloc(dev, buffer_size, GFP_KERNEL);
if (!klog393_buf){
buffer_size = 0;
dev_err(dev,"%s: Failed to create buffer for "DEV393_NAME(DEV393_KLOGGER)" of %d(0x%x) bytes\n",
__func__,buffer_size,buffer_size);
return -ENOMEM;
}
res = register_chrdev(DEV393_MAJOR(DEV393_FRAMEPARS0), DEV393_NAME(DEV393_FRAMEPARS0), &framepars_fops);
if (res < 0) {
dev_err(dev, "framepars_init: couldn't get a major number %d (DEV393_MAJOR(DEV393_FRAMEPARS0)).\n",
DEV393_MAJOR(DEV393_FRAMEPARS0));
return res;
}
} else {
dev_warn(dev,"%s: No entry for "DEV393_NAME(DEV393_KLOGGER)", in Device Tree, logger is disabled\n", __func__);
}
// klogger_393_sysfs_register(pdev);
// dev_info(dev, DEV393_NAME(DEV393_KLOGGER)": registered sysfs\n");
return 0;
}
int klogger_393_remove(struct platform_device *pdev)
{
if (klog393_buf)
devm_kfree(&pdev->dev, klog393_buf);
unregister_chrdev(DEV393_MAJOR(DEV393_KLOGGER), DEV393_NAME(DEV393_KLOGGER));
return 0;
}
static const struct of_device_id klogger_393_of_match[] = {
{ .compatible = "elphel,klogger-393-1.00" },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, klogger_393_of_match);
static struct platform_driver klogger_393 = {
.probe =klogger_393_probe,
.remove =klogger_393_remove,
.driver = {
.name = DEV393_NAME(DEV393_KLOGGER),
.of_match_table = klogger_393_of_match,
},
};
module_platform_driver(klogger_393);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION("Record/playback strings with FPGA timestams");
/**
* @file klogger_393.c
* @brief Header file for klogger_393.c
* @copyright Copyright (C) 2016 Elphel, Inc.
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KLOGGER_393_H
#define KLOGGER_393_H
int klog393_puts(const char * str);
int klog393_ts(const char * str);
#endif
......@@ -2197,7 +2197,7 @@ int mt9x001_init(struct platform_device *pdev)
{
int res;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
// const struct of_device_id *match;
int sensor_port;
for (sensor_port = 0; sensor_port < SENSOR_PORTS; sensor_port++) {
......
......@@ -9,7 +9,7 @@
* - tasklets
* - device driver that includes waiting for the next frame regardless of compression
* @copyright Copyright (C) 2016 Elphel, Inc.
*
* @par <b>License</b>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
......
......@@ -59,7 +59,7 @@ struct x393_i2c_device_list {
x393_i2c_device_t i2c_dev;
struct list_head list;
};
const char of_prop_name[] = "elphel393-sensor-i2c,i2c_devices";
const char sensor_i2c_of_prop_name[] = "elphel393-sensor-i2c,i2c_devices";
const char group_name[] = "i2c_classes";
const int max_buf_len = 4096-256; ///< stop output when only 256 bytes are left in the caller's buffer
const int max_i2c_classes = 256;
......@@ -190,7 +190,7 @@ int i2c_page_alloc(int chn)
#else
spin_unlock_irqrestore(sensori2c_locks[chn],flags);
#endif
dev_dbg(sdev, "Allocated page= %d for port %d, is RESET(chn=%d, group= 0x%08x bits = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x )\n",
dev_dbg(sdev, "Allocated page= %d for port %d, is RESET(group= 0x%08x bits = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x )\n",
(g << 5) + b, chn,free_i2c_groups[chn],
free_i2c_pages[chn][0],free_i2c_pages[chn][1],free_i2c_pages[chn][2],free_i2c_pages[chn][3],
free_i2c_pages[chn][4],free_i2c_pages[chn][5],free_i2c_pages[chn][6],free_i2c_pages[chn][7]);
......@@ -1592,9 +1592,9 @@ static void elphel393_sensor_i2c_init_of(struct platform_device *pdev) ///< Plat
struct device *dev =&pdev->dev;
if (node) {
/*TODO: Configure some i2c devices here (slaves, formats, speeds) to be used by names*/
num_devs = of_property_count_strings(node,of_prop_name);
num_devs = of_property_count_strings(node,sensor_i2c_of_prop_name);
for (nd=0; nd <num_devs; nd++){
if (of_property_read_string_index(node, of_prop_name, nd, &config_string)) {
if (of_property_read_string_index(node, sensor_i2c_of_prop_name, nd, &config_string)) {
pr_err("%s: No data for selected i2c device\n", __func__);
BUG();
}
......
......@@ -48,6 +48,11 @@ sec_usec_t * get_fpga_rtc(sec_usec_t * ts) ///< Pointer to a sec/usec structure
// x393_rtc_sec_t sec;
int i;
if (!ts) return NULL;
if (!is_fpga_programmed()) {
ts->sec = 0;
ts->usec = 0;
return ts;
}
spin_lock_bh(&fpga_time_lock);
stat = x393_rtc_status();
stat_ctrl.mode = 1;
......@@ -72,11 +77,14 @@ void set_fpga_rtc (sec_usec_t ts) ///< timestamp providing seconds and microseco
x393_rtc_sec_t sec;
usec.usec = ts.usec;
sec.sec = ts.sec;
if (!is_fpga_programmed())
return;
spin_lock_bh(&fpga_time_lock);
set_x393_rtc_usec(usec);
set_x393_rtc_sec_set(sec); // And apply
spin_unlock_bh(&fpga_time_lock);
}
/** Check if bitstream is loaded */
int is_fpga_programmed(void) ///< @return 0 - bitstream is NOT loaded, 1 - bitsteam IS loaded, -ENOMEM - error in ioremap
{
......
......@@ -91,6 +91,7 @@
#define DEV393_DETECT_SENSORS ("detect_sensors", "detect_sensors",143, 1, "0666", "c") ///< Probably not needed, only sysfs is used
#define DEV393_I2C_SENSORS ("", "elphel393-sensor-i2c",-1, -1, "0666", "c") ///< Used only in sysfs, no character device (yet?)
#define DEV393_MT9X001 ("", "elphel393-mt9x001", -1, -1, "0666", "c") ///< Used only in sysfs, no character device (yet?)
#define DEV393_KLOGGER ("klogger_393", "klogger_393", 144, 1, "0666", "c") ///< kernel event logger to memory (no i/o)
#define _DEV393_PATH(n, ...) "/dev/"n
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment