framepars.c 111 KB
Newer Older
1 2
/** @file framepars.c
 * @brief Handling of frame parameters, making use of FPGA i2c
3
 * and command sequencer that accepts commands up to 14 frames ahead.
Andrey Filippov's avatar
Andrey Filippov committed
4
 *
5 6
 * This module includes parameter storage, code called from ISR,
 * from other kernel drivers as well as from the user space
Andrey Filippov's avatar
Andrey Filippov committed
7
 * @copyright Copyright (C) 2016 Elphel, Inc.
8 9 10 11 12 13 14 15 16 17 18 19
 *
 *  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/>.
20
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
21 22 23

//copied from cxi2c.c - TODO:remove unneeded

24
//#define DEBUG // should be before linux/module.h - enables dev_dbg at boot in this file (needs "debug" in bootarg)
25 26
#include <linux/types.h>        // div for 64
#include <asm/div64.h>          // div for 64
Mikhail Karpenko's avatar
Mikhail Karpenko committed
27 28 29 30 31

#include <linux/module.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/slab.h>
32
//#include <linux/errno.h>
Mikhail Karpenko's avatar
Mikhail Karpenko committed
33 34 35 36 37 38
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/init.h>
//#include <linux/autoconf.h>
#include <linux/vmalloc.h>
39
#include <linux/platform_device.h>
Andrey Filippov's avatar
Andrey Filippov committed
40
#include <linux/spinlock.h>
Andrey Filippov's avatar
Andrey Filippov committed
41
#include <linux/delay.h>
Mikhail Karpenko's avatar
Mikhail Karpenko committed
42 43

//#include <asm/system.h>
44 45
//#include <asm/byteorder.h> // endians
//#include <asm/io.h>
Mikhail Karpenko's avatar
Mikhail Karpenko committed
46

47
//#include <asm/irq.h>
Mikhail Karpenko's avatar
Mikhail Karpenko committed
48

49
//#include <asm/delay.h>
Mikhail Karpenko's avatar
Mikhail Karpenko committed
50
#include <asm/uaccess.h>
51 52
#include <uapi/elphel/c313a.h>
#include <uapi/elphel/exifa.h>
53 54
#include <uapi/elphel/x393_devices.h>

Mikhail Karpenko's avatar
Mikhail Karpenko committed
55 56 57 58
//#include "fpgactrl.h"  // defines port_csp0_adsensor_common.hdr, port_csp4_addr
//#include "cc3x3.h"
//#include "x3x3.h"           // hardware definitions

59
#include "x393_fpga_functions.h"
Mikhail Karpenko's avatar
Mikhail Karpenko committed
60 61 62
#include "sensor_common.h"
#include "framepars.h"
#include "param_depend.h" // specifies what functions should be called for different parameters changed
63
// needed for lseek commands
Mikhail Karpenko's avatar
Mikhail Karpenko committed
64 65
//#include "cxdma.h" // x313_dma_init
//#include "cci2c.h" // to use void i2c_reset_wait(void), reset shadow static 'i2c_hardware_on'
66
#include "x393_macro.h"
67
#include "x393.h"
Andrey Filippov's avatar
Andrey Filippov committed
68
#include "sensor_i2c.h" // read_xi2c_frame()
69 70
#include "klogger_393.h"

Mikhail Karpenko's avatar
Mikhail Karpenko committed
71
/**
72
 * \def MDF1(x) optional debug output
Mikhail Karpenko's avatar
Mikhail Karpenko committed
73 74
 */

75 76
#undef LOCK_BH_PROCESSPARS

77
//#undef LOCK_BH_FRAMEPARS
78 79
#define LOCK_BH_FRAMEPARS

80
//#define USE_KLOG393
81

82 83 84 85 86 87 88 89 90 91 92 93 94


#ifdef LOCK_BH_FRAMEPARS
    #define FLAGS_IBH
    #define LOCK_IBH(x)   spin_lock_bh(x)
    #define UNLOCK_IBH(x) spin_unlock_bh(x)
#else
    #define FLAGS_IBH     unsigned long flags;
    #define LOCK_IBH(x)   spin_lock_irqsave(x,flags)
    #define UNLOCK_IBH(x) spin_unlock_irqrestore(x,flags)
#endif


95 96 97 98 99 100 101 102 103
#include "debug393.h"


#define ELPHEL_DEBUG 0



// Below are old NC353 debug macros, remove them

Mikhail Karpenko's avatar
Mikhail Karpenko committed
104
#if ELPHEL_DEBUG
105
// #define MDF2(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 2)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
106
// setFrameParsAtomic
Mikhail Karpenko's avatar
Mikhail Karpenko committed
107 108
 #define MDF5(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 5)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
 #define   D5(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 5)) { x; } }
109
// processPars
Mikhail Karpenko's avatar
Mikhail Karpenko committed
110 111
 #define MDF6(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 6)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
 #define   D6(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 6)) { x; } }
112
//update FramePars
Mikhail Karpenko's avatar
Mikhail Karpenko committed
113 114
 #define MDF7(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 7)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
 #define   D7(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 7)) { x; } }
115
// setFramePar[s]
Mikhail Karpenko's avatar
Mikhail Karpenko committed
116 117
 #define MDF8(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 8)) { printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; } }
 #define   D8(x) { if (GLOBALPARS(0,G_DEBUG) & (1 << 8)) { x; } }
118 119 120 121 122
 #define D5(chn,...)
 #define D6(chn,...)
 #define D7(chn,...)
 #define D8(chn,...)

Mikhail Karpenko's avatar
Mikhail Karpenko committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
 #define ELPHEL_DEBUG_THIS 0
// #define ELPHEL_DEBUG_THIS 1
#else
 #define MDF2(x)
 #define MDF5(x)
 #define D5(x)
 #define MDF6(x)
 #define D6(x)
 #define MDF7(x)
 #define D7(x)
 #define MDF8(x)
 #define D8(x)
 #define ELPHEL_DEBUG_THIS 0
#endif


#if ELPHEL_DEBUG_THIS
140 141
  #define MDD1(x) printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x; udelay(ELPHEL_DEBUG_DELAY)
  #define MDF1(x) printk("%s:%d:%s ", __FILE__, __LINE__, __FUNCTION__); x
Mikhail Karpenko's avatar
Mikhail Karpenko committed
142 143 144 145 146 147 148 149 150 151 152
  #define D1(x) x
  #define D1I(x)

#else
  #define MDD1(x)
  #define MDF1(x)
  #define D1(x)
  #define D1I(x) x
#endif

/**
153
 * driver name to display
Mikhail Karpenko's avatar
Mikhail Karpenko committed
154
 */
155
#define  FRAMEPARS_DRIVER_DESCRIPTION "Elphel (R) Model 393 Frame Parameters device driver"
Mikhail Karpenko's avatar
Mikhail Karpenko committed
156

157 158 159
static int hardware_initialized = 0;


Mikhail Karpenko's avatar
Mikhail Karpenko committed
160 161
/* 393: sFrameParsAll is an array of 4per-port structures */
static struct framepars_all_t sFrameParsAll[SENSOR_PORTS] __attribute__ ((aligned(PAGE_SIZE)));  ///< Sensor Parameters, currently 16 pages all and 2048 pages some, static struct
Andrey Filippov's avatar
Andrey Filippov committed
162
unsigned int frameParsInitialized[SENSOR_PORTS];                                                     // set to 0 at startup, 1 after initialization that is triggered by setParsAtomic()
Andrey Filippov's avatar
Andrey Filippov committed
163 164
#define  thisFrameNumber(p)            GLOBALPARS(p,G_THIS_FRAME)                       // Current frame number (may lag from the hardware)
#define  thisCompressorFrameNumber(p)  GLOBALPARS(p,G_COMPRESSOR_FRAME)                 // Current compressed frame number (lags from thisFrameNumber)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
165 166

#ifdef NC353
167
	struct framepars_all_t  *frameparsall = NULL;           // - will be mmap-ed
Mikhail Karpenko's avatar
Mikhail Karpenko committed
168 169
	struct framepars_t      *framepars =   NULL;            ///< getting rid of static to be able to use extern
	struct framepars_past_t *pastpars =    NULL;            ///< getting rid of static to be able to use extern
170 171 172 173 174
	unsigned long           *funcs2call =  NULL;            //  sFrameParsAll.func2call.pars; - each parameter has a 32-bit mask of what pgm_function to call - other fields not used
	unsigned long           *globalPars =  NULL;            // parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
	unsigned long           *multiSensIndex = NULL;         // index for per-sensor alternatives
	unsigned long           *multiSensRvrsIndex = NULL;     // reverse index (to parent) for the multiSensIndex
wait_queue_head_t framepars_wait_queue;                 // used to wait for the frame to be acquired
Mikhail Karpenko's avatar
Mikhail Karpenko committed
175 176
#endif
/* 393 : Changing to per-port */
177
struct framepars_all_t  *aframeparsall = NULL;              // - will be mmap-ed, in 393 points to an array of structures
Mikhail Karpenko's avatar
Mikhail Karpenko committed
178 179
struct framepars_t      *aframepars[SENSOR_PORTS];          ///< getting rid of static to be able to use extern
struct framepars_past_t *apastpars[SENSOR_PORTS];            ///< getting rid of static to be able to use extern
180 181 182 183 184
unsigned long           *afuncs2call[SENSOR_PORTS];          //  sFrameParsAll.func2call.pars; - each parameter has a 32-bit mask of what pgm_function to call - other fields not used
unsigned long           *aglobalPars[SENSOR_PORTS];          // parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
unsigned long           *amultiSensIndex[SENSOR_PORTS];      // index for per-sensor alternatives
unsigned long           *amultiSensRvrsIndex[SENSOR_PORTS];  // reverse index (to parent) for the multiSensIndex
wait_queue_head_t       aframepars_wait_queue[SENSOR_PORTS];// used to wait for the frame to be acquired
Mikhail Karpenko's avatar
Mikhail Karpenko committed
185

Andrey Filippov's avatar
Andrey Filippov committed
186 187 188 189 190 191 192
static DEFINE_SPINLOCK(framepars_lock_0); ///<
static DEFINE_SPINLOCK(framepars_lock_1); ///<
static DEFINE_SPINLOCK(framepars_lock_2); ///<
static DEFINE_SPINLOCK(framepars_lock_3); ///<
/** Define array of pointers to locks - hardware allows concurrent writes to different ports tables */
spinlock_t * framepars_locks[4] = {&framepars_lock_0, &framepars_lock_1, &framepars_lock_2, &framepars_lock_3};

193 194 195 196 197 198 199 200 201
static struct common_pars_t scommon_pars = {
        .master_chn =       0,
        .sensors=           {0,0,0,0}, // maybe not needed (it is whom to notify of
        .updated =          {0,0,0,0}, // set by master, cleared by other channels
        .trig_period =      0,
        .trig_bitlength =   0,
        .extern_timestamp = 0,
        .xmit_timestamp =   0,
        .trig_condition =   0,
202 203
        .trig_out =         0,
        .trig_mode =        TRIGMODE_FREERUN
204
};
205 206 207 208 209 210
/*
#define TRIGMODE_FREERUN  0
#define TRIGMODE_SNAPSHOT 4
#define TRIGMODE_GRR      20

 */
211
struct common_pars_t *common_pars = NULL;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
212
/* Remove after compilation OK */
Andrey Filippov's avatar
Andrey Filippov committed
213
//struct sensorproc_t * sensorproc = NULL;
Andrey Filippov's avatar
Andrey Filippov committed
214
//void compressor_interrupts (int on) {}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
#if 0
#define wait_event_interruptible(wq, condition)				\
({									\
	int __ret = 0;							\
	might_sleep();							\
	if (!(condition))						\
		__ret = __wait_event_interruptible(wq, condition);	\
	__ret;								\
})

#define __wait_event_interruptible_timeout(wq, condition, timeout)	\
	___wait_event(wq, ___wait_cond_timeout(condition),		\
		      TASK_INTERRUPTIBLE, 0, timeout,			\
		      __ret = schedule_timeout(__ret))

#define __wait_event_interruptible(wq, condition)			\
	___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0,		\
		      schedule())

#endif

236 237 238
/** @brief Global pointer to basic device structure. This pointer is used in debugfs output functions */
static struct device *g_devfp_ptr;

239
//wait_queue_head_t framepars_wait_queue; // used to wait for the frame to be acquired
Mikhail Karpenko's avatar
Mikhail Karpenko committed
240 241 242 243 244

/**
 * @brief file private data
 */
struct framepars_pd {
245
	int minor;                                      ///< file minor value
246
	struct wait_queue *framepars_wait_queue;        ///< wait queue (waiting for file number to increase)  //NOTE: not used at all?
Mikhail Karpenko's avatar
Mikhail Karpenko committed
247 248 249
// something else to be added here?
};

Andrey Filippov's avatar
Andrey Filippov committed
250
static u32 debug_flags = 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
251 252 253 254

/**
 * @brief assign non-static pointers to static data to be used as extern
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
255
void init_framepars_ptr(int sensor_port)
256
{
257 258
//	frameparsall =      &sFrameParsAll; // - will be mmap-ed
	aframeparsall =                    sFrameParsAll; // - will be mmap-ed
Mikhail Karpenko's avatar
Mikhail Karpenko committed
259 260
	aframepars[sensor_port] =          sFrameParsAll[sensor_port].framePars;
	apastpars[sensor_port] =           sFrameParsAll[sensor_port].pastPars;
261 262 263 264
	afuncs2call[sensor_port] =         sFrameParsAll[sensor_port].func2call.pars;       // each parameter has a 32-bit mask of what pgm_function to call - other fields not used
	aglobalPars[sensor_port] =         sFrameParsAll[sensor_port].globalPars;           // parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both
	amultiSensIndex[sensor_port] =     sFrameParsAll[sensor_port].multiSensIndex;      // indexes of individual sensor register shadows (first of 3) - now for all parameters, not just sensor ones
	amultiSensRvrsIndex[sensor_port] = sFrameParsAll[sensor_port].multiSensRvrsIndex;  // reverse index (to parent) for the multiSensIndex
265
	common_pars =                      &scommon_pars;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
266 267
}

268
int        framepars_open(struct inode *inode, struct file *filp);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
269
int        framepars_release(struct inode *inode, struct file *filp);
270 271 272
loff_t     framepars_lseek(struct file * file, loff_t offset, int orig);
ssize_t    framepars_write(struct file * file, const char * buf, size_t count, loff_t *off);
int        framepars_mmap(struct file *file, struct vm_area_struct *vma);
273
void       trigSlaveUpdate(int sensor_port);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
274 275 276

/**
 * @brief Reset hardware sequencers (i2c, command) and initialize framepars structure
277
 * Does not seem to do anything with the sequencers
Mikhail Karpenko's avatar
Mikhail Karpenko committed
278
 */
279
int initSequencers(int sensor_port)
280
{
281 282
//    x393_rtc_sec_t  rtc_sec =  {.d32=0};
    sec_usec_t sec_usec;
283
    FLAGS_IBH
284
    if (!is_fpga_programmed()){
285 286 287 288 289 290
        dev_err(g_devfp_ptr,"*** Attempted to access hardware without bitsteram ***\n");
        return - ENODEV;
    }
    if (!hardware_initialized) {
        dev_dbg(g_devfp_ptr,"Configuring compressor DMA channels\n");
        dev_info(g_devfp_ptr,"Configuring compressor DMA channels\n");
291
        init_compressor_dma(0xf, // all channels (TODO: NC393 - select channels in DT or use existing for sensors?
292
                              0); // not to interfere with python setting the same
293 294 295 296 297
        // Start RTC by writing 0 to seconds if it was not already set, otherwise preserve current time
        get_fpga_rtc(&sec_usec);
        set_fpga_rtc( sec_usec);
        // Start RTC by writing 0 to seconds
//        set_x393_rtc_sec_set (rtc_sec); // started RTC, correct time may be set later or before
298 299 300
        hardware_initialized = 1;
    }
	dev_dbg(g_devfp_ptr,"port= %d,initSequencers:resetting both sequencers (not really?)\n", sensor_port);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
301
#ifdef TEST_DISABLE_CODE
302
	local_ irq_save(flags);
303 304 305
	X3X3_SEQ_RESET;
	i2c_reset_wait();
	local_irq_restore(flags);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
306
#endif
Andrey Filippov's avatar
Andrey Filippov committed
307
    initFramePars(sensor_port);
308
    return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
309
}
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
/** Enable/disable sesnor channel (will not generate SoF/EoF pulses and interrupts if disabled). Used to turn off missing channels */
void enDisSensorChn(int sensor_port, ///< sensor_port sensor port number (0..3)
                    int en)          ///< enable channel
{
    x393_sens_mode_t sens_mode =  {.d32=0};
    sens_mode.chn_en =     en;
    sens_mode.chn_en_set = 1;
    x393_sens_mode(sens_mode,sensor_port);
    dev_dbg(g_devfp_ptr,"enDisSensorChn(%d,%d)\n", sensor_port, en);
}




/** Stop frame sequencer, optionally disable interrupts also */
void stopFrameSequencer(int sensor_port, ///< sensor_port sensor port number (0..3)
                        int dis_int)     ///< disable interrupts
{
    x393_cmdframeseq_mode_t cmdframeseq_mode = {.d32=0};
    // TODO: Add locking for sequence reset?
    cmdframeseq_mode.run_cmd = 2; // Stop
    if (dis_int) cmdframeseq_mode.interrupt_cmd = 2; // disable
    x393_cmdframeseq_ctrl(cmdframeseq_mode, sensor_port);
    dev_dbg(g_devfp_ptr,"Stop command sequencer for port= %d,  dis_int = %d\n", sensor_port, dis_int);
}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
335

Andrey Filippov's avatar
Andrey Filippov committed
336 337 338 339
/** Reset absolute frame number \b thisFrameNumber to \b frame16, optionally reset/restart sequencer */
void resetFrameNumber(int sensor_port, ///< sensor_port sensor port number (0..3)
                      u32 aframe,      ///< absolute frame number to set (lower 4 bits will be set from hardware)
                      int hreset)      ///< Reset hardware sequencer itself
340 341
{
	int i;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
342 343
	x393_cmdseqmux_status_t stat;
	x393_status_ctrl_t      stat_ctrl;
Andrey Filippov's avatar
Andrey Filippov committed
344 345 346 347 348 349 350 351 352 353
	x393_cmdframeseq_mode_t cmdframeseq_mode = {.d32=0};
	u32 frame16;
	// TODO: Add locking for sequence reset?
	if (hreset){
	    cmdframeseq_mode.reset = 1;
	    x393_cmdframeseq_ctrl(cmdframeseq_mode, sensor_port);
	    udelay(2);
        cmdframeseq_mode.d32 =     0;
        cmdframeseq_mode.run_cmd = 3; // Run
        x393_cmdframeseq_ctrl(cmdframeseq_mode, sensor_port);
Andrey Filippov's avatar
Andrey Filippov committed
354
        dev_dbg(g_devfp_ptr,"Reset command sequencer (all channels !): port= %d,  thisFrameNumber=0x%lx\n", sensor_port, thisFrameNumber(sensor_port));
Andrey Filippov's avatar
Andrey Filippov committed
355 356
	}

Mikhail Karpenko's avatar
Mikhail Karpenko committed
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
	/* Check if the status update mode for command sequencer is not 3 (auto), set/wait if needed */
	stat_ctrl =  get_x393_cmdseqmux_status_ctrl();
	if (stat_ctrl.mode !=3) {
		stat = x393_cmdseqmux_status();
		stat_ctrl.seq_num = stat.seq_num + 1;
		stat_ctrl.mode = 3;
		set_x393_cmdseqmux_status_ctrl(stat_ctrl);
		for (i = 0; i < 10; i++) {
			stat = x393_cmdseqmux_status();
			if (likely(stat.seq_num == stat_ctrl.seq_num))
				break;
		}
	} else {
		stat = x393_cmdseqmux_status();
	}
	switch (sensor_port) {
Andrey Filippov's avatar
Andrey Filippov committed
373 374 375 376 377 378
	//		case 0: thisFrameNumber(sensor_port) = stat.frame_num0; break;
	case 0: frame16 = stat.frame_num0; break;
	case 1: frame16 = stat.frame_num1; break;
	case 2: frame16 = stat.frame_num2; break;
	default:
	    frame16 = stat.frame_num3; break;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
379
	}
Andrey Filippov's avatar
Andrey Filippov committed
380
    thisFrameNumber(sensor_port) = (aframe & PARS_FRAMES_MASK) | frame16;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
381 382
#ifdef NC353
	thisFrameNumber(sensor_port) = X3X3_I2C_FRAME;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
383
#endif
Andrey Filippov's avatar
Andrey Filippov committed
384
	dev_dbg(g_devfp_ptr,"Resetting frame number, port= %d,  thisFrameNumber=0x%lx\n", sensor_port, thisFrameNumber(sensor_port));
Mikhail Karpenko's avatar
Mikhail Karpenko committed
385
// write absolute frame numbers
Andrey Filippov's avatar
Andrey Filippov committed
386 387
//    for (i = thisFrameNumber(sensor_port); i < (thisFrameNumber(sensor_port) + PARS_FRAMES); i++) aframepars[sensor_port][i & PARS_FRAMES_MASK].pars[P_FRAME] = i;
    for (i = 0; i <  PARS_FRAMES; i++) aframepars[sensor_port][(i+frame16) & PARS_FRAMES_MASK].pars[P_FRAME] = thisFrameNumber(sensor_port) + i;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
388 389 390 391
}

/**
 * @brief initialize all parameters, set \b thisFrameNumber to \b frame number read from hardware hardware ( 0 after resetting i2c and cmd_seq)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
392
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
393
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
394
void initFramePars(int sensor_port)
395 396
{
	int i;
397 398
	FLAGS_IBH;
	LOCK_IBH(framepars_locks[sensor_port]);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
399
	memset(aframepars[sensor_port], 0, sizeof(struct framepars_t) * PARS_FRAMES);
Andrey Filippov's avatar
Andrey Filippov committed
400
	resetFrameNumber(sensor_port, 0, 1);
401
// initialize frameParsDeps.pars masks:
402
	for (i = 0; i < (sizeof(param_depend_tab) / 8); i++) {
403
		afuncs2call[sensor_port][param_depend_tab[2 * i] & 0xffff] = param_depend_tab[2 * i + 1]; // remove possible flags
Andrey Filippov's avatar
Andrey Filippov committed
404
		dev_dbg(g_devfp_ptr,"%s : port= %d, funcs2call[0x%lx]=0x%08lx\n",__func__, sensor_port, param_depend_tab[2 * i] & 0xffff, param_depend_tab[2 * i + 1]);
405
	}
406 407 408
	for (i = 0; i < P_SENSOR_NUMREGS; i++) afuncs2call[sensor_port][P_SENSOR_REGS + i] = ONCHANGE_SENSORREGS;     // by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
// Same for 10359 registers - will not change anything if there is no 10359 - these registers will not be changed, and if will be it wil cause no action
	for (i = 0; i < P_M10359_NUMREGS; i++) afuncs2call[sensor_port][P_M10359_REGS + i] = ONCHANGE_SENSORREGS;     // by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
Mikhail Karpenko's avatar
Mikhail Karpenko committed
409

410
	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
Andrey Filippov's avatar
Andrey Filippov committed
411
	frameParsInitialized[sensor_port] = 1;
412
	UNLOCK_IBH(framepars_locks[sensor_port]);
413 414
    dev_dbg(g_devfp_ptr,"%s port %d: DONE, frameParsInitialized[%d]=%d\n",
            __func__, sensor_port, sensor_port, frameParsInitialized[sensor_port]);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
415 416 417 418
}

/**
 * @brief reset all global parameters, set default for debug mask (if ELPHEL_DEBUG)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
419
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
420
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
421
void initGlobalPars(int sensor_port)
422
{
Mikhail Karpenko's avatar
Mikhail Karpenko committed
423
	memset(&aglobalPars[sensor_port][GLOBALS_PRESERVE], 0, (NUM_GPAR - GLOBALS_PRESERVE) * sizeof(unsigned long));
424
//   MDF(GLOBALPARS(G_DEBUG) = ELPHEL_DEBUG_STARTUP;// removed - add write to fpga init script
Andrey Filippov's avatar
Andrey Filippov committed
425
	dev_dbg(g_devfp_ptr,"%s : port= %d, GLOBALPARS(0,G_DEBUG)=%lx\n",__func__, sensor_port, GLOBALPARS(0,G_DEBUG));
Mikhail Karpenko's avatar
Mikhail Karpenko committed
426 427 428 429
}

/**
 * @brief initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
Mikhail Karpenko's avatar
Mikhail Karpenko committed
430
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
431 432
 * @return number of multi-regs
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
433
int initMultiPars(int sensor_port)
434 435
{
	int i, j, n;
436
	int ireg = P_MULTI_REGS; // multi-reg shadows start index
437 438
	unsigned long m;

Mikhail Karpenko's avatar
Mikhail Karpenko committed
439 440 441 442 443
//	memset(amultiSensIndex[sensor_port], 0, sizeof(struct framepars_all_t.multiSensIndex));
	memset(amultiSensIndex[sensor_port], 0, P_MAX_PAR_ROUNDUP * sizeof(int));
//	memset(multiSensRvrsIndex, 0, sizeof(multiSensRvrsIndex));
	memset(amultiSensRvrsIndex[sensor_port], 0, P_MAX_PAR_ROUNDUP * sizeof(int));
	GLOBALPARS(sensor_port,G_MULTI_NUM) = 0;
444
	for (i = 0; i < 8; i++) {
445
		m = GLOBALPARS(sensor_port, G_MULTI_REGSM + i); // 1 bit per register that need individual shadows
Andrey Filippov's avatar
Andrey Filippov committed
446
//     dev_dbg(g_devfp_ptr,"%s i=%d, m=0x%lx\n",__func__,i,m);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
447
		for (j = P_SENSOR_REGS + (i << 5); m && (GLOBALPARS(sensor_port,G_MULTI_NUM) < P_MULTI_NUMREGS); j++, m >>= 1) {
448
			if (m & 1) {
Andrey Filippov's avatar
Andrey Filippov committed
449 450
				amultiSensIndex[sensor_port][j] = ireg;
//         dev_dbg(g_devfp_ptr,"%s j=0x%x ireg=0x%x\n",__func__,j,ireg);
451
				for (n = 0; n < MAX_SENSORS; n++) {
452
					afuncs2call[sensor_port][ireg] = ONCHANGE_SENSORREGS; // by default each "manual" write to any of these registers will trigger pgm_sensorreg function
Mikhail Karpenko's avatar
Mikhail Karpenko committed
453
					amultiSensRvrsIndex[sensor_port][ireg++] = j | ((n + 1) << 16);
454
				}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
455
				GLOBALPARS(sensor_port,G_MULTI_NUM)++;
456 457 458
			}
		}
	}
459
	// remark: the line below is called from initFramePars, consider removing it
460
	for (i = 0; i < P_SENSOR_NUMREGS; i++) afuncs2call[sensor_port][P_SENSOR_REGS + i] = ONCHANGE_SENSORREGS;  // by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
Andrey Filippov's avatar
Andrey Filippov committed
461
	dev_dbg(g_devfp_ptr,"%s : port= %d, GLOBALPARS(G_MULTI_NUM)=%lx\n",__func__, sensor_port, GLOBALPARS(sensor_port, G_MULTI_NUM));
Mikhail Karpenko's avatar
Mikhail Karpenko committed
462
	return GLOBALPARS(sensor_port, G_MULTI_NUM);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
463 464
}

465 466 467 468 469 470 471 472
/** Reads parameters for the specified frame number, OK to use in compressor ISR using last compressed frame */
inline unsigned long get_imageParamsFrame(int sensor_port, ///< sensor port (0..3)
                                          int n,           ///< parameter index (should be 128..143)
                                          int frame)       ///< absolute frame number
{
    return aframepars[sensor_port][frame & PARS_FRAMES_MASK].pars[n];
}

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
inline unsigned long * get_imageParamsFramePtr(int sensor_port, ///< sensor port (0..3)
                                               int n,           ///< parameter index (should be 128..143)
                                               int frame)       ///< absolute frame number
{
    return &(aframepars[sensor_port][frame & PARS_FRAMES_MASK].pars[n]);
}

inline unsigned long * get_imageParamsPastPtr(int sensor_port, ///< sensor port (0..3)
                                              int n,           ///< parameter index (should be 128..143)
                                              int frame)       ///< absolute frame number
{
    return &(apastpars[sensor_port][frame & PASTPARS_SAVE_ENTRIES_MASK].past_pars[n-PARS_SAVE_FROM]);
}




Mikhail Karpenko's avatar
Mikhail Karpenko committed
490 491
/**
 * @brief reads parameters from the current frame (matching hardware index)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
492
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
493 494 495
 * @param n number of a parameter to read
 * @return parameter value (unsigned long)
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
496
inline unsigned long get_imageParamsThis(int sensor_port, int n)
497
{
Mikhail Karpenko's avatar
Mikhail Karpenko committed
498
	return aframepars[sensor_port][thisFrameNumber(sensor_port) & PARS_FRAMES_MASK].pars[n];
Mikhail Karpenko's avatar
Mikhail Karpenko committed
499 500 501 502
}

/**
 * @brief reads parameters from the previous frame (matching hardware index) - used to determine if historam was needed
Mikhail Karpenko's avatar
Mikhail Karpenko committed
503
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
504 505 506
 * @param n number of a parameter to read
 * @return parameter value (unsigned long)
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
507
inline unsigned long get_imageParamsPrev(int sensor_port, int n)
508
{
Mikhail Karpenko's avatar
Mikhail Karpenko committed
509
	return aframepars[sensor_port][(thisFrameNumber(sensor_port) - 1) & PARS_FRAMES_MASK].pars[n];
Mikhail Karpenko's avatar
Mikhail Karpenko committed
510 511
}

512
/** Reads past parameters (small subset of all) for absolute frame number */
Andrey Filippov's avatar
Andrey Filippov committed
513 514 515 516 517 518 519 520 521
inline unsigned long get_imageParamsPast(int sensor_port, ///< sensor port (0..3)
                                         int n,           ///< parameter index (should be 128..143)
                                         int frame)       ///< absolute frame number
{
    return apastpars[sensor_port][frame & PASTPARS_SAVE_ENTRIES_MASK].past_pars[n-PARS_SAVE_FROM];
}



Mikhail Karpenko's avatar
Mikhail Karpenko committed
522 523 524
/**
 * @brief writes read-only parameter to the current frame (does not propagate to next frames as setFramePar() does)
 * In most cases you really need to use setFramePar() instead;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
525
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
526 527 528 529
 * @param n number of a parameter to set
 * @param d data to write to the selected parameter
 */

Mikhail Karpenko's avatar
Mikhail Karpenko committed
530
inline void set_imageParamsThis(int sensor_port, int n, unsigned long d)
531
{
Mikhail Karpenko's avatar
Mikhail Karpenko committed
532
	aframepars[sensor_port][thisFrameNumber(sensor_port) & PARS_FRAMES_MASK].pars[n] = d;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
533 534 535 536
}

/**
 * @brief reads global (not related to particular frames) parameters
Mikhail Karpenko's avatar
Mikhail Karpenko committed
537
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
538 539 540
 * @param n number of a parameter to read (numbers start from FRAMEPAR_GLOBALS)
 * @return parameter value (unsigned long)
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
541
inline unsigned long get_globalParam(int sensor_port, int n)
542
{
Mikhail Karpenko's avatar
Mikhail Karpenko committed
543
	return GLOBALPARS(sensor_port, n);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
544 545 546
}
/**
 * @brief sets global (not related to particular frames) parameters
Mikhail Karpenko's avatar
Mikhail Karpenko committed
547
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
548 549 550 551
 * @param n number of a parameter to set  (numbers start from FRAMEPAR_GLOBALS)
 * @param d data to write to the selected parameter
 */

Mikhail Karpenko's avatar
Mikhail Karpenko committed
552
inline void          set_globalParam(int sensor_port, int n, unsigned long d)
553
{
Mikhail Karpenko's avatar
Mikhail Karpenko committed
554
	GLOBALPARS(sensor_port, n) = d;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
555 556 557 558 559
}

/**
 * @brief set same parameters in all frames
 * currently used only in compressor reset
Mikhail Karpenko's avatar
Mikhail Karpenko committed
560
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
561 562 563
 * @param n number of a parameter to set
 * @param d data to write to the selected parameter
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
564
inline void          set_imageParamsR_all(int sensor_port, int n, unsigned long d)
565 566
{
	int i;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
567
	for (i = 0; i < PARS_FRAMES; i++) aframepars[sensor_port][i].pars[n] = d;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
568
}
Andrey Filippov's avatar
Andrey Filippov committed
569 570 571 572 573 574 575
/**
 * Update "interframe" parameters (inside the circular buffer). Called from ISR (comressor done)
 * @param sensor_port - sensor
 * @param frame16
 * @param interframe_pars
 */

Andrey Filippov's avatar
Andrey Filippov committed
576 577 578
void updateInterFrame(int sensor_port,      ///< Sensor port number (0..3)
                      u32 compressed_frame, ///< number of frame just compressed
                                            ///< interrupt should be processed after frame sync interrupt
Andrey Filippov's avatar
Andrey Filippov committed
579 580
                      struct interframe_params_t * interframe_pars) ///< pointer to the area in circbuf to save parameters
{
Andrey Filippov's avatar
Andrey Filippov committed
581 582 583 584
//    int findex_this, findex_prev, findex_future, findex_next;
//    int index;
//    int index32;
//    unsigned long bmask, bmask32;
Andrey Filippov's avatar
Andrey Filippov committed
585
    int pastParsIndex;
586 587 588
    int compressedIndex = compressed_frame & PARS_FRAMES_MASK; // last compressed frame mod 16
    struct framepars_t *framepars = aframepars[sensor_port];

Andrey Filippov's avatar
Andrey Filippov committed
589 590
    thisCompressorFrameNumber(sensor_port) = compressed_frame;
    pastParsIndex = compressed_frame & PASTPARS_SAVE_ENTRIES_MASK; // copying from what was past frame that might include histogram data
591 592
// After Frame sync interrupt processed, oldest valid will be is sensor frame number -2, compressor lag is 1 frame (0..2), so read not past-pars is OK
#ifdef USE_PASTPARS_IN_CMPRSIRQ
Andrey Filippov's avatar
Andrey Filippov committed
593 594 595 596 597
    memcpy(interframe_pars,      &apastpars[sensor_port][pastParsIndex].past_pars[P_GTAB_R-PARS_SAVE_FROM], 24); // will leave some gaps, but copy [P_ACTUAL_WIDTH]
    interframe_pars->height =     apastpars[sensor_port][pastParsIndex].past_pars[P_ACTUAL_HEIGHT-PARS_SAVE_FROM];        // NOTE: P_ACTUAL_WIDTH,P_QUALITY copied with memcpy
    interframe_pars->color =      apastpars[sensor_port][pastParsIndex].past_pars[P_COLOR-PARS_SAVE_FROM];
    interframe_pars->byrshift =   apastpars[sensor_port][pastParsIndex].past_pars[P_COMPMOD_BYRSH-PARS_SAVE_FROM];
    interframe_pars->quality2 |= (apastpars[sensor_port][pastParsIndex].past_pars[P_PORTRAIT-PARS_SAVE_FROM] & 1) << 7;
598 599 600 601 602 603 604 605 606 607

#else
    memcpy (interframe_pars,  &framepars[compressedIndex].pars[P_GTAB_R], 24); /// will leave some gaps, but copy [P_ACTUAL_WIDTH]
    interframe_pars->height=  framepars[compressedIndex].pars[P_ACTUAL_HEIGHT]; /// NOTE: P_ACTUAL_WIDTH,P_QUALITY copied with memcpy
    interframe_pars->color=   framepars[compressedIndex].pars[P_COLOR];
    interframe_pars->byrshift=framepars[compressedIndex].pars[P_COMPMOD_BYRSH];
    interframe_pars->quality2 |= (framepars[compressedIndex].pars[P_PORTRAIT] & 1) << 7;
#endif


Andrey Filippov's avatar
Andrey Filippov committed
608
}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
609

610
//++++++++++++++++++++++++++++++++++++++++++
Andrey Filippov's avatar
Andrey Filippov committed
611
/** Called from ISR (sensor frame interrupt)- advance thisFrameNumber to match hardware frame16, copy parameters as needed.
612 613 614 615
 * before: (thisFrameNumber mod 16      pointed to current (for the software) parameters frame (now behind by at least 1, maybe 2)
 *         (thisFrameNumber-1) mod 16 - oldest with parameters preserved, also containes histograms results (+image timestamp, size?)
 *                                        subset of that frame data is copied to pastpars
 *         (thisFrameNumber-2) mod 16- farthest in the future frame
Mikhail Karpenko's avatar
Mikhail Karpenko committed
616 617
 * after:   thisFrameNumber matches hardware pointer
 */
Andrey Filippov's avatar
Andrey Filippov committed
618 619

//TODO: Remove interframe, handle it with compressor interrupts (above)
620 621 622 623
/// Among other things copies subset of parameters to pastpars

void updateFramePars(int sensor_port, ///< sensor port number (0..3)
                     int frame16)     ///< Sensor sequencer (hardware) frame number
624 625 626 627 628
{
	int findex_this, findex_prev, findex_future, findex_next;
	int index, index32;
	unsigned long bmask, bmask32;
	int pastParsIndex;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
629
	struct framepars_t *framepars = aframepars[sensor_port];
630 631 632 633 634
#define DEBUG_BYRSH
#ifdef DEBUG_BYRSH
	int comp_frame16 = getHardFrameNumber(sensor_port, 1);    // Use compressor frame number
	u32 comp_aframe = thisCompressorFrameNumber(sensor_port);
	x393_cmprs_mode_t cmprs_mode = get_x393_cmprs_control_reg(sensor_port);
Andrey Filippov's avatar
Andrey Filippov committed
635 636
#endif
    dev_dbg(g_devfp_ptr,"%s : port= %d, frame16=%d\n",__func__, sensor_port, frame16);
637
	while ((frame16 ^ thisFrameNumber(sensor_port)) & PARS_FRAMES_MASK) { // While hardware pointer is still ahead of the software maintained one
638
	    dev_dbg(g_devfp_ptr,"%s : port= %d, frame16=%d, thisFrameNumber(%d)=%d\n",__func__, sensor_port, frame16, sensor_port, (int)thisFrameNumber(sensor_port));
639
// before update:
640
//   framepars[findex_prev]  holds previous frame data (oldest availble - latest?)
641 642 643
//   framepars[findex_future] holds farthest in the future one
// after update:
//   framepars[findex_prev]  holds farthest in the future one ("this" will become "prev")
644 645 646 647
		findex_this =  thisFrameNumber(sensor_port)  & PARS_FRAMES_MASK; // Nothing is yet done for this frame (mod 16)
		findex_prev =  (findex_this - 1)  & PARS_FRAMES_MASK;            // Holds previous frame data (mod 16)  (latest available)
		findex_future = (findex_this - 2)  & PARS_FRAMES_MASK;           // farthest in the future (mod 16)  (not to overwrite latest
		findex_next =  (findex_this + 1)  & PARS_FRAMES_MASK;            // Just next frame (mod 16) after the current
648 649 650
// copy subset of the parameters to the long buffer of past parameters. TODO: fill Exif also here?
// TODO:DONE: Change - make pastpars be save for all frames, not just compressed ones
// With PASTPARS_SAVE_ENTRIES being multiple of PARS_FRAMES - make it possible to calculate past_index from thisFrameNumber
Mikhail Karpenko's avatar
Mikhail Karpenko committed
651
//    pastParsIndex= thisFrameNumber & PASTPARS_SAVE_ENTRIES_MASK;
652
		pastParsIndex = (thisFrameNumber(sensor_port) - 1) & PASTPARS_SAVE_ENTRIES_MASK; // copying from what was past frame that might include histogram data
Mikhail Karpenko's avatar
Mikhail Karpenko committed
653
//    memcpy (pastpars[pastParsIndex].past_pars, &framepars[findex_prev].pars[PARS_SAVE_FROM], sizeof(pastpars[0].past_pars));
654 655 656
//		memcpy(apastpars[sensor_port][pastParsIndex].past_pars, &framepars[findex_prev].pars[PARS_SAVE_FROM], PARS_SAVE_COPY * sizeof(int));
        memcpy(apastpars[sensor_port][pastParsIndex].past_pars, &framepars[findex_prev].pars[PARS_SAVE_FROM], PARS_SAVE_COPY << 2);

657 658 659 660 661 662 663
#ifdef DEBUG_BYRSH
        apastpars[sensor_port][pastParsIndex].past_pars[PARS_SAVE_COPY + 0] = comp_frame16;
        apastpars[sensor_port][pastParsIndex].past_pars[PARS_SAVE_COPY + 1] = comp_aframe;
        apastpars[sensor_port][pastParsIndex].past_pars[PARS_SAVE_COPY + 2] = cmprs_mode.d32;
        apastpars[sensor_port][pastParsIndex].past_pars[PARS_SAVE_COPY + 3] = pastParsIndex;
#endif

664 665
		// Now update interframe_pars (interframe area) used to create JPEG headers. Interframe area survives exactly as long as the frames themselves (not like pastpars)

666
//      debug code - save compressor states in the past parameters
667
// copy parameters from findex_future (old "farthest in the future") to findex_prev (new "fartherst in the future") if it was changed since
668
		if ((bmask32 = framepars[findex_prev].modsince32)) {
Andrey Filippov's avatar
Andrey Filippov committed
669
			dev_dbg(g_devfp_ptr,"%s framepars[%d].modsince32=0x%lx\n",__func__, findex_prev, bmask32);
670 671 672 673 674
			for (index32 = 0; bmask32; index32++, bmask32 >>= 1) {
				if (bmask32 & 1) {
					for (index = (index32 << 5), bmask = framepars[findex_prev].modsince[index32]; bmask; index++, bmask >>= 1)
						if (bmask & 1) {
							framepars[findex_prev].pars[index] = framepars[findex_future].pars[index];
Andrey Filippov's avatar
Andrey Filippov committed
675
							dev_dbg(g_devfp_ptr,"%s hw=%d framepars[%d].pars[%d]=framepars[%d].pars[%d]=0x%lx\n",__func__, frame16, findex_prev, index, findex_future, index, framepars[findex_future].pars[index]);
676
						}
677
					framepars[findex_prev].modsince[index32] = 0; //  mark as not "modified since" (yet)
678 679
				}
			}
680
			framepars[findex_prev].modsince32 = 0; //  mark as not "modified since" super index
681
		}
682
// clear "modified" and  flags on the brand new future frame
683 684
		// remark: framepars[findex_prev].mod is 31 dwords long abd here 32 dwords are cleared
		// explanation: mod32 goes after mod[31] and it is cleared too
685 686
		if (framepars[findex_prev].mod32) memset(framepars[findex_prev].mod, 0, 32 * 4);        // .mod[0]-.mod[30], .mod32
		framepars[findex_prev].functions = 0;                                                   // No functions yet needed on the brand new frame
687
		// remark: replace number 7 with named constant, it should correspond to total frame num (16 in new camera)
688 689 690
		framepars[findex_prev].pars[P_FRAME] = thisFrameNumber(sensor_port) + (PARS_FRAMES-1);  // that will be the full frame number
// NOTE: Handle past due - copy functions, and mod if functions were non-zero
		if (framepars[findex_this].functions) {                                                 // Some functions were not yet processed (past due)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
691
			if (!(get_globalParam(sensor_port, G_TASKLET_CTL) & (1 << TASKLET_CTL_IGNPAST))) {
692 693 694 695 696 697 698 699 700
				framepars[findex_next].functions |= framepars[findex_this].functions;
				if ((bmask32 = framepars[findex_this].mod32)) {
					for (index32 = 0; bmask32; index32++, bmask32 >>= 1) {
						if (bmask32 & 1) {
							framepars[findex_next].mod[index32] |= framepars[findex_this].mod[index32];
						}
						framepars[findex_next].mod32 |= framepars[findex_this].mod32;
					}
				}
Andrey Filippov's avatar
Andrey Filippov committed
701
				dev_dbg(g_devfp_ptr,"%s resubmitting past due functions = 0x%lx for frame=%ld (0x%x)\n",__func__, framepars[findex_this].functions, thisFrameNumber(sensor_port), findex_this);
702
			} else {
Andrey Filippov's avatar
Andrey Filippov committed
703
				dev_dbg(g_devfp_ptr,"%s Ignored past due functions = 0x%lx for frame=%ld (0x%x)\n",__func__, framepars[findex_this].functions, thisFrameNumber(sensor_port), findex_this);
704 705
			}
		}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
706
		thisFrameNumber(sensor_port)++;
707 708 709 710
//        if (thisFrameNumber(sensor_port)<20) {
//            dev_dbg(g_devfp_ptr,"thisFrameNumber(%d)=0x%x\n",sensor_port, (int) thisFrameNumber(sensor_port));
//        }

711
	}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
712 713
}

Andrey Filippov's avatar
Andrey Filippov committed
714
/** Process parameters that are overdue or due in ASAP mode (not through the sequencer)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
715
 * Called twice from processPars - at the beginning and at the end to finish off any derivatives (needed?)
Andrey Filippov's avatar
Andrey Filippov committed
716 717 718 719
 * Should never be called from outside processPars() where there is a per-port lock */
inline void _processParsASAP(int sensor_port,                   ///< sensor port number (0..3)
                             struct sensorproc_t * sensorproc,  ///< per-port array of sensor capabilities and 32+32 on-change functions
                             int frame16)                       ///< Hardware sequencer frame number, or -1 for ASAP
720 721
{
	unsigned long todo, mask, remain;
Andrey Filippov's avatar
Andrey Filippov committed
722
	int pars_ahead;                 // considering parameter "pars_ahead" of the (frame16+job_ahead) mod 8
723
	int frame_proc;                 // current frame for which parameters are considered
724
	struct framepars_t * procpars;
725
	struct framepars_t * prevpars;  // maybe - drop calculation for each function, move it to pgm_* where needed?
Mikhail Karpenko's avatar
Mikhail Karpenko committed
726 727
	struct framepars_t *framepars = aframepars[sensor_port];
	unsigned long * p_nasap = &GLOBALPARS(sensor_port, G_CALLNASAP);
728 729
	int i;
	int rslt;
730

731
#ifdef ELPHEL_DEBUG_0
732 733
	unsigned long allfunctions = framepars[0].functions  | framepars[1].functions | framepars[2].functions | framepars[3].functions |
				     framepars[4].functions | framepars[5].functions | framepars[6].functions | framepars[7].functions;
Andrey Filippov's avatar
Andrey Filippov committed
734
	if (allfunctions) MDF6(printk("frame16=%d, functions: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", frame16, framepars[0].functions,
Mikhail Karpenko's avatar
Mikhail Karpenko committed
735 736
			framepars[1].functions, framepars[2].functions, framepars[3].functions, framepars[4].functions, framepars[5].functions,
			framepars[6].functions, framepars[7].functions));
Mikhail Karpenko's avatar
Mikhail Karpenko committed
737
#endif
Andrey Filippov's avatar
Andrey Filippov committed
738 739 740 741 742
	if (debug_flags)
	    dev_dbg(g_devfp_ptr,"ASAP: port=%d frame16=%d\n",   sensor_port,  frame16);
	else
        dev_dbg(g_devfp_ptr,"ASAP: port=%d frame16=%d\n",   sensor_port,  frame16);

Andrey Filippov's avatar
Andrey Filippov committed
743
    if (!sensorproc){
Andrey Filippov's avatar
Andrey Filippov committed
744
        dev_err(g_devfp_ptr,"sensorproc==NULL !!!! port=%d frame16=%d \n", sensor_port,  frame16);
Andrey Filippov's avatar
Andrey Filippov committed
745 746 747
        return;
    }

748 749
// do all ASAP tasks (they should not be done ahead of the corresponding interrupt!)
// Now try overdue functions with latencies >=1 and try them in ASAP mode
750
	for (pars_ahead = 0; pars_ahead <= 4; pars_ahead++ ) {
Andrey Filippov's avatar
Andrey Filippov committed
751
		frame_proc = (frame16 + pars_ahead) & PARS_FRAMES_MASK;
752 753 754 755 756
		procpars  = &framepars[frame_proc];
		prevpars  = &framepars[(frame_proc - 1) & PARS_FRAMES_MASK];
		i = 0;
		mask = 1;
		remain = 0xffffffff;
Andrey Filippov's avatar
Andrey Filippov committed
757 758 759 760 761

	    if (debug_flags) {
	        todo = (pars_ahead) ?
	                           (p_nasap[pars_ahead] & (procpars->functions) & remain) :
	                           (procpars->functions & remain);
762
	        dev_dbg(g_devfp_ptr,"port=%d frame16=%d todo=0x%08lx,p_nasap[%d]=0x%08lx procpars->functions=0x%08lx\n",
763
	                sensor_port,  frame16, todo, pars_ahead, p_nasap[pars_ahead], procpars->functions);
764
            MDP(DBGB_FASAP,sensor_port,"frame16=%d todo=0x%08lx,p_nasap[%d]=0x%08lx procpars->functions=0x%08lx\n",
765 766
                    frame16, todo, pars_ahead, p_nasap[pars_ahead], procpars->functions)

Andrey Filippov's avatar
Andrey Filippov committed
767 768 769 770
	    } else {
            todo = (pars_ahead) ?
                               (p_nasap[pars_ahead] & (procpars->functions) & remain) :
                               (procpars->functions & remain);
771
            dev_dbg(g_devfp_ptr,"port=%d frame16=%d todo=0x%08lx,p_nasap[%d]=0x%08lx procpars->functions=0x%08lx\n",
772
                    sensor_port,  frame16, todo, pars_ahead, p_nasap[pars_ahead], procpars->functions);
Andrey Filippov's avatar
Andrey Filippov committed
773
	    }
774 775
		while ((todo = (pars_ahead) ?
			       (p_nasap[pars_ahead] & (procpars->functions) & remain) :
776
			       (procpars->functions & remain) )) {      //none, *1, *2,*3,*4
777

778
			while (!(todo & mask)) {                        // skip zeros - todo will stay current (.functions will not change
779 780 781 782
				i++;
				mask   <<= 1;
				remain <<= 1;
			}
783
// now (todo & mask) !=0
Andrey Filippov's avatar
Andrey Filippov committed
784 785 786
	        if (debug_flags) {
	            dev_dbg(g_devfp_ptr,"port= %d, todo=0x%08lx (curr=0x%08lx) frame16=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx func=0x%08x\n",
	                    sensor_port, todo, procpars->functions, frame16, pars_ahead, frame_proc, i, mask, (int)sensorproc->pgm_func[i]);
787 788
	            MDP(DBGB_FASAP,sensor_port,"todo=0x%08lx (curr=0x%08lx) frame16=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx func=0x%08x\n",
	                    todo, procpars->functions, frame16, pars_ahead, frame_proc, i, mask, (int)sensorproc->pgm_func[i])
Andrey Filippov's avatar
Andrey Filippov committed
789 790 791 792 793

	            dev_dbg(g_devfp_ptr,"port= %d, %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
	                    sensor_port,
	                    framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions,
	                    framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions);
794 795 796 797 798
                MDP(DBGB_FASAP,sensor_port,"%08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
                        framepars[ 0].functions, framepars[ 1].functions, framepars[ 2].functions, framepars[ 3].functions,
                        framepars[ 4].functions, framepars[ 5].functions, framepars[ 6].functions, framepars[ 7].functions,
                        framepars[ 8].functions, framepars[ 9].functions, framepars[10].functions, framepars[11].functions,
                        framepars[12].functions, framepars[13].functions, framepars[14].functions, framepars[15].functions)
Andrey Filippov's avatar
Andrey Filippov committed
799 800 801 802 803 804 805 806 807
	        } else {
	            dev_dbg(g_devfp_ptr,"port= %d, todo=0x%08lx (curr=0x%08lx) frame16=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx func=0x%08x\n",
	                    sensor_port, todo, procpars->functions, frame16, pars_ahead, frame_proc, i, mask, (int)sensorproc->pgm_func[i]);

	            dev_dbg(g_devfp_ptr,"port= %d, %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
	                    sensor_port,
	                    framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions,
	                    framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions);
	        }
808
			if (sensorproc->pgm_func[i]) {
809 810
	            dev_dbg(g_devfp_ptr,"port= %d, Calling GENERIC pgm_func[%d] ASAP, now frame = 0x%lx\n",sensor_port,i,thisFrameNumber(sensor_port));
	            MDP(DBGB_FASAP,sensor_port,"Calling GENERIC pgm_func[%d] ASAP, now frame = 0x%x\n",i,thisFrameNumber(sensor_port))
811
				rslt = sensorproc->pgm_func[i]    (sensor_port, &(sensorproc->sensor), procpars, prevpars, -1);
812 813
			} else rslt = 0;                                        // only sensor-specific function, nothing to do common to all sensors
			if ((rslt >= 0) && (sensorproc->pgm_func[i + 32])) {    // sensor - specific functions, called after the main ones
814 815
                dev_dbg(g_devfp_ptr,"port= %d, Calling SENSOR-SPECIFIC  pgm_func[%d] ASAP, now frame = 0x%lx\n",sensor_port,i,thisFrameNumber(sensor_port));
                MDP(DBGB_FASAP,sensor_port,"Calling SENSOR-SPECIFIC  pgm_func[%d] ASAP, now frame = 0x%x\n",i,thisFrameNumber(sensor_port))
816
				rslt = sensorproc->pgm_func[i + 32] (sensor_port, &(sensorproc->sensor), procpars, prevpars, -1);
817
			}
818
			if (rslt < 0) dev_warn(g_devfp_ptr,"port %d: %s:%d:%s - error=%d",sensor_port,  __FILE__, __LINE__, __FUNCTION__, rslt);// Nothing to do with errors here - just report?
819
			procpars->functions &= ~mask;
Andrey Filippov's avatar
Andrey Filippov committed
820
			dev_dbg(g_devfp_ptr,"%s : port= %d, .functions=0x%08lx)\n",__func__, sensor_port, procpars->functions);
821 822 823 824 825
			i++;
			mask   <<= 1;
			remain <<= 1;
		}
	}
Andrey Filippov's avatar
Andrey Filippov committed
826 827
    dev_dbg(g_devfp_ptr,"%s port=%d DONE\n",  __func__, sensor_port);

Mikhail Karpenko's avatar
Mikhail Karpenko committed
828
}
829

830
// Next 5 should go in that sequence
831 832
//#define G_CALLNASAP    119 // bitmask - what functions can be used not only in the current frame (ASAP) mode
//#define G_CALLNEXT1      120 // bitmask of actions to be one   or more frames ahead of the programmed one (OR-ed with G_CALLNEXT2..G_CALLNEXT4)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
833 834 835 836
//#define G_CALLNEXT2      121 // bitmask of actions to be two   or more frames ahead of the programmed one (OR-ed with G_CALLNEXT3..G_CALLNEXT4)
//#define G_CALLNEXT3      122 // bitmask of actions to be three or more frames ahead of the programmed one (OR-ed with G_CALLNEXT4)
//#define G_CALLNEXT4      123 // bitmask of actions to be four  or more frames ahead of the programmed one

837
/** Process parameters in "normal way" - not ASAP or overdue
Andrey Filippov's avatar
Andrey Filippov committed
838 839
 * Called twice from processPars - at the beginning and at the end to finish off any derivatives (needed?)
 * Should never be called from outside processPars() where there is a per-port lock */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
840

Andrey Filippov's avatar
Andrey Filippov committed
841 842 843 844
inline void _processParsSeq(int sensor_port,                   ///< sensor port number (0..3)
                            struct sensorproc_t * sensorproc,  ///< per-port array of sensor capabilities and 32+32 on-change functions
                            int frame16,                       ///< Hardware sequencer frame number, or -1 for ASAP
                            int maxahead)                      ///< Maximal number of frames ahead to process. TODO NC393: Set G_MAXAHEAD >0 (max latency, was 2 in NC353!),
845 846
{
	unsigned long todo, mask, remain;
847
	int job_ahead;                  // doing job "job_ahead" ahead of needed
848
	int pars_ahead;                 // considering parameter "pars_ahead" of the (frame16+job_ahead) mod 16
849
	int frame_proc;                 // current frame for which parameters are considered
850
	struct framepars_t * procpars;
851
	struct framepars_t * prevpars;  // maybe - drop calculation for each function, move it to pgm_* where needed?
Mikhail Karpenko's avatar
Mikhail Karpenko committed
852 853
	struct framepars_t *framepars = aframepars[sensor_port];
	unsigned long * p_nasap = &GLOBALPARS(sensor_port, G_CALLNASAP);
854
	int seq_frame;                  // sequencer frame for which pgm_* function should schedule data
855 856 857 858
	int i;
	int rslt;
	int max_par_ahead;
	int this_ahead;
Andrey Filippov's avatar
Andrey Filippov committed
859
    dev_dbg(g_devfp_ptr,"%s port=%d frame16=%d,  maxahead=%d\n",  __func__, sensor_port,  frame16, maxahead);
860

861 862 863 864 865
	if (maxahead > (PARS_FRAMES - 3)) maxahead = PARS_FRAMES - 3;  // use 5 if maxahead >5
// commands that use FPGA queues for the i2c/sequencer commands, executed at frame syncs
// Modifying - as soon as found the frame to process with non-zero masked .functions - process all functions for that
// frame with appropriate sequencer frame.
// For now - scan p_nasap[i] to find latency - improve that later
Andrey Filippov's avatar
Andrey Filippov committed
866
	for (job_ahead = 0; job_ahead <= maxahead; job_ahead++ ) { // If have some time - do future job (not required just now)
867 868
		max_par_ahead = min(5, (PARS_FRAMES - 3) - job_ahead);
		for (pars_ahead = 0; pars_ahead < max_par_ahead; pars_ahead++ ) {
Andrey Filippov's avatar
Andrey Filippov committed
869
			frame_proc = (frame16 + job_ahead + pars_ahead + 1) & PARS_FRAMES_MASK; //
870
			procpars  = &framepars[frame_proc];
871
// Check if at least one function is needed for frame_proc
872
			if (procpars->functions &
873
			    p_nasap[pars_ahead] & //all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice
874 875
			    p_nasap[0]) {
				prevpars  = &framepars[(frame_proc - 1) & PARS_FRAMES_MASK];
Andrey Filippov's avatar
Andrey Filippov committed
876
//        seq_frame=  (frame16+job_ahead+1) & PARS_FRAMES_MASK;
877 878 879 880
				i = 0;
				mask = 1;
				remain = 0xffffffff;
				while ((todo = procpars->functions &
881 882 883
//                     p_nasap[pars_ahead] &  //all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice
					       p_nasap[0] & remain)) {  // eliminate ASAP-only function
					while (!(todo & mask)) {        // skip zeros - todo will stay current (.functions will not change)
884 885 886 887
						i++;
						mask   <<= 1;
						remain <<= 1;
					}
888 889 890
// now (todo & mask) !=0
// find the right latency
					for (this_ahead = 1; (p_nasap[this_ahead] & todo & mask) && (this_ahead <= 4); this_ahead++) ;  // this_ahead==1..5
Andrey Filippov's avatar
Andrey Filippov committed
891
//          seq_frame=  (frame16 + job_ahead + this_ahead) & PARS_FRAMES_MASK;
892 893
					seq_frame =  (frame_proc + 1 - this_ahead) & PARS_FRAMES_MASK;

Andrey Filippov's avatar
Andrey Filippov committed
894 895 896 897
					dev_dbg(g_devfp_ptr,"%s port=%d todo=0x%08lx (curr=0x%08lx) frame16=%d, frame_proc=%d, seq_frame=%d, i=%d, mask=0x%08lx\n",
					        __func__, sensor_port, todo, procpars->functions, frame16, frame_proc, seq_frame, i, mask);
					dev_dbg(g_devfp_ptr,"%s port=%d %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
					        __func__, sensor_port, framepars[0].functions, framepars[1].functions, framepars[2].functions, framepars[3].functions, framepars[4].functions, framepars[5].functions, framepars[6].functions, framepars[7].functions);
898 899

					if (sensorproc->pgm_func[i]) {
Andrey Filippov's avatar
Andrey Filippov committed
900
						// NOTE: Was (frame16+job_ahead +1) & PARS_FRAMES_MASK
901 902
                        dev_dbg(g_devfp_ptr,"port= %d, Calling GENERIC pgm_func[%d], seq_frame = 0x%x, now frame = 0x%lx\n",sensor_port,i,seq_frame,thisFrameNumber(sensor_port));
                        MDP(DBGB_FSEQ,sensor_port,"Calling GENERIC pgm_func[%d],  seq_frame = 0x%x, now frame = 0x%x\n",i,seq_frame,thisFrameNumber(sensor_port))
903
						rslt = sensorproc->pgm_func[i]    (sensor_port, &(sensorproc->sensor), procpars, prevpars, seq_frame);
904 905
					} else rslt = 0;                                        // only sensor-specific function, nothing to do common to all sensors
					if ((rslt >= 0) && (sensorproc->pgm_func[i + 32])) {    // sensor - specific functions, called after the main ones
906 907
                        dev_dbg(g_devfp_ptr,"port= %d, Calling SENSOR-SPECIFIC pgm_func[%d], seq_frame = 0x%x, now frame = 0x%lx\n",sensor_port,i,seq_frame,thisFrameNumber(sensor_port));
                        MDP(DBGB_FSEQ,sensor_port,"Calling SENSOR-SPECIFIC pgm_func[%d],  seq_frame = 0x%x, now frame = 0x%x\n",i,seq_frame,thisFrameNumber(sensor_port))
Andrey Filippov's avatar
Andrey Filippov committed
908
					    rslt = sensorproc->pgm_func[i + 32] (sensor_port, &(sensorproc->sensor), procpars, prevpars, seq_frame);
909 910
					}
					if (rslt >= 0) {
911
						procpars->functions &= ~mask; // mark it done
912
					} else {
Andrey Filippov's avatar
Andrey Filippov committed
913
						dev_dbg(g_devfp_ptr,"%s port %d: Error - function result was %d\n",__func__, sensor_port, rslt);
914 915 916 917 918 919 920 921
					}
					i++;
					mask   <<= 1;
					remain <<= 1;
				}
			}
		}
	}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
922 923 924 925
}

/**
 * @brief Program image acquisition, according to the parameters changed
Andrey Filippov's avatar
Andrey Filippov committed
926
 * Called from tasklet and user (setFrameParsAtomic) and LSEEK_SENSORPROC
Mikhail Karpenko's avatar
Mikhail Karpenko committed
927
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
928
 * @param sensorproc pointer to sensor static parameters and functions
Andrey Filippov's avatar
Andrey Filippov committed
929
 * @param frame16     current hardware frame number
Mikhail Karpenko's avatar
Mikhail Karpenko committed
930 931 932 933
 * @param maxahead   maximal number of frames to program ahead of the current (make it  P_* parameter ?)
 * @return always 0 ?
 */
//TODO: "Do it later" should be the only reason not to erase todo bit
934
//#define P_CALLASAP       107 // bitmask - what functions work only in the current frame (ASAP) mode
Andrey Filippov's avatar
Andrey Filippov committed
935
void _processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
936
{
Andrey Filippov's avatar
Andrey Filippov committed
937
    frame16 &= PARS_FRAMES_MASK;
938
    if (debug_flags) {
939
        dev_dbg(g_devfp_ptr,"port= %d,  frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
940 941
        MDP(DBGB_FPPI,sensor_port,"frame16=%d, maxahead=%d\n",
                frame16, maxahead)
942
    }
Andrey Filippov's avatar
Andrey Filippov committed
943
    dev_dbg(g_devfp_ptr,"port= %d,  frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
Andrey Filippov's avatar
Andrey Filippov committed
944
    if (!sensorproc){
945
        dev_err(g_devfp_ptr,"port=%d frame16=%d sensorproc==NULL !!!! \n", sensor_port,  frame16);
Andrey Filippov's avatar
Andrey Filippov committed
946 947
        return;
    }
948 949
    // Check if master channel updated trigger parameters, schedule them to be updated
    trigSlaveUpdate(sensor_port); // that will possible schedule more parameters
950 951 952
    //    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__);
953

Andrey Filippov's avatar
Andrey Filippov committed
954
    _processParsASAP(sensor_port, sensorproc, frame16); // NC393: never gets here ? Only after _processParsSeq?
955

956
    if (debug_flags) {
957 958
        MDP(DBGB_FPPI,sensor_port,"(after first _processParsASAP),  frame16=%d, maxahead=%d\n",
                frame16, maxahead)
959
        dev_dbg(g_devfp_ptr,"port= %d (after first _processParsASAP),  frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
960
    }
961 962
    dev_dbg(g_devfp_ptr,"port= %d (after first _processParsASAP),  frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);

963 964 965
    // 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__);
Andrey Filippov's avatar
Andrey Filippov committed
966
    _processParsSeq(sensor_port, sensorproc, frame16, maxahead);
967
    if (debug_flags) {
968 969
        MDP(DBGB_FPPI,sensor_port,"(after _processParsSeq),  frame16=%d, maxahead=%d\n",
                frame16, maxahead)
970
        dev_dbg(g_devfp_ptr,"port= %d (after _processParsSeq),  frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
971
    }
972 973
    dev_dbg(g_devfp_ptr,"port= %d (after _processParsSeq),  frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);

974 975
    // 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__);
Andrey Filippov's avatar
Andrey Filippov committed
976
    _processParsASAP(sensor_port, sensorproc, frame16);
977
    if (debug_flags) {
978 979
        MDP(DBGB_FPPI,sensor_port,"(after second _processParsASAP),  frame16=%d, maxahead=%d\n",
                frame16, maxahead)
980
        dev_dbg(g_devfp_ptr,"port= %d (after second _processParsASAP),  frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
981
    }
982
    dev_dbg(g_devfp_ptr,"port= %d (after second _processParsASAP),  frame16=%d, maxahead=%d\n", sensor_port, frame16, maxahead);
983 984 985 986
    if (debug_flags)   {
        dev_dbg(g_devfp_ptr,"debug_flags= %d \n", debug_flags);
        debug_flags--;
    }
Andrey Filippov's avatar
Andrey Filippov committed
987 988 989

}

990
#if 0
Andrey Filippov's avatar
Andrey Filippov committed
991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
void processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
{
    frame16 &= PARS_FRAMES_MASK;
    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);
        return;
    }
#ifdef LOCK_BH_PROCESSPARS
    spin_lock_bh(framepars_locks[sensor_port]);
    // WARNING: CPU: 1 PID: 2329 at /home/eyesis/git/elphel393/poky/build/tmp/work-shared/elphel393/kernel-source/kernel/softirq.c:150 __local_bh_enable_ip+0xb0/0x100()
#else
    // Here we can get from both a tasklet and from LSEEK_SENSORPROC. We do not need to do this twice - if processPars() is ran by
    // somebody else - that is OK not to do it again (what about maxahead?)
    if (!spin_trylock(framepars_locks[sensor_port])) {
        dev_dbg(g_devfp_ptr,"framepars_locks[%d] is locked, we do not need to re-run it. frame16=%d maxahead=%d \n",  sensor_port,  frame16, maxahead);
        return;
    }
#endif
    _processPars(sensor_port, sensorproc, frame16, maxahead);
#ifdef    LOCK_BH_PROCESSPARS
    spin_unlock_bh(framepars_locks[sensor_port]); // removed, see above
#else
    spin_unlock(framepars_locks[sensor_port]);
#endif
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1016
}
1017
#else
1018
int processPars(int sensor_port, struct sensorproc_t * sensorproc, int frame16, int maxahead)
1019 1020 1021
{
    FLAGS_IBH
    frame16 &= PARS_FRAMES_MASK;
1022
    if (debug_flags) {
1023 1024
        MDP(DBGB_FPPT,sensor_port,"==from tasklet: frame16=%d, maxahead=%d\n",
                frame16, maxahead)
1025
        dev_dbg(g_devfp_ptr,"==from tasklet: port= %d,  frame16=%d, maxahead=%d  now=0x%lx\n", sensor_port, frame16, maxahead, getThisFrameNumber(sensor_port));
1026 1027
    }

1028 1029 1030
    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);
1031
        return -ENODEV;
1032 1033 1034 1035
    }
    LOCK_IBH(framepars_locks[sensor_port]);
    _processPars(sensor_port, sensorproc, frame16, maxahead);
    UNLOCK_IBH(framepars_locks[sensor_port]);
1036
    if (debug_flags) {
1037 1038
        MDP(DBGB_FPPT,sensor_port,"==Done from tasklet: frame16=%d, maxahead=%d\n",
                frame16, maxahead)
1039
        dev_dbg(g_devfp_ptr,"== Done from tasklet: port= %d,  frame16=%d, maxahead=%d now=0x%lx\n", sensor_port, frame16, maxahead, getThisFrameNumber(sensor_port));
1040
    }
1041
    return 0;
1042 1043
}
#endif
Andrey Filippov's avatar
Andrey Filippov committed
1044

Mikhail Karpenko's avatar
Mikhail Karpenko committed
1045
/**
Andrey Filippov's avatar
Andrey Filippov committed
1046
 * @brief schedule pgm_func to be executed for selected frame (frame16)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1047
 * @param sensor_port sensor port number (0..3)
1048
 * @param frame16 frame number (4-bit) to schedule a function for
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1049 1050
 * @param func_num function number to schedule
 */
Andrey Filippov's avatar
Andrey Filippov committed
1051
void schedule_pgm_func(int sensor_port, int frame16, int func_num)
1052
{
Andrey Filippov's avatar
Andrey Filippov committed
1053
	aframepars[sensor_port][frame16 & PARS_FRAMES_MASK].functions |= 1 << func_num;
1054
    dev_dbg(g_devfp_ptr,"func_num=%d, aframepars[%d][%d].functions=0x%08lx\n",
1055
            func_num, sensor_port, frame16, aframepars[sensor_port][frame16 & PARS_FRAMES_MASK].functions);
1056
    MDP(DBGB_FSCF,sensor_port,"func_num=%d, aframepars[%d][%d].functions=0x%08lx\n",
1057 1058
            func_num, sensor_port, frame16,aframepars[sensor_port][frame16 & PARS_FRAMES_MASK].functions)

Mikhail Karpenko's avatar
Mikhail Karpenko committed
1059 1060 1061 1062
}

/**
 * @brief schedule pgm_func to be executed for this_framepars->pars[P_FRAME] & PARS_FRAMES_MASK
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1063
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1064 1065 1066
 * @param this_framepars pointer to frame parameters structure
 * @param func_num number of function to schedule
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1067
void schedule_this_pgm_func(int sensor_port, struct framepars_t * this_framepars, int func_num)
1068
{
Andrey Filippov's avatar
Andrey Filippov committed
1069 1070
	int frame16 = this_framepars->pars[P_FRAME] & PARS_FRAMES_MASK;
	aframepars[sensor_port][frame16].functions |= 1 << func_num;
1071
    dev_dbg(g_devfp_ptr,"func_num=%d, aframepars[%d][%d].functions=0x08%lx\n",
1072
            func_num, sensor_port, frame16, aframepars[sensor_port][frame16 & PARS_FRAMES_MASK].functions);
1073
    MDP(DBGB_FSCF,sensor_port,"func_num=%d, aframepars[%d][%d].functions=0x08%lx\n",
1074
            func_num, sensor_port, frame16,aframepars[sensor_port][frame16 & PARS_FRAMES_MASK].functions)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1075 1076 1077 1078 1079
}


/**
 * @brief just return current thisFrameNumber
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1080
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1081 1082
 * @return current value of thisFrameNumber
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1083
unsigned long getThisFrameNumber(int sensor_port)
1084
{
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1085
	return thisFrameNumber(sensor_port);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1086 1087 1088 1089
}


/**
1090
 * @brief Set a single parameter to all frames (during sensor detection)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1091
 * @param sensor_port sensor port number (0..3)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1092 1093 1094 1095
 * @param numPars number of parameters to set
 * @param pars array of parameters (number/value pairs)
 * @return always 0
 */
1096 1097 1098 1099 1100
int setFrameParStatic(int sensor_port,                     ///< sensor port number (0..3)
                      unsigned long index,                 ///< parameter number
                      unsigned long val)                   ///< parameter value to set
                                                           ///< @return 0 - OK, -ERR_FRAMEPARS_BADINDEX

1101
{
1102 1103 1104 1105 1106 1107
    struct framepars_t *framepars = aframepars[sensor_port];
    int nframe;
    index &= 0xffff;  // get rid of any modifier (not applicable here)
	if (index > P_MAX_PAR) return -ERR_FRAMEPARS_BADINDEX;
    for (nframe = 0; nframe < PARS_FRAMES; nframe++) {
        framepars[nframe].pars[index] = val;
1108 1109
	}
	return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1110 1111
}

1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
/**
 * @brief Set parameters that will never change (usually after sensor discovery), other fields are supposed to be cleared
 */
int setFrameParsStatic(int sensor_port,               ///< sensor_port sensor port number (0..3)
                       int numPars,                   ///< numPars number of parameters to set
                       struct frameparspair_t * pars) ///< pars array of parameters (number/value pairs)
                                                      ///< @return always 0
{
    int npar, nframe, index;
    struct framepars_t *framepars = aframepars[sensor_port];
    for (npar = 0; npar < numPars; npar++) {
        index = pars[npar].num & 0xffff; // get rid of any modifier (not applicable here)
        if (index > P_MAX_PAR) return -ERR_FRAMEPARS_BADINDEX;
        for (nframe = 0; nframe < PARS_FRAMES; nframe++) {
            framepars[nframe].pars[index] = pars[npar].val;
        }
    }
    return 0;
}


Andrey Filippov's avatar
Andrey Filippov committed
1133 1134 1135 1136
/** Set parameters for the specified frame  (atomic, with interrupts off). Used from applications through driver write */
//TODO: Check that writes never to the future or past frame (only 6 of 8 are allowed -> 14 of 16). Have seen just_this to flood all
int setFrameParsAtomic(int sensor_port,               ///< sensor port number (0..3)
                       unsigned long frameno,         ///< absolute (full) frame number parameters should be applied to
1137
                                                      ///< frameno = 0xffffffff => use maxlatency -1, frame = 0
Andrey Filippov's avatar
Andrey Filippov committed
1138 1139 1140 1141 1142 1143
                       int maxLatency,                ///< maximal command latency (parameters should be set not less than maxLatency ahead of the current frame)
                                                      ///< maxLatency < 0 - don't check latency (i.e. only commands that are not releted to particular frames),
                                                      ///< with negative and frameno< current frame will make it current, to use with ASAP
                       int numPars,                   ///< number of parameters to set (0 is OK to just test if it is too early/too late)
                       struct frameparspair_t * pars) ///< array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number
                                                      ///< @return 0 - OK, -ERR_FRAMEPARS_TOOEARLY, -ERR_FRAMEPARS_TOOLATE
1144
{
1145
    FLAGS_IBH
1146
    int npar, nframe, res;
1147 1148
	unsigned long val, bmask, bmask32;
	int index, bindex;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1149 1150
	struct framepars_t *framepars = aframepars[sensor_port];
	unsigned long      *funcs2call =afuncs2call[sensor_port];
Andrey Filippov's avatar
Andrey Filippov committed
1151
	int findex_this, findex_prev, findex_future, frame16;
1152 1153 1154 1155 1156 1157
	if (frameno == 0xffffffff){
	    maxLatency = -1;
	    frameno = 0;
	    dev_dbg(g_devfp_ptr,"port= %d, frameno was 0xffffffff, modifying maxLatency=0x%x, frameno = 0x%08lx\n",sensor_port, maxLatency, frameno);
	}

Andrey Filippov's avatar
Andrey Filippov committed
1158 1159 1160
    findex_this =  thisFrameNumber(sensor_port) & PARS_FRAMES_MASK;
    findex_prev = (findex_this - 1)  & PARS_FRAMES_MASK;
    findex_future = (findex_this - 2)  & PARS_FRAMES_MASK; // actually - fartherst in the future??
1161 1162
	MDP(DBGB_FSFA,sensor_port,"frameno=0x%lx, findex_this=%ld (0x%lx) maxLatency=%d, numPars=%d, frameParsInitialized[%d]=%d\n",
            frameno, findex_this, thisFrameNumber(sensor_port), maxLatency, numPars, sensor_port, frameParsInitialized[sensor_port])
1163 1164 1165 1166
    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);

Andrey Filippov's avatar
Andrey Filippov committed
1167
	if (!frameParsInitialized[sensor_port]) {
1168 1169
		res = initSequencers(sensor_port); // Will call  initFramePars(); and initialize functions
		if (res <0) return res;
1170
	}
1171
	LOCK_IBH(framepars_locks[sensor_port]);
Andrey Filippov's avatar
Andrey Filippov committed
1172
	PROFILE_NOW(5); // Was 6, but no 7 in NC393
1173
	if (maxLatency >= 0) {
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1174
		if (frameno <= (thisFrameNumber(sensor_port) + maxLatency)) {
1175 1176
		    UNLOCK_IBH(framepars_locks[sensor_port]);
		    dev_dbg(g_devfp_ptr,"port=%d, ERR_FRAMEPARS_TOOLATE, frameno = 0x%x\n",sensor_port, (int)frameno);
1177
			return -ERR_FRAMEPARS_TOOLATE;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1178
		}else if (frameno >= (thisFrameNumber(sensor_port) + (PARS_FRAMES - 1))) {
1179
            UNLOCK_IBH(framepars_locks[sensor_port]);
Andrey Filippov's avatar
Andrey Filippov committed
1180
            dev_dbg(g_devfp_ptr,"port=%d, ERR_FRAMEPARS_TOOEARLY, frameno = 0x%x\n",sensor_port, (int)frameno);
1181 1182
			return -ERR_FRAMEPARS_TOOEARLY;
		}
Andrey Filippov's avatar
Andrey Filippov committed
1183 1184 1185 1186 1187 1188 1189 1190
	} else {
        dev_dbg(g_devfp_ptr,"port=%d, Using negative maxLatency, frameno = 0x%x, thisFrameNumber(%d) = 0x%x\n",
                sensor_port, (int)frameno, sensor_port, (int) thisFrameNumber(sensor_port));
        if (frameno < thisFrameNumber(sensor_port)){
            dev_dbg(g_devfp_ptr,"port=%d, Replacing earlier supplied frame number = 0x%x with the current one= 0x%x\n",
                    sensor_port, (int)frameno, (int) thisFrameNumber(sensor_port));
            frameno = thisFrameNumber(sensor_port);
        }
1191
	}
Andrey Filippov's avatar
Andrey Filippov committed
1192
	// not too late, not too early, go ahead (or maxlatency <0 - ASAP only)
1193
	for (npar = 0; npar < numPars; npar++) {
Andrey Filippov's avatar
Andrey Filippov committed
1194 1195 1196
	    dev_dbg(g_devfp_ptr,"port= %d,  --pars[%d].num=0x%lx, pars[%d].val=0x%lx\n", sensor_port, npar, pars[npar].num, npar, pars[npar].val);
        MDP(DBGB_FSFA,sensor_port,"  --pars[%d].num=0x%lx, pars[%d].val=0x%lx\n", npar, pars[npar].num, npar, pars[npar].val)

Andrey Filippov's avatar
Andrey Filippov committed
1197 1198
//    frame16=      (pars[npar].num & FRAMEPAR_GLOBALS)? -1: (frameno  & PARS_FRAMES_MASK);
		frame16 =      frameno  & PARS_FRAMES_MASK;
1199 1200 1201
		val = pars[npar].val;
		index = pars[npar].num & 0xffff;
		if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : P_MAX_PAR)) {
1202
            UNLOCK_IBH(framepars_locks[sensor_port]);
Andrey Filippov's avatar
Andrey Filippov committed
1203
            dev_dbg(g_devfp_ptr,"port=%d, ERR_FRAMEPARS_BADINDEX, frameno = 0x%x\n",sensor_port, (int)frameno);
1204 1205
			return -ERR_FRAMEPARS_BADINDEX;
		}
1206
		dev_dbg(g_devfp_ptr,"port= %d, index=0x%x, val=0x%lx", sensor_port, index, val);
1207 1208
		if (index >= FRAMEPAR_GLOBALS) {                        // ignore frame logic, set "static" parameters to frame 0
			if (pars[npar].num & FRAMEPAIR_MASK_BYTES) {    // combine new value with the old one
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1209
				val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(sensor_port,index), val);
1210
			}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1211
			GLOBALPARS(sensor_port, index) = val;
1212 1213 1214
			D5(printk(" set GLOBALPARS(0x%x)=0x%lx\n", index, val));
		} else if (pars[npar].num  & FRAMEPAIR_FRAME_FUNC) {
			funcs2call[index] = val;
1215
			dev_dbg(g_devfp_ptr,"port= %d, set funcs2call[0x%x]=0x%lx\n", sensor_port, index, val);
1216
//    } else if ((frameno !=findex_prev) && (frameno != findex_future)) { // do not write parameters in the future otherwise
Andrey Filippov's avatar
Andrey Filippov committed
1217
		} else if ((frame16 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS) == 0)) {        // do not write "JUST_THIS" parameters in the future otherwise they'll stick
1218
			if (pars[npar].num & FRAMEPAIR_MASK_BYTES) {                                            // combine new value with the old one
Andrey Filippov's avatar
Andrey Filippov committed
1219
				val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame16].pars[index], val);
1220
			}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1221
//TODO: optimize to use mask several parameters together
1222
			dev_dbg(g_devfp_ptr,"port= %d, frame16=0x%x\n", sensor_port, frame16);
Andrey Filippov's avatar
Andrey Filippov committed
1223 1224
	        MDP(DBGB_FSFA,sensor_port,"framepars[%d].pars[%d]=0x%lx =?= val = 0x%lx, pars[%d].num=0x%08lx & 0x%08x\n",
	                frame16, index, framepars[frame16].pars[index], val, npar, pars[npar].num, FRAMEPAIR_FORCE_NEW)
Andrey Filippov's avatar
Andrey Filippov committed
1225
			if ((framepars[frame16].pars[index] != val) || (pars[npar].num & FRAMEPAIR_FORCE_NEW)) {
1226 1227 1228
				bmask =   1 << (index & 31);
				bindex = index >> 5;
				bmask32 = 1 << bindex;
1229
//   Set this parameter for specified frame
Andrey Filippov's avatar
Andrey Filippov committed
1230 1231 1232 1233
				framepars[frame16].pars[index]       = val;
				framepars[frame16].mod[bindex]      |= bmask;
				framepars[frame16].mod32            |= bmask32;
				framepars[frame16].functions        |= funcs2call[index]; //Mark which functions will be needed to process the parameters
Andrey Filippov's avatar
Andrey Filippov committed
1234 1235 1236 1237 1238
				dev_dbg(g_devfp_ptr,"port= %d,  bindex=0x%x, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",
				        sensor_port, bindex, bmask, bmask32, framepars[frame16].functions);
                MDP(DBGB_FSFA,sensor_port,"bindex=0x%x, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",
                        bindex, bmask, bmask32, framepars[frame16].functions)

1239
// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS)
1240
				if ((pars[npar].num & FRAMEPAIR_JUST_THIS) == 0) {
Andrey Filippov's avatar
Andrey Filippov committed
1241 1242 1243
					dev_dbg(g_devfp_ptr,"port= %d,       ---   setting next frames, pars[%d].num=0x%lx\n",sensor_port,npar,pars[npar].num);
                    MDP(DBGB_FSFA,sensor_port,"    ---   setting next frames, pars[%d].num=0x%lx\n",npar,pars[npar].num)

Andrey Filippov's avatar
Andrey Filippov committed
1244
					for (nframe = (frame16 + 1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe = (nframe + 1) & PARS_FRAMES_MASK) {
1245
						framepars[nframe].pars[index] = val;
1246 1247
						dev_dbg(g_devfp_ptr,"framepars[%d].pars[%d] <- 0x%08lx  ", nframe, index, val);
	                    MDP(DBGB_FSFA,sensor_port,"framepars[%d].pars[%d] <- 0x%08lx  ", nframe, index, val)
1248
					}
Andrey Filippov's avatar
Andrey Filippov committed
1249
					frame16 = (frame16 - 1) & PARS_FRAMES_MASK; // for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
Andrey Filippov's avatar
Andrey Filippov committed
1250 1251
                    dev_dbg(g_devfp_ptr,"\n");
	                MDP(DBGB_FSFA,sensor_port,"%s\n","")
Andrey Filippov's avatar
Andrey Filippov committed
1252
//					D5(printk("\n"));
1253
				}
1254 1255
// Mark this parameter in all previous frames as "modified since"
// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
Andrey Filippov's avatar
Andrey Filippov committed
1256
				for (nframe = frame16; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { //NOTE: frame16 is modified here
1257 1258
					framepars[nframe].modsince[bindex] |= bmask;
					framepars[nframe].modsince32       |= bmask32;
Andrey Filippov's avatar
Andrey Filippov committed
1259 1260
	                MDP(DBGB_FSFA,sensor_port,"framepars[%d].modsince[%d] |= 0x%08x, framepars[%d].modsince32 |= 0x%08x  ",
	                        nframe, bindex, bmask, nframe, bmask32)
1261
				}
Andrey Filippov's avatar
Andrey Filippov committed
1262
                MDP(DBGB_FSFA,sensor_port,"%s\n","")
1263
			}
1264
		} else { // error - trying to write "just this" to the "future" - that would stick if allowed
1265
            UNLOCK_IBH(framepars_locks[sensor_port]);
Andrey Filippov's avatar
Andrey Filippov committed
1266 1267
            dev_dbg(g_devfp_ptr,"port= %d, Tried to write JUST_THIS parameter (0x%lx) too far in the future", sensor_port, pars[npar].num);
            dev_err(g_devfp_ptr,"port= %d, Tried to write JUST_THIS parameter (0x%lx) too far in the future", sensor_port, pars[npar].num);
1268 1269 1270
			return -ERR_FRAMEPARS_TOOEARLY;
		}
	}
1271 1272
// 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
1273 1274 1275

// ASAP - needed to set with sequencer is stopped!

1276
// Changed to all (don't care about uncertainty - they will trigger only if it is too late or during sensor detection/initialization)
1277
	debug_flags = 20; // enable debug print several times
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1278
	if (!(get_globalParam(sensor_port, G_TASKLET_CTL) & (1 << TASKLET_CTL_NOSAME))) {
Andrey Filippov's avatar
Andrey Filippov committed
1279 1280 1281 1282
//    _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
1283 1284
		MDP(DBGB_FSFA,sensor_port,"G_TASKLET_CTL -> 0x%x\n",
	            (int) get_globalParam(sensor_port, G_TASKLET_CTL))
Andrey Filippov's avatar
Andrey Filippov committed
1285
        _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
1286 1287 1288
        MDP(DBGB_FSFA,sensor_port,"kthread _processPars( .., 0x%x) DONE\n",
                thisFrameNumber(sensor_port))
        dev_dbg(g_devfp_ptr,"kthread _processPars(%d, .., 0x%lx) DONE\n",sensor_port, thisFrameNumber(sensor_port));
Andrey Filippov's avatar
Andrey Filippov committed
1289 1290
	} else {
        dev_dbg(g_devfp_ptr,"kthread: NOT calling _processPars(%d, .., 0x%lx) DONE\n",sensor_port, thisFrameNumber(sensor_port));
1291
	}
Andrey Filippov's avatar
Andrey Filippov committed
1292
	PROFILE_NOW(6); // 7); // no (7) in NC393
1293
    UNLOCK_IBH(framepars_locks[sensor_port]);
1294
	return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1295 1296
}
//#define FRAMEPAIR_JUST_THIS     0x40000 // write only to this frame, don't propagate
1297
// (like "single frame" - compressor, sensor) first write "stop", then - "single" with FRAMEPAIR_JUST_THIS
Andrey Filippov's avatar
Andrey Filippov committed
1298 1299

/** Set a single output (calculated) parameter for the frame referenced by this_framepars structure.
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1300
 * Schedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in mindex
Andrey Filippov's avatar
Andrey Filippov committed
1301 1302 1303 1304 1305 1306
 * Should only be called when IRQ (just bh preferrably) is off and lock on framepars_locks[sensor_port] (all pgm_* have that)  */
int setFramePar(int sensor_port,                     ///< sensor port number (0..3)
                struct framepars_t * this_framepars, ///< pointer to the current parameters structure
                unsigned long mindex,                ///< parameter number (with optional modifiers in high bits)
                unsigned long val)                   ///< parameter value to set
                                                     ///< @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
1307
{
Andrey Filippov's avatar
Andrey Filippov committed
1308
	int frame16 =  (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
Andrey Filippov's avatar
Andrey Filippov committed
1309
	//  unsigned long flags; should only be called when interruypts disabled and lock obtained
1310 1311
	int nframe;
	unsigned long bmask, bmask32, bindex;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1312
	int findex_this =  thisFrameNumber(sensor_port) & PARS_FRAMES_MASK;
1313 1314 1315
	int findex_prev = (findex_this - 1)  & PARS_FRAMES_MASK;
	int findex_future = (findex_this - 2)  & PARS_FRAMES_MASK;
	int index =    mindex & 0xffff;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1316 1317
	struct framepars_t *framepars = aframepars[sensor_port];
	unsigned long      *funcs2call =afuncs2call[sensor_port];
1318

1319 1320 1321 1322 1323
	dev_dbg(g_devfp_ptr, "port=%d, thisFrameNumber=0x%lx frame16=%d index= %d (0x%lx), val=0x%lx\n",
	        sensor_port, thisFrameNumber(sensor_port), frame16, index, mindex, val);
    MDP(DBGB_FSFP,sensor_port,"thisFrameNumber=0x%lx frame16=%d index= %d (0x%lx), val=0x%lx\n",
            thisFrameNumber(sensor_port), frame16, index, mindex, val)

Andrey Filippov's avatar
Andrey Filippov committed
1324

Mikhail Karpenko's avatar
Mikhail Karpenko committed
1325
//  if (index > P_MAX_PAR) {
1326 1327 1328
	if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : P_MAX_PAR)) {
		return -ERR_FRAMEPARS_BADINDEX;
	}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1329
//TODO: optimize to use mask several parameters together
1330 1331
	if (index >= FRAMEPAR_GLOBALS) {                // ignore frame logic, set "static" parameters to frame 0
		if (mindex & FRAMEPAIR_MASK_BYTES) {    // combine new value with the old one
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1332
			val = FRAMEPAIR_FRAME_MASK_NEW(mindex, GLOBALPARS(sensor_port,index), val);
1333
		}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1334
		GLOBALPARS(sensor_port,index) = val;
1335
	} else if (mindex  & FRAMEPAIR_FRAME_FUNC) { // write to func_proc[] instead
1336
		funcs2call[index] = val;
Andrey Filippov's avatar
Andrey Filippov committed
1337
	} else if ((frame16 != findex_future) || ((mindex & FRAMEPAIR_JUST_THIS) == 0)) {        // do not write "JUST_THIS" parameters in the future otherwise they'll stick
1338
		if (mindex & FRAMEPAIR_MASK_BYTES) {                                            // combine new value with the old one
Andrey Filippov's avatar
Andrey Filippov committed
1339
			val = FRAMEPAIR_FRAME_MASK_NEW(mindex, framepars[frame16].pars[index], val);
1340 1341 1342
		    dev_dbg(g_devfp_ptr, "val updated to 0x%lx\n", val);
		    MDP(DBGB_FSFP,sensor_port,"val updated to 0x%lx\n", val)

1343
		}
Andrey Filippov's avatar
Andrey Filippov committed
1344
		if ((framepars[frame16].pars[index] != val) || (mindex & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))) {
1345 1346 1347
			bmask =   1 << (index & 31);
			bindex = index >> 5;
			bmask32 = 1 << bindex;
1348
//   Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED!
Andrey Filippov's avatar
Andrey Filippov committed
1349 1350 1351
			framepars[frame16].pars[index]       = val;
			framepars[frame16].mod[bindex]      |= bmask;
			framepars[frame16].mod32            |= bmask32;
1352
			if (mindex & FRAMEPAIR_FORCE_PROC) {
Andrey Filippov's avatar
Andrey Filippov committed
1353
				framepars[frame16].functions        |= funcs2call[index]; //Mark which functions will be needed to process the parameters
1354
			}
1355 1356 1357 1358
			dev_dbg(g_devfp_ptr, " bindex=0x%lx, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",
			        bindex, bmask, bmask32, framepars[frame16].functions);
            MDP(DBGB_FSFP,sensor_port," bindex=0x%lx, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",
                    bindex, bmask, bmask32, framepars[frame16].functions)
1359
// Write parameter to the next frames up to the one that have the same parameter already modified
1360
			if ((mindex & FRAMEPAIR_JUST_THIS) == 0) {
1361
//				MDF8(printk(":        ---   setting next frames"));
Andrey Filippov's avatar
Andrey Filippov committed
1362 1363
//        for (nframe=(frame16+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[frame16].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) {
				for (nframe = (frame16 + 1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe = (nframe + 1) & PARS_FRAMES_MASK) {
1364
					framepars[nframe].pars[index] = val;
1365 1366
//					D8(printk(" %d", nframe));
				    MDP(DBGB_FSFV,sensor_port,"framepars[%d].pars[%d] <- 0x%08x  ", nframe, index, val)
1367
				}
Andrey Filippov's avatar
Andrey Filippov committed
1368
				frame16 = (frame16 - 1) & PARS_FRAMES_MASK; // for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
1369
                MDP(DBGB_FSFV,sensor_port,"%s\n","")
1370
			}
Andrey Filippov's avatar
Andrey Filippov committed
1371
//      dev_dbg(g_devfp_ptr,"%s \n",__func__);
1372 1373
// Mark this parameter in all previous frames as "modified since"
// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
1374
//			MDF8(printk(":        >>>   setting modsince"));
Andrey Filippov's avatar
Andrey Filippov committed
1375 1376
//    for (nframe=(frame16-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) {
			for (nframe = frame16; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { //NOTE: frame16 is modified here
1377 1378
				framepars[nframe].modsince[bindex] |= bmask;
				framepars[nframe].modsince32       |= bmask32;
1379 1380 1381
                MDP(DBGB_FSFV,sensor_port,"framepars[%d].modsince[%d] |= 0x%08x, framepars[%d].modsince32 |= 0x%08x  ",
                        nframe, bindex, bmask, nframe, bmask32)
//				D8(printk(" %d", nframe));
1382
			}
1383 1384
            MDP(DBGB_FSFV,sensor_port,"%s\n", "")
//			D8(printk("\n"));
1385
		}
1386
	} else { // error - trying to write "just this" to the "future" - that would stick if allowed
Andrey Filippov's avatar
Andrey Filippov committed
1387
        dev_dbg(g_devfp_ptr, "Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex);
1388
		dev_err(g_devfp_ptr, "Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex);
1389
        MDP(DBGB_FSFP,sensor_port,"Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex)
1390 1391 1392
		return -ERR_FRAMEPARS_TOOEARLY;
	}
	return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1393
}
Andrey Filippov's avatar
Andrey Filippov committed
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404

/** Set a single output (calculated) parameter for the frame referenced by this_framepars structure from the user program
 * Obtain lock, disable IRQ and  call setFramePar
 * Schedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in mindex
 * Should only be called when IRQ (just bh preferrably) is off and lock on framepars_locks[sensor_port] (all pgm_* have that)  */
int setFrameParLocked(int sensor_port,                     ///< sensor port number (0..3)
                      struct framepars_t * this_framepars, ///< pointer to the current parameters structure
                      unsigned long mindex,                ///< parameter number (with optional modifiers in high bits)
                      unsigned long val)                   ///< parameter value to set
                                                           ///< @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
{
1405
    FLAGS_IBH
Andrey Filippov's avatar
Andrey Filippov committed
1406
    int rslt;
1407
    LOCK_IBH(framepars_locks[sensor_port]);
1408
    MDP(DBGB_FSFP,sensor_port,"mindex=0x%08lx, val=0x%08lx", mindex,val)
Andrey Filippov's avatar
Andrey Filippov committed
1409 1410 1411 1412 1413
    rslt =  setFramePar(sensor_port,    // sensor port number (0..3)
                        this_framepars, // pointer to the current parameters structure
                        mindex,         // parameter number (with optional modifiers in high bits)
                        val);           // parameter value to set
                                        // @return 0 - OK, -ERR_FRAMEPARS_BADINDEX
1414
    UNLOCK_IBH(framepars_locks[sensor_port]);
1415
    MDP(DBGB_FSFP,sensor_port,"DONE: mindex=0x%08lx, val=0x%08lx", mindex,val)
Andrey Filippov's avatar
Andrey Filippov committed
1416 1417 1418
    return rslt;
}

1419 1420 1421
void trigSlaveUpdate(int sensor_port)  ///< sensor port number (0..3)
{
    struct framepars_t *framepars =  aframepars[sensor_port];
1422
    struct frameparspair_t pars_to_update[8];
1423 1424 1425 1426 1427
    int nupdate = 0;
    int updated_period = 0;
    while (common_pars->updated[sensor_port]) {
        dev_dbg(g_devfp_ptr,"port= %d,  thisFrameNumber[%d] = %d\n", sensor_port, sensor_port, (int) thisFrameNumber(sensor_port));
        common_pars->updated[sensor_port] = 0;
1428
        if (pars_to_update[nupdate  ].num != P_TRIG_PERIOD){ // updated any other parameter - treat as period is updated (make sure it will not trigger)
1429 1430 1431 1432 1433 1434 1435 1436 1437
            updated_period = FRAMEPAIR_FORCE_PROC;
        }
        pars_to_update[nupdate  ].num= P_TRIG_MASTER ;                  pars_to_update[nupdate++].val = common_pars->master_chn;
        pars_to_update[nupdate  ].num= P_TRIG_PERIOD | updated_period ; pars_to_update[nupdate++].val = common_pars->trig_period;
        pars_to_update[nupdate  ].num= P_TRIG_BITLENGTH ;               pars_to_update[nupdate++].val = common_pars->trig_bitlength;
        pars_to_update[nupdate  ].num= P_EXTERN_TIMESTAMP ;             pars_to_update[nupdate++].val = common_pars->extern_timestamp;
        pars_to_update[nupdate  ].num= P_XMIT_TIMESTAMP ;               pars_to_update[nupdate++].val = common_pars->xmit_timestamp;
        pars_to_update[nupdate  ].num= P_TRIG_CONDITION ;               pars_to_update[nupdate++].val = common_pars->trig_condition;
        pars_to_update[nupdate  ].num= P_TRIG_OUT ;                     pars_to_update[nupdate++].val = common_pars->trig_out;
1438
        pars_to_update[nupdate  ].num= P_TRIG ;                         pars_to_update[nupdate++].val = common_pars->trig_mode;
1439 1440 1441 1442 1443 1444 1445
//        if (nupdate)  setFramePars(sensor_port, &framepars[frame16], nupdate, pars_to_update);  // save changes, schedule functions
        if (nupdate)  setFramePars(sensor_port, &framepars[thisFrameNumber(sensor_port)], nupdate, pars_to_update);  // save changes, schedule functions

    }
}


Andrey Filippov's avatar
Andrey Filippov committed
1446
/** Set multiple output (calculated) parameters for the frame referenced by this_framepars structure.
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1447
 * Schedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in the particular parameter index
Andrey Filippov's avatar
Andrey Filippov committed
1448 1449 1450 1451 1452 1453 1454 1455
 * Called from tasklets (while executing (*_)pgm_* functions
 * Should only be called when IRQ (just bh preferrably) is off and lock on framepars_locks[sensor_port] (all pgm_* have that)  */

int setFramePars(int sensor_port,                     ///< sensor port number (0..3)
                 struct framepars_t * this_framepars, ///< this_framepars pointer to the current parameters structure
                 int numPars,                         ///< number of parameters to set
                 struct frameparspair_t * pars)       ///<array of parameters (number/value pairs). Parameter numbers accept modifiers
                                                      ///< @return  0 - OK, -ERR_FRAMEPARS_BADINDEX
1456
{
Andrey Filippov's avatar
Andrey Filippov committed
1457
	int frame16;
1458
//	unsigned long flags; should only be called when interrupts disabled and lock obtained
1459 1460 1461
	int npar, nframe;
	unsigned long val, bmask, bmask32;
	int index, bindex;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1462
	int findex_this =  thisFrameNumber(sensor_port) & PARS_FRAMES_MASK;
1463 1464
	int findex_prev = (findex_this - 1)  & PARS_FRAMES_MASK;
	int findex_future = (findex_this - 2)  & PARS_FRAMES_MASK;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1465 1466
	struct framepars_t *framepars = aframepars[sensor_port];
	unsigned long      *funcs2call =afuncs2call[sensor_port];
1467

1468 1469 1470
	dev_dbg(g_devfp_ptr, "port= %d, this_framepars=0x%x numPars=%d\n", sensor_port, (int)this_framepars, numPars);
    MDP(DBGB_FSFP,sensor_port,"this_framepars=0x%x numPars=%d\n", (int)this_framepars, numPars)

1471
	for (npar = 0; npar < numPars; npar++) {
Andrey Filippov's avatar
Andrey Filippov committed
1472
		frame16 = (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK;
1473 1474
		val = pars[npar].val;
		index = pars[npar].num & 0xffff;
1475
		dev_dbg(g_devfp_ptr, ":    ---   frame16=%d index=%d (0x%x) val=0x%x, findex_future = 0x%x\n", frame16, index, (int)pars[npar].num, (int)val, findex_future);
1476
	    MDP(DBGB_FSFV,sensor_port,"  ---   frame16=%d index=%d (0x%x) val=0x%x\n", frame16, index, (int)pars[npar].num, (int)val)
1477
		// remark: code below looks similar to setFramePar function, call it instead
1478
		if (index > ((index >= FRAMEPAR_GLOBALS) ? (P_MAX_GPAR + FRAMEPAR_GLOBALS) : P_MAX_PAR)) {
1479
			dev_err(g_devfp_ptr, " bad index=%d > %d\n", index, P_MAX_PAR);
1480 1481
			return -ERR_FRAMEPARS_BADINDEX;
		}
1482 1483
		if (index >= FRAMEPAR_GLOBALS) {                        // ignore frame logic, set "static" parameters to frame 0
			if (pars[npar].num & FRAMEPAIR_MASK_BYTES) {    // combine new value with the old one
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1484
				val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(sensor_port,index), val);
1485
			}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1486
			GLOBALPARS(sensor_port,index) = val;
1487 1488
		} else if (pars[npar].num  & FRAMEPAIR_FRAME_FUNC) {
			funcs2call[index] = val;
Andrey Filippov's avatar
Andrey Filippov committed
1489
		} else if ((frame16 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS) == 0)) {        // do not write "JUST_THIS" parameters in the future otherwise they'll stick
1490
			if (pars[npar].num & FRAMEPAIR_MASK_BYTES) {                                            // combine new value with the old one
Andrey Filippov's avatar
Andrey Filippov committed
1491
				val = FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame16].pars[index], val);
1492
			}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1493
//TODO: optimize to use mask several parameters together
1494
	        dev_dbg(g_devfp_ptr, "{%d}:  framepars[%d].pars[0x%x] = 0x%x, val=0x%x\n", sensor_port, frame16, index, (int) framepars[frame16].pars[index], (int)val);
Andrey Filippov's avatar
Andrey Filippov committed
1495
			if ((framepars[frame16].pars[index] != val) || (pars[npar].num & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))) {
1496 1497 1498
				bmask =   1 << (index & 31);
				bindex = index >> 5;
				bmask32 = 1 << bindex;
1499
//   Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED!
Andrey Filippov's avatar
Andrey Filippov committed
1500 1501 1502
				framepars[frame16].pars[index]       = val;
				framepars[frame16].mod[bindex]      |= bmask;
				framepars[frame16].mod32            |= bmask32;
1503
				if (pars[npar].num & FRAMEPAIR_FORCE_PROC) {
Andrey Filippov's avatar
Andrey Filippov committed
1504
					framepars[frame16].functions        |= funcs2call[index]; //Mark which functions will be needed to process the parameters
1505
				}
1506
	            dev_dbg(g_devfp_ptr, "{%d}:  framepars[%d].functions=0x%x\n", sensor_port, frame16, (int) framepars[frame16].functions);
1507
// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS)
1508
				if ((pars[npar].num & FRAMEPAIR_JUST_THIS) == 0) {
1509
//					MDF8(printk(":        ---   setting next frames"));
Andrey Filippov's avatar
Andrey Filippov committed
1510
					for (nframe = (frame16 + 1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe = (nframe + 1) & PARS_FRAMES_MASK) {
1511
						framepars[nframe].pars[index] = val;
1512 1513 1514
//                        D8(printk(" %d", nframe));
	                    MDP(DBGB_FSFV,sensor_port,"framepars[%d].pars[%d] <- 0x%08x  ", nframe, index, val)

1515
					}
Andrey Filippov's avatar
Andrey Filippov committed
1516
					frame16 = (frame16 - 1) & PARS_FRAMES_MASK; // for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does
1517 1518
                    MDP(DBGB_FSFV,sensor_port,"%s\n", "")
//					D8(printk("\n"));
1519
				}
1520 1521
// Mark this parameter in all previous frames as "modified since"
// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them
Andrey Filippov's avatar
Andrey Filippov committed
1522 1523
//      for (nframe=(frame16-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) {
				for (nframe = frame16; nframe != findex_future; nframe = (nframe - 1) & PARS_FRAMES_MASK) { //NOTE: frame16 is modified here
1524 1525
					framepars[nframe].modsince[bindex] |= bmask;
					framepars[nframe].modsince32       |= bmask32;
1526 1527
	                MDP(DBGB_FSFV,sensor_port,"framepars[%d].modsince[%d] |= 0x%08x, framepars[%d].modsince32 |= 0x%08x  ",
	                        nframe, bindex, bmask, nframe, bmask32)
1528
				}
1529
                MDP(DBGB_FSFV,sensor_port,"%s\n", "")
1530
			}
1531
		} else { // error - trying to write "just this" to the "future" - that would stick if allowed
1532
			dev_err(g_devfp_ptr, "Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num);
1533 1534 1535 1536
			return -ERR_FRAMEPARS_TOOEARLY;
		}
	}
	return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1537 1538
}

1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
//TODO: make some parameters readonly (prohibited from modification from the userland)
// File operations:
// open, release - nop
// read - none
// write -> setFrameParsAtomic (first 4 bytes - absolute frame number, next 4 bytes - latency, then each 8 bytes - index/value)
// can use current file pointer or special indexes (0x****ff01 - set frame number, 0x****ff02 - set latency) that should come before actual parameters
// file pointer - absolute frame number
// lseek (SEEK_SET, value) - set absolute frame number
// lseek (SEEK_CUR, value) - set frame number relative to the current frame number (thisFrameNumber),
// lseek (SEEK_CUR, 0)     - (used by ftell()) also modifies file pointer - set it to thisFrameNumber,
// lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
// lseek (SEEK_END, value >  0) - execute commands, do not modify file pointer (and actually use it - frame number the command applies to)
// mmap (should be used read only)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1552 1553

static struct file_operations framepars_fops = {
1554 1555 1556 1557 1558 1559
	owner:    THIS_MODULE,
	llseek:   framepars_lseek,
	write:    framepars_write,
	open:     framepars_open,
	mmap:     framepars_mmap,
	release:  framepars_release
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1560 1561 1562 1563 1564 1565 1566 1567
};

/**
 * @brief Driver OPEN method
 * @param inode  inode
 * @param filp   file pointer
 * @return OK - 0, -EINVAL for wrong minor
 */
1568 1569 1570 1571 1572 1573 1574 1575
int framepars_open(struct inode *inode, struct file *filp)
{
	int res;
	struct framepars_pd * privData;
	privData = (struct framepars_pd*)kmalloc(sizeof(struct framepars_pd), GFP_KERNEL);
	if (!privData) return -ENOMEM;
	filp->private_data = privData;
	privData->minor = MINOR(inode->i_rdev);
1576
	dev_dbg(g_devfp_ptr,"minor=0x%x\n", privData->minor);
1577
	switch (privData->minor) {
1578 1579 1580 1581
	case  DEV393_MINOR(DEV393_FRAMEPARS0):
	case  DEV393_MINOR(DEV393_FRAMEPARS1):
	case  DEV393_MINOR(DEV393_FRAMEPARS2):
	case  DEV393_MINOR(DEV393_FRAMEPARS3):
1582
	    MDP(DBGB_FFOP,privData->minor-DEV393_MINOR(DEV393_FRAMEPARS0),"minor=0x%x\n",privData->minor)
1583 1584 1585 1586 1587 1588 1589
		inode->i_size = 0; //or return 8 - number of frame pages?
		return 0;
	default:
		kfree(filp->private_data); // already allocated
		return -EINVAL;
	}
	return res;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1590 1591 1592 1593 1594 1595 1596 1597
}

/**
 * @brief Driver RELEASE method
 * @param inode  inode
 * @param filp   file pointer
 * @return OK - 0, -EINVAL for wrong minor
 */
1598 1599 1600 1601 1602
int framepars_release(struct inode *inode, struct file *filp)
{
	int res = 0;
	int p = MINOR(inode->i_rdev);

Andrey Filippov's avatar
Andrey Filippov committed
1603
	dev_dbg(g_devfp_ptr,"%s : minor=0x%x\n",__func__, p);
1604
	switch ( p ) {
1605 1606 1607 1608
	case  DEV393_MINOR(DEV393_FRAMEPARS0):
	case  DEV393_MINOR(DEV393_FRAMEPARS1):
	case  DEV393_MINOR(DEV393_FRAMEPARS2):
	case  DEV393_MINOR(DEV393_FRAMEPARS3):
1609
	    MDP(DBGB_FFOP,p-DEV393_MINOR(DEV393_FRAMEPARS0),"minor=0x%x\n",p)
1610 1611 1612 1613 1614 1615
		break;
	default:
		return -EINVAL; //! do not need to free anything - "wrong number"
	}
	kfree(filp->private_data);
	return res;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1616 1617 1618 1619 1620 1621 1622 1623 1624 1625
}

/**
 * @brief Driver LSEEK  method (and execute commands)
 * - lseek (SEEK_SET, value) - set absolute frame number
 * - lseek (SEEK_CUR, value) - set frame number relative to the current frame number (thisFrameNumber),
 * - lseek (SEEK_CUR, 0)     - (used by ftell()) DOES NOT modify file pointer, returns thisFrameNumber,
 * - lseek (SEEK_END, value <= 0) - do nothing?, do not modify file pointer
 * - lseek (SEEK_END, value >  0) - execute commands, do not modify file pointer (and actually use it - frame number the command applies to)
 * - no commands yet
1626 1627
 * @param file
 * @param offset
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1628 1629 1630
 * @param orig SEEK_SET, SEEK_CUR or SEEK_SET END
 * @return file position (absolute frame number)
 */
1631 1632 1633
loff_t framepars_lseek(struct file * file, loff_t offset, int orig)
{
	unsigned long target_frame;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1634
	struct framepars_pd * privData = (struct framepars_pd*) file -> private_data;
1635
	int sensor_port = privData -> minor - DEV393_MINOR(DEV393_FRAMEPARS0);
1636
    sec_usec_t sec_usec;
1637
    int res;
1638
//	struct framepars_t *framepars = aframepars[sensor_port];
1639
    dev_dbg(g_devfp_ptr, "(framepars_lseek)  offset=0x%x, orig=0x%x, sensor_port = %d\n", (int)offset, (int)orig, sensor_port);
1640
    MDP(DBGB_FFOP, sensor_port, "(framepars_lseek)  offset=0x%x, orig=0x%x\n", (int)offset, (int)orig)
1641

1642 1643 1644 1645 1646
	switch (orig) {
	case SEEK_SET:
		file->f_pos = offset;
		break;
	case SEEK_CUR:
1647 1648
		if (offset == 0) return getThisFrameNumber(sensor_port);   // do not modify frame number
		file->f_pos = getThisFrameNumber(sensor_port) + offset;    // modifies frame number, but it is better to use absolute SEEK SET
1649 1650 1651 1652 1653
		break;
	case SEEK_END:
		if (offset <= 0) {
			break;
		} else if (offset >= LSEEK_FRAME_WAIT_REL) {
1654
			if (offset >= LSEEK_FRAME_WAIT_ABS) target_frame = offset - LSEEK_FRAME_WAIT_ABS;       // Wait for absolute frame number
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1655
			else target_frame = getThisFrameNumber(sensor_port) + offset - LSEEK_FRAME_WAIT_REL;
1656
			// Skip 0..255 frames
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1657
//			wait_event_interruptible (framepars_wait_queue, getThisFrameNumber()>=target_frame);
1658
		    dev_dbg(g_devfp_ptr, "getThisFrameNumber(%d) == 0x%x, target_frame = 0x%x\n", sensor_port, (int) getThisFrameNumber(sensor_port), (int)target_frame);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1659
			wait_event_interruptible(aframepars_wait_queue[sensor_port], getThisFrameNumber(sensor_port) >= target_frame);
1660
            dev_dbg(g_devfp_ptr, "getThisFrameNumber(%d) == 0x%x\n", sensor_port, (int) getThisFrameNumber(sensor_port));
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1661

Mikhail Karpenko's avatar
Mikhail Karpenko committed
1662
//       if (getThisFrameNumber()<target_frame) wait_event_interruptible (framepars_wait_queue,getThisFrameNumber()>=target_frame);
1663
			return getThisFrameNumber(sensor_port);    // Does not modify current frame pointer? lseek (,0,SEEK_CUR) anyway returns getThisFrameNumber()
1664 1665
		} else {                                //! Other lseek commands
			switch (offset & ~0x1f) {
1666
			case  LSEEK_DAEMON_FRAME:       // wait the daemon enabled and a new frame interrupt (sensor frame sync)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1667
				wait_event_interruptible(aframepars_wait_queue[sensor_port], get_imageParamsThis(sensor_port, P_DAEMON_EN) & (1 << (offset & 0x1f)));
1668 1669 1670 1671 1672
				break;
			default:
				switch (offset) {
				case LSEEK_GET_FPGA_TIME:
					//X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS), GLOBALPARS(G_MICROSECONDS) );
1673 1674
                    if (!get_fpga_rtc(&sec_usec))
                        return - ENODEV;
1675 1676 1677
                    GLOBALPARS(sensor_port,G_SECONDS) =      sec_usec.sec;
                    GLOBALPARS(sensor_port,G_MICROSECONDS) = sec_usec.usec;
                    dev_dbg(g_devfp_ptr, "LSEEK_GET_FPGA_TIME: sec=%ld, usec=%ld\n", sec_usec.sec, sec_usec.usec);
1678
					break;
1679
				case LSEEK_SET_FPGA_TIME: // better to use write, not lseek to set FPGA time
1680
					//X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) );
1681 1682
                    sec_usec.sec =  GLOBALPARS(sensor_port,G_SECONDS);
                    sec_usec.usec = GLOBALPARS(sensor_port,G_MICROSECONDS);
1683 1684 1685 1686
                    res = set_fpga_rtc(sec_usec);
                    if (res <0){
                        return - ENODEV;
                    }
1687
                    dev_dbg(g_devfp_ptr, "LSEEK_SET_FPGA_TIME: sec=%ld, usec=%ld\n", sec_usec.sec, sec_usec.usec);
1688
					break;
1689
				case LSEEK_FRAMEPARS_INIT:      // reset hardware sequencers, init framepars structure
1690
				    dev_dbg(g_devfp_ptr, "LSEEK_FRAMEPARS_INIT\n");
1691
					initGlobalPars(sensor_port);       // reset all global parameters but the first 32
1692 1693
					res = initSequencers(sensor_port);
					if (res <0) return res;
1694
					break;
1695
				case LSEEK_FRAME_RESET: // reset absolute frame number to avoid integer frame number overflow
1696
                    dev_dbg(g_devfp_ptr, "LSEEK_FRAME_RESET\n");
Andrey Filippov's avatar
Andrey Filippov committed
1697
					resetFrameNumber(sensor_port, 0, 0 ); // just high bits, do not reset hardware
1698
					break;
1699
				case LSEEK_SENSORPROC:                  // process modified parameters in frame 0 (to start sensor detection)
1700 1701
				    dev_dbg(g_devfp_ptr, "LSEEK_SENSORPROC: aframepars[%d][0].functions=0x%08lx\n",
				            sensor_port, aframepars[sensor_port][0].functions);
1702 1703
					res = processPars(sensor_port, &asensorproc[sensor_port], 0, PARS_FRAMES);  //frame0, all 8 frames (maxAhead==8)
					if (res <0) return res;
1704
					break;
1705
				case LSEEK_DMA_INIT:                    // initialize ETRAX DMA (normally done in sensor_common.c at driver init
1706
				    dev_dbg(g_devfp_ptr, "LSEEK_DMA_INIT\n");
1707
				    trigger_restart  (); // LSEEK_DMA_INIT is unused
1708 1709
					//x313_dma_init();
					break;
1710
				case LSEEK_DMA_STOP: // stop DMA
1711
				    dev_dbg(g_devfp_ptr, "LSEEK_DMA_STOP\n");
1712
					//x313_dma_stop();           //
1713
					break;
1714
				case LSEEK_DMA_START: // start DMA
1715
				    dev_dbg(g_devfp_ptr, "LSEEK_DMA_START\n");
1716
					//x313_dma_start();          //
1717
					break;
1718
				case LSEEK_COMPRESSOR_RESET: // reset compressor and buffer pointers
1719
				    dev_dbg(g_devfp_ptr, "LSEEK_COMPRESSOR_RESET\n");
1720 1721
					//reset_compressor();
					break;
1722
				case LSEEK_INTERRUPT_OFF: // disable camera interrupts
1723
				    dev_dbg(g_devfp_ptr, "LSEEK_INTERRUPT_OFF\n");
Andrey Filippov's avatar
Andrey Filippov committed
1724 1725
//					compressor_interrupts(0,sensor_port);
                    sensor_interrupts(0,sensor_port);
1726
					break;
1727
				case LSEEK_INTERRUPT_ON: // enable camera interrupts
1728
				    dev_dbg(g_devfp_ptr, "LSEEK_INTERRUPT_ON\n");
Andrey Filippov's avatar
Andrey Filippov committed
1729
					sensor_interrupts(1,sensor_port);
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739
					break;
				}
			}
			break;
		}
		break;
	default:
		return -EINVAL;
	}
	return file->f_pos;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1740 1741 1742 1743 1744
}

/**
 * @brief Driver WRITE method
 * writes all at once, no provisions to continue in the next call
1745 1746 1747 1748
 * @param file
 * @param buf
 * @param count
 * @param off
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1749 1750
 * @return OK - number of bytes written, negative - errors
 */
1751 1752
ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff_t *off)
{
1753
	struct frameparspair_t pars_static[256]; // will be sufficient for most calls
1754 1755
	struct frameparspair_t * pars = pars_static;
	struct framepars_pd * privData = (struct framepars_pd*)file->private_data;
1756
	int sensor_port = privData -> minor - DEV393_MINOR(DEV393_FRAMEPARS0);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1757
	//	struct framepars_t *framepars = aframepars[sensor_port];
1758
	unsigned long frame = *off; // ************* NOTE: Never use file->f_pos in write() and read() !!!
1759 1760 1761
	int latency = -1;
	int first = 0;
	int last;
1762 1763 1764
	int result = 0;
	int port_mask=0; // to apply to several channels simultaneously
	unsigned long frames[SENSOR_PORTS];
1765
	sec_usec_t sec_usec;
Andrey Filippov's avatar
Andrey Filippov committed
1766
//	dev_dbg(g_devfp_ptr,"%s : file->f_pos=0x%x, *off=0x%x, count=0x%x\n",__func__, (int)file->f_pos, (int)*off, (int)count);
1767 1768 1769 1770 1771 1772
    dev_dbg(g_devfp_ptr, "file->f_pos=0x%x, *off=0x%x, count=0x%x, minor=0x%x\n",
            (int)file->f_pos, (int)*off, (int)count, (int) privData->minor);

    MDP(DBGB_FFOP, sensor_port, "file->f_pos=0x%x, *off=0x%x, count=0x%x, minor=0x%x\n",
            (int)file->f_pos, (int)*off, (int)count, (int) privData->minor)

1773
	count &= ~7; // sizeof (struct frameparspair_t)==8
1774
	switch (privData->minor) {
1775 1776 1777 1778
	case DEV393_MINOR(DEV393_FRAMEPARS0):
    case DEV393_MINOR(DEV393_FRAMEPARS1):
    case DEV393_MINOR(DEV393_FRAMEPARS2):
    case DEV393_MINOR(DEV393_FRAMEPARS3):
1779
		if (count > sizeof(pars_static)) // only allocate if static is not enough
1780 1781
			pars =     (struct frameparspair_t*)kmalloc(count, GFP_KERNEL);
		if (!pars) return -ENOMEM;
1782
		count >>= 3; // divide by sizeof(struct frameparspair_t); // 8
1783 1784 1785 1786 1787 1788 1789
		if (count) {
			if (copy_from_user((char*)pars, buf, count << 3)) {
				if (count > sizeof(pars_static)) kfree(pars);
				return -EFAULT;
			}
			while (first < count) {
				while ((first < count) && ((pars[first].num & 0xff00) == 0xff00)) { // process special instructions
1790 1791 1792
				    dev_dbg(g_devfp_ptr, "pars[%d].num = 0x%lx pars[%d].val = 0x%lx\n",first,pars[first].num, first,pars[first].val);
					switch (pars[first].num & 0xff0f) {
#if 0
1793 1794
					case FRAMEPARS_SETFRAME:
						frame = pars[first].val;
1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812
						port_mask = (pars[first].num >> 4) & ((1 << SENSOR_PORTS) - 1);
						if (port_mask){
						    // Retry if got different results - mostly for in-sync running sensors and just swicthed
						    // TODO: What to do: triggered sensors have frame sync delayed by exposure time from the common trigger
						    int frames_diff=1;
                            int ii;
						    for (ii =0; ii < SENSOR_PORTS; ii++) frames[ii] = 0xffffffff;
						    while (frames_diff) {
						        frames_diff = 0;
						        frame = pars[first].val;
						        //TODO: Disable interrupts here to freeze frame difference
						        for (ii =0; ii < SENSOR_PORTS; ii++){
                                    frame = pars[first].val + getThisFrameNumber(ii) - getThisFrameNumber(sensor_port);
                                    if (frame != frames[ii]) frames_diff = 1;
						            frames[ii] = frame;
						        }
						    }
						}
1813
						break;
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827
#endif
                    case FRAMEPARS_SETFRAME:
                        frame = pars[first].val;
                        port_mask = (pars[first].num >> 4) & ((1 << SENSOR_PORTS) - 1);
                        // No correction - frames should be exctly synchronized to work this way, otherwise use relative
                        if (port_mask){
                            int ii;
                            for (ii =0; ii < SENSOR_PORTS; ii++) if (port_mask & (1 << ii)){
                                frames[ii] = frame;
                            }
                        }
                        dev_dbg(g_devfp_ptr, "port_mask=0x%x frames[0]=0x%lx frames[1]=0x%lx frames[2]=0x%lx frames[3]=0x%lx\n",
                                port_mask, frames[0], frames[1], frames[2], frames[3]);
                        break;
1828
					case FRAMEPARS_SETFRAMEREL:
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1829
						frame = pars[first].val + getThisFrameNumber(sensor_port);
1830 1831 1832 1833 1834 1835 1836
                        port_mask = (pars[first].num >> 4) & ((1 << SENSOR_PORTS) - 1);
                        if (port_mask){
                            int ii;
                            for (ii =0; ii < SENSOR_PORTS; ii++) if (port_mask & (1 << ii)){
                                frames[ii] = pars[first].val + getThisFrameNumber(ii);
                            }
                        }
1837 1838 1839 1840
						break;
					case FRAMEPARS_SETLATENCY:
						latency = (pars[first].val & 0x80000000) ? -1 : pars[first].val;
						break;
1841
					case FRAMEPARS_SETFPGATIME: //ignore value (should be already set in G_SECONDS, G_MICROSECONDS frame0)
1842 1843 1844
                        //X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) );
					    sec_usec.sec =  GLOBALPARS(sensor_port,G_SECONDS);
                        sec_usec.usec = GLOBALPARS(sensor_port,G_MICROSECONDS);
1845 1846 1847
                        result = set_fpga_rtc(sec_usec);
                        if (result <0)
                            return result;
1848
						break;
1849
					case FRAMEPARS_GETFPGATIME: //ignore value, set frame 0 G_SECONDS, G_MICROSECONDS to FPGA registers
1850
						//X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) );
1851 1852
					    if (!get_fpga_rtc(&sec_usec))
					        return - ENODEV;
1853 1854
					    GLOBALPARS(sensor_port,G_SECONDS) =      sec_usec.sec;
                        GLOBALPARS(sensor_port,G_MICROSECONDS) = sec_usec.usec;
1855 1856
						break;
					default:
Andrey Filippov's avatar
Andrey Filippov committed
1857 1858
					    dev_err(g_devfp_ptr, "%s 0x%x: invalid special instruction: 0x%x\n",
					            __func__, (int) privData->minor,  (int)pars[first].num);
1859 1860 1861 1862 1863
					}
					first++;
				}
				last = first + 1;
				while ((last < count) && ((pars[last].num & 0xff00) != 0xff00)) last++;  // skip to the end or next special instructions
1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880
                if (port_mask) {
                    int ii;
                    dev_dbg(g_devfp_ptr, "0x%x: port_mask=0x%x\n", (int) privData->minor, port_mask);
                    for (ii =0; ii < SENSOR_PORTS; ii++) if (port_mask & (1 << ii)){
                        dev_dbg(g_devfp_ptr, "0x%x: setFrameParsAtomic(%d, %ld, %d, %d)\n",
                                (int) privData->minor, ii, frame, latency, last - first);
                        MDP(DBGB_FFOP, sensor_port, "0x%x: setFrameParsAtomic(%d, %ld, %d, %d)\n",
                                (int) privData->minor, ii, frame, latency, last - first)
                        result |= setFrameParsAtomic(ii, frames[ii], latency, last - first, &pars[first]);
                    }
                } else {
                    dev_dbg(g_devfp_ptr, "0x%x: setFrameParsAtomic(%ld, %d, %d)\n",
                            (int) privData->minor, frame, latency, last - first);
                    MDP(DBGB_FFOP, sensor_port, "0x%x: setFrameParsAtomic(%ld, %d, %d)\n",
                            (int) privData->minor, frame, latency, last - first)
                    result = setFrameParsAtomic(sensor_port,frame, latency, last - first, &pars[first]);
                }
1881 1882 1883 1884 1885 1886 1887 1888
				if (result < 0) {
					if (count > sizeof(pars_static)) kfree(pars);
					return -EFAULT;
				}
				first = last;
			}
		}
		if (count > sizeof(pars_static)) kfree(pars);
1889
		return count << 3; // *sizeof(struct frameparspair_t);
1890 1891
	default: return -EINVAL;
	}
Andrey Filippov's avatar
Andrey Filippov committed
1892
} // the frame size of 2080 bytes is larger than 1024 bytes [-Wframe-larger-than=]
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1893 1894 1895 1896

/**
 * @brief Driver MMAP method (should be used read only)
 * provides access to both 8-frame parameters (including future ones), frame - 0 - some static ones too and
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1897
 * much longer retained past parameters - subset of all parameters
1898 1899
 * @param file
 * @param vma
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1900 1901
 * @return OK - 0, negative - errors
 */
1902 1903 1904 1905
int framepars_mmap(struct file *file, struct vm_area_struct *vma)
{
	int result;
	struct framepars_pd * privData = (struct framepars_pd*)file->private_data;
1906
	int sensor_port = privData -> minor - DEV393_MINOR(DEV393_FRAMEPARS0);
1907

Andrey Filippov's avatar
Andrey Filippov committed
1908
	dev_dbg(g_devfp_ptr,"%s : minor=0x%x\n",__func__, privData->minor);
1909
	switch (privData->minor) {
1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
	case DEV393_MINOR(DEV393_FRAMEPARS0):
	case DEV393_MINOR(DEV393_FRAMEPARS1):
	case DEV393_MINOR(DEV393_FRAMEPARS2):
	case DEV393_MINOR(DEV393_FRAMEPARS3):
	result = remap_pfn_range(vma,
	        vma->vm_start,
	        ((unsigned long)virt_to_phys(&aframeparsall[sensor_port])) >> PAGE_SHIFT, // Should be page-aligned
	        vma->vm_end - vma->vm_start,
	        vma->vm_page_prot);
	dev_dbg(g_devfp_ptr, "remap_pfn_range returned=%x\n", result);
1920 1921
	MDP(DBGB_FFOP, sensor_port, "remap_pfn_range returned=%x\n", result)

1922 1923
	if (result) return -EAGAIN;
	return 0;
1924 1925
	default: return -EINVAL;
	}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1926
}
Andrey Filippov's avatar
Andrey Filippov committed
1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951
// SysFS interface to framepars
#define SYSFS_PERMISSIONS           0644 /* default permissions for sysfs files */
#define SYSFS_READONLY              0444
#define SYSFS_WRITEONLY             0222
/** Sysfs helper function - get channel number from the last character of the attribute name*/
static int get_channel_from_name(struct device_attribute *attr) ///< Linux kernel interface for exporting device attributes
                                                                ///< @return channel number
{
    int reg = 0;
    sscanf(attr->attr.name + (strlen(attr->attr.name)-1), "%du", &reg);
    return reg;
}

static ssize_t show_this_frame(struct device *dev, struct device_attribute *attr, char *buf)
{
    return sprintf(buf,"%u\n", (int) GLOBALPARS(get_channel_from_name(attr), G_THIS_FRAME));
}

static ssize_t store_this_frame(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    u32 aframe;
    if (sscanf(buf, "%u", &aframe)>0) {
        resetFrameNumber(get_channel_from_name(attr),
                         aframe,
                         (aframe < PARS_FRAMES)?1:0); // reset hardware if aframe is small
1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962
    } else {
        stopFrameSequencer(get_channel_from_name(attr), 1); // 0); // do not disable interrupts here?
//        return - EINVAL;
    }
    return count;
}
static ssize_t store_endis_chn(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    u32 en;
    if (sscanf(buf, "%u", &en)>0) {
        enDisSensorChn(get_channel_from_name(attr),en);
Andrey Filippov's avatar
Andrey Filippov committed
1963 1964 1965 1966 1967
    } else {
        return - EINVAL;
    }
    return count;
}
1968 1969 1970



Andrey Filippov's avatar
Andrey Filippov committed
1971 1972
//    sscanf(buf, "%i", &buffer_settings.frame_start[get_channel_from_name(attr)], &len);

1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995
static ssize_t show_fpga_version(struct device *dev, struct device_attribute *attr, char *buf)
{
    if (!hardware_initialized)
        return -EBUSY;
    return sprintf(buf,"0x%08lx\n", x393_fpga_version());
}

static ssize_t show_fpga_sensor_interface(struct device *dev, struct device_attribute *attr, char *buf)
{
    if (!hardware_initialized)
        return -EBUSY;
    switch (x393_sensor_interface()){
    case 0:
        return sprintf(buf,"PAR12\n");
    case 1:
        return sprintf(buf,"HISPI\n");
    default:
        return sprintf(buf,"0x%08%lx\n", x393_sensor_interface());
    }
}



Andrey Filippov's avatar
Andrey Filippov committed
1996 1997 1998
static ssize_t show_fpga_time(struct device *dev, struct device_attribute *attr, char *buf)
{
    sec_usec_t sec_usec;
1999 2000
    if (!get_fpga_rtc(&sec_usec))
        return - ENODEV;
Andrey Filippov's avatar
Andrey Filippov committed
2001 2002 2003 2004 2005 2006 2007
    return sprintf(buf,"%lu.%lu\n", sec_usec.sec, sec_usec.usec);
}

static ssize_t store_fpga_time(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
    sec_usec_t sec_usec={.sec=0, .usec=0};
    // avoiding floating point calcualtions in the kernel
2008
    const char *cp = buf;
Andrey Filippov's avatar
Andrey Filippov committed
2009
    int i;
Andrey Filippov's avatar
Andrey Filippov committed
2010
    if (sscanf(buf, "%lu.%s", &sec_usec.sec, cp)>0){
Andrey Filippov's avatar
Andrey Filippov committed
2011 2012 2013
        sscanf(cp,"%lu",&sec_usec.usec);
        for (i=strlen(cp); i<6;i++)
            sec_usec.usec *=10;
2014 2015
        i = set_fpga_rtc(sec_usec);
        if (i<0) return i;
Andrey Filippov's avatar
Andrey Filippov committed
2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064
    } else {
        return - EINVAL;
    }
    return count;
}

static ssize_t show_all_frames(struct device *dev, struct device_attribute *attr, char *buf)
{
    int chn;
    int sensor_frame16[SENSOR_PORTS];
    int compressor_frame16[SENSOR_PORTS];
    int i2c_frame16[SENSOR_PORTS];
    int sensor_aframe[SENSOR_PORTS];
    int compressor_aframe[SENSOR_PORTS];
    int compressor_gframe[SENSOR_PORTS];
    char * buf0=buf;
    for (chn = 0; chn < SENSOR_PORTS; chn++){
        sensor_frame16[chn] =     getHardFrameNumber(chn,0);
        compressor_frame16[chn] = getHardFrameNumber(chn,1);
        i2c_frame16[chn] =    read_xi2c_frame(chn);
        sensor_aframe[chn] =     (int) GLOBALPARS(chn, G_THIS_FRAME);
        compressor_aframe[chn] = (int) get_compressor_frame(chn);
        compressor_gframe[chn] = (int) GLOBALPARS(chn, G_COMPRESSOR_FRAME);
    }
    buf += sprintf(buf,"    sensor_fram16 ");
    for (chn = 0; chn < SENSOR_PORTS; chn++) buf += sprintf(buf,"       0x%x ",sensor_frame16[chn]);
    buf += sprintf(buf,"\n");
    buf += sprintf(buf,"compressor_fram16 ");
    for (chn = 0; chn < SENSOR_PORTS; chn++) buf += sprintf(buf,"       0x%x ",compressor_frame16[chn]);
    buf += sprintf(buf,"\n");
    buf += sprintf(buf,"      i2c_frame16 ");
    for (chn = 0; chn < SENSOR_PORTS; chn++) buf += sprintf(buf,"       0x%x ",i2c_frame16[chn]);
    buf += sprintf(buf,"\n");
    buf += sprintf(buf,"    sensor_aframe ");
    for (chn = 0; chn < SENSOR_PORTS; chn++) buf += sprintf(buf,"0x%08x ",sensor_aframe[chn]);
    buf += sprintf(buf,"\n");
    buf += sprintf(buf,"compressor_aframe ");
    for (chn = 0; chn < SENSOR_PORTS; chn++) buf += sprintf(buf,"0x%08x ",compressor_aframe[chn]);
    buf += sprintf(buf,"\n");
    buf += sprintf(buf,"compressor_gframe ");
    for (chn = 0; chn < SENSOR_PORTS; chn++) buf += sprintf(buf,"0x%08x ",compressor_gframe[chn]);
    buf += sprintf(buf,"\n");
    return buf-buf0;
}

static DEVICE_ATTR(this_frame0,               SYSFS_PERMISSIONS,     show_this_frame,                store_this_frame);
static DEVICE_ATTR(this_frame1,               SYSFS_PERMISSIONS,     show_this_frame,                store_this_frame);
static DEVICE_ATTR(this_frame2,               SYSFS_PERMISSIONS,     show_this_frame,                store_this_frame);
static DEVICE_ATTR(this_frame3,               SYSFS_PERMISSIONS,     show_this_frame,                store_this_frame);
2065 2066 2067 2068 2069 2070 2071 2072 2073
static DEVICE_ATTR(chn_en0,                   SYSFS_PERMISSIONS,     NULL,                           store_endis_chn);
static DEVICE_ATTR(chn_en1,                   SYSFS_PERMISSIONS,     NULL,                           store_endis_chn);
static DEVICE_ATTR(chn_en2,                   SYSFS_PERMISSIONS,     NULL,                           store_endis_chn);
static DEVICE_ATTR(chn_en3,                   SYSFS_PERMISSIONS,     NULL,                           store_endis_chn);
//static DEVICE_ATTR(chn_en0,                 SYSFS_WRITEONLY,       NULL,                           store_endis_chn);
//static DEVICE_ATTR(chn_en1,                 SYSFS_WRITEONLY,       NULL,                           store_endis_chn);
//static DEVICE_ATTR(chn_en2,                 SYSFS_WRITEONLY,       NULL,                           store_endis_chn);
//static DEVICE_ATTR(chn_en3,                 SYSFS_WRITEONLY,       NULL,                           store_endis_chn);

Andrey Filippov's avatar
Andrey Filippov committed
2074 2075
static DEVICE_ATTR(all_frames,                SYSFS_READONLY,        show_all_frames,                NULL);
static DEVICE_ATTR(fpga_time,                 SYSFS_PERMISSIONS,     show_fpga_time,                 store_fpga_time);
2076 2077
static DEVICE_ATTR(fpga_version,              SYSFS_READONLY,        show_fpga_version,              NULL);
static DEVICE_ATTR(fpga_sensor_interface,     SYSFS_READONLY,        show_fpga_sensor_interface,     NULL);
Andrey Filippov's avatar
Andrey Filippov committed
2078 2079 2080 2081 2082 2083 2084 2085

static struct attribute *root_dev_attrs[] = {
        &dev_attr_this_frame0.attr,
        &dev_attr_this_frame1.attr,
        &dev_attr_this_frame2.attr,
        &dev_attr_this_frame3.attr,
        &dev_attr_all_frames.attr,
        &dev_attr_fpga_time.attr,
2086 2087 2088 2089
        &dev_attr_chn_en0.attr,
        &dev_attr_chn_en1.attr,
        &dev_attr_chn_en2.attr,
        &dev_attr_chn_en3.attr,
2090 2091
        &dev_attr_fpga_version.attr,
        &dev_attr_fpga_sensor_interface.attr,
Andrey Filippov's avatar
Andrey Filippov committed
2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110
        NULL
};

static const struct attribute_group dev_attr_root_group = {
    .attrs = root_dev_attrs,
    .name  = NULL,
};


static int elphel393_framepars_sysfs_register(struct platform_device *pdev)
{
    int retval=0;
    struct device *dev = &pdev->dev;
    if (&dev->kobj) {
        if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
    }
    return retval;
}

Mikhail Karpenko's avatar
Mikhail Karpenko committed
2111 2112

/**
2113 2114 2115
 * @brief framepars driver probing function
 * @param[in]   pdev   pointer to \b platform_device structure
 * @return      0 on success or negative error code otherwise
Mikhail Karpenko's avatar
Mikhail Karpenko committed
2116
 */
2117
int framepars_init(struct platform_device *pdev)
2118
{
2119 2120
	int res;
	struct device *dev = &pdev->dev;
2121
//	const struct of_device_id *match;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
2122
	int sensor_port;
2123

Mikhail Karpenko's avatar
Mikhail Karpenko committed
2124 2125
	for (sensor_port = 0; sensor_port < SENSOR_PORTS; sensor_port++) {
		init_framepars_ptr(sensor_port);
2126 2127
		initGlobalPars(sensor_port);       // sets default debug if enabled - not anymore. Add here?
		initMultiPars(sensor_port);        // just clear - needs to be called again when sensor is recognized
Andrey Filippov's avatar
Andrey Filippov committed
2128
	    frameParsInitialized[sensor_port] = 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
2129
	}
2130
	res = register_chrdev(DEV393_MAJOR(DEV393_FRAMEPARS0), DEV393_NAME(DEV393_FRAMEPARS0), &framepars_fops);
2131
	if (res < 0) {
2132 2133
	    dev_err(dev, "framepars_init: couldn't get a major number %d (DEV393_MAJOR(DEV393_FRAMEPARS0)).\n",
		        DEV393_MAJOR(DEV393_FRAMEPARS0));
2134 2135
		return res;
	}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
2136 2137 2138
	for (sensor_port = 0; sensor_port < SENSOR_PORTS; sensor_port++) {
		init_waitqueue_head(&aframepars_wait_queue[sensor_port]);
	}
2139
	dev_info(dev, DEV393_NAME(DEV393_FRAMEPARS0)": registered MAJOR: %d\n", DEV393_MAJOR(DEV393_FRAMEPARS0));
Andrey Filippov's avatar
Andrey Filippov committed
2140 2141
	elphel393_framepars_sysfs_register(pdev);
    dev_info(dev, DEV393_NAME(DEV393_FRAMEPARS0)": registered sysfs\n");
2142
    g_devfp_ptr = dev;
2143 2144
    hardware_initialized = 0;

2145
	return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
2146 2147
}

2148
int framepars_remove(struct platform_device *pdev)
2149
{
2150
	unregister_chrdev(DEV393_MAJOR(DEV393_FRAMEPARS0), DEV393_NAME(DEV393_FRAMEPARS0));
2151 2152 2153
	return 0;
}

2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174
static const struct of_device_id elphel393_framepars_of_match[] = {
	{ .compatible = "elphel,elphel393-framepars-1.00" },
	{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_framepars_of_match);

static struct platform_driver elphel393_framepars = {
	.probe			= framepars_init,
	.remove			= framepars_remove,
	.driver			= {
		.name		= DEV393_NAME(DEV393_FRAMEPARS0),
		.of_match_table = elphel393_framepars_of_match,
	},
};

module_platform_driver(elphel393_framepars);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(FRAMEPARS_DRIVER_DESCRIPTION);