/** @file framepars.c */ /*!******************************************************************************** *! FILE NAME : framepars.c *! DESCRIPTION: Handling of frame parameters, making use of FPGA i2c *! and command sequencer that accepts commands up to 6 frames ahead. *! This module includes parameter storage, code called from ISR, *! from other kernel drivers as well as from the user space *! Copyright (C) 2008 Elphel, Inc. *! -----------------------------------------------------------------------------** *! *! 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. *!senssensor_common.hor_common.h *! You should have received a copy of the GNU General Public License *! along with this program. If not, see . *! -----------------------------------------------------------------------------** *! $Log: framepars.c,v $ *! Revision 1.14 2011/12/22 05:39:07 elphel *! catching up after some missed interrupts *! *! Revision 1.13 2010/08/10 21:10:41 elphel *! portrait mode now includes all 4 rotations (2 bits) *! *! Revision 1.12 2010/08/03 23:37:34 elphel *! rev 8.0.8.37, portrait mode support *! *! Revision 1.11 2010/05/25 00:52:23 elphel *! 8.0.8.20, working on multi-sensor *! *! Revision 1.10 2010/05/21 06:12:16 elphel *! continue working on multi-sensor software *! *! Revision 1.9 2010/05/16 02:03:47 elphel *! 8.0.8.4 - driver working with individual/broadcast sensor registers *! *! Revision 1.8 2010/05/13 03:39:31 elphel *! 8.0.8.12 - drivers modified for multi-sensor operation *! *! Revision 1.7 2010/04/28 02:34:33 elphel *! 8.0.6.6 - added support for linescan mode (also useful for high fps small images). 2.5K full line pairs/second with 5MPix sensor *! *! Revision 1.6 2010/04/06 20:35:42 elphel *! 8.0.7.5 - made the fpgaclock driver program 10359 clock in addition to the system one *! *! Revision 1.5 2010/01/27 22:51:52 elphel *! turned off ELPHEL_DEBUG, fixed errors caused by that. *! *! Revision 1.4 2008/12/02 19:08:54 elphel *! Bug fixin setFramePar() *! *! Revision 1.3 2008/11/30 05:01:03 elphel *! Changing gains/scales behavior *! *! Revision 1.2 2008/11/28 08:17:09 elphel *! keeping Doxygen a little happier *! *! Revision 1.1.1.1 2008/11/27 20:04:00 elphel *! *! *! Revision 1.41 2008/11/17 06:42:37 elphel *! added SETFRAMEREL - skipping specified number of frames from current (through lseek) *! *! Revision 1.40 2008/11/14 07:09:48 elphel *! additional test to prevent "JUST_THIS" parameters to be written to the future-most frame (otherwise it can get stuck) *! *! Revision 1.39 2008/11/13 05:40:45 elphel *! 8.0.alpha16 - modified histogram storage, profiling *! *! Revision 1.38 2008/11/05 02:01:25 elphel *! Added bit field manipulation in parameters *! *! Revision 1.37 2008/11/02 00:31:25 elphel *! reduced required initialization steps *! *! Revision 1.36 2008/10/29 04:18:28 elphel *! v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue) *! *! Revision 1.35 2008/10/25 19:59:48 elphel *! added lseek() calls to enable/disable daemons at events (compressed frame available, any frame available, histogram-Y and histograms-C available) *! *! Revision 1.34 2008/10/23 18:25:40 elphel *! removed unneeded test condition before calling wait_event_interruptible() *! *! Revision 1.33 2008/10/23 08:03:38 elphel *! cleanup *! *! Revision 1.32 2008/10/21 21:28:26 elphel *! minor bug fix *! *! Revision 1.31 2008/10/20 18:46:36 elphel *! all the functions for the same target frame are processed in the order regardless of latencies *! *! Revision 1.30 2008/10/19 06:51:51 elphel *! rearranged initialization, added frame number reset (to avoid unlikely integer overflow) *! *! Revision 1.29 2008/10/17 05:44:48 elphel *! fixing latencies *! *! Revision 1.28 2008/10/15 22:28:56 elphel *! snapshot 8.0.alpha2 *! *! Revision 1.27 2008/10/12 06:13:10 elphel *! snapshot *! *! Revision 1.26 2008/10/11 18:46:07 elphel *! snapshot *! *! Revision 1.25 2008/10/10 17:06:59 elphel *! just a snapshot *! *! Revision 1.24 2008/10/08 21:26:25 elphel *! snapsot 7.2.0.pre4 - first images (actually - second) *! *! Revision 1.23 2008/10/06 08:31:08 elphel *! snapshot, first images *! *! Revision 1.22 2008/10/05 05:13:33 elphel *! snapshot003 *! *! Revision 1.21 2008/10/04 16:10:12 elphel *! snapshot *! *! Revision 1.20 2008/09/28 00:31:57 elphel *! snapshot *! *! Revision 1.19 2008/09/25 00:58:11 elphel *! snapshot *! *! Revision 1.18 2008/09/20 00:29:50 elphel *! moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h *! *! Revision 1.17 2008/09/19 04:37:25 elphel *! snapshot *! *! Revision 1.16 2008/09/16 00:49:31 elphel *! snapshot *! *! Revision 1.15 2008/09/12 20:40:11 elphel *! snapshot *! *! Revision 1.14 2008/09/12 00:28:54 elphel *! typo fixed *! *! Revision 1.13 2008/09/12 00:23:59 elphel *! removed cc353.c, cc353.h *! *! Revision 1.12 2008/09/07 19:48:08 elphel *! snapshot *! *! Revision 1.11 2008/09/05 23:20:26 elphel *! just a snapshot *! *! Revision 1.10 2008/09/04 17:37:13 elphel *! documenting *! *! Revision 1.9 2008/09/02 21:01:06 elphel *! just next... *! *! Revision 1.8 2008/07/27 04:27:49 elphel *! next snapshot *! *! Revision 1.7 2008/06/24 00:43:44 elphel *! just a snapshot *! *! Revision 1.6 2008/06/20 03:54:19 elphel *! another snapshot *! *! Revision 1.5 2008/06/19 02:17:36 elphel *! continuing work - just a snapshot *! *! Revision 1.4 2008/06/16 06:51:21 elphel *! work in progress, intermediate commit *! *! Revision 1.3 2008/06/10 00:03:14 elphel *! storing past frame data - subset of the frame parameters *! *! Revision 1.2 2008/06/08 23:48:39 elphel *! minor cleanup *! *! Revision 1.1 2008/05/26 23:33:00 elphel *! Added driver to handle multi-frame parameters *! *! */ //copied from cxi2c.c - TODO:remove unneeded #include /// div for 64 #include /// div for 64 #include #include #include #include #include #include #include #include #include //#include #include #include #include #include //#include #include // endians #include #include #include #include #include #include #include //#include "fpgactrl.h" // defines port_csp0_adsensor_common.hdr, port_csp4_addr //#include "cc3x3.h" //#include "x3x3.h" // hardware definitions #include "sensor_common.h" #include "framepars.h" #include "param_depend.h" // specifies what functions should be called for different parameters changed /// needed for lseek commands //#include "cxdma.h" // x313_dma_init //#include "cci2c.h" // to use void i2c_reset_wait(void), reset shadow static 'i2c_hardware_on' #include "x393_macro.h" /** * \def MDF1(x) optional debug output */ #if ELPHEL_DEBUG #define MDF(x) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} #define MDF2(x) { if (GLOBALPARS(G_DEBUG) & (1 <<2)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} } /// setFrameParsAtomic #define MDF5(x) { if (GLOBALPARS(G_DEBUG) & (1 <<5)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} } #define D5(x) { if (GLOBALPARS(G_DEBUG) & (1 <<5)) {x ;} } /// processPars #define MDF6(x) { if (GLOBALPARS(G_DEBUG) & (1 <<6)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} } #define D6(x) { if (GLOBALPARS(G_DEBUG) & (1 <<6)) {x ;} } ///update FramePars #define MDF7(x) { if (GLOBALPARS(G_DEBUG) & (1 <<7)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} } #define D7(x) { if (GLOBALPARS(G_DEBUG) & (1 <<7)) {x ;} } /// setFramePar[s] #define MDF8(x) { if (GLOBALPARS(G_DEBUG) & (1 <<8)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} } #define D8(x) { if (GLOBALPARS(G_DEBUG) & (1 <<8)) {x ;} } #define ELPHEL_DEBUG_THIS 0 // #define ELPHEL_DEBUG_THIS 1 #else #define MDF(x) #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 #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 #define D1(x) x #define D1I(x) #else #define MDD1(x) #define MDF1(x) #define D1(x) #define D1I(x) x #endif //#define ELP_KERR(x) printk("%s:%d:%s: ERROR ",__FILE__,__LINE__,__FUNCTION__); x /** * \def FRAMEPARS_DRIVER_NAME driver name to display */ #define FRAMEPARS_DRIVER_NAME "Elphel (R) Model 393 Frame Parameters device driver" static const struct of_device_id elphel393_framepars_of_match[]; static struct framepars_all_t sFrameParsAll __attribute__ ((aligned (PAGE_SIZE))); ///< Sensor Parameters, currently 8 pages all and 2048 pages some, static struct unsigned long frameParsInitialized; /// set to 0 at startup, 1 after initialization that is triggered by setParsAtomic() #define thisFrameNumber GLOBALPARS(G_THIS_FRAME) // Current frame number (may lag from the hardware) //#define THISFRAMENUMBER GLOBALPARS(G_THIS_FRAME) // Current frame number (may lag from the hardware) struct framepars_all_t *frameparsall=NULL; /// - will be mmap-ed 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 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 /** * @brief file private data */ struct framepars_pd { int minor; ///< file minor value struct wait_queue *framepars_wait_queue; ///< wait queue (waiting for file number to increase) ///NOTE: not used at all? // something else to be added here? }; /** * @brief assign non-static pointers to static data to be used as extern */ void init_framepars_ptr(void) { frameparsall= &sFrameParsAll; /// - will be mmap-ed framepars = sFrameParsAll.framePars; pastpars = sFrameParsAll.pastPars; funcs2call = sFrameParsAll.func2call.pars; /// each parameter has a 32-bit mask of what pgm_function to call - other fields not used globalPars = sFrameParsAll.globalPars; /// parameters that are not frame-related, their changes do not initiate any actions so they can be mmaped for both multiSensIndex= sFrameParsAll.multiSensIndex; /// indexes of individual sensor register shadows (first of 3) - now for all parameters, not just sensor ones multiSensRvrsIndex= sFrameParsAll.multiSensRvrsIndex; /// reverse index (to parent) for the multiSensIndex } int framepars_open (struct inode *inode, struct file *filp); int framepars_release(struct inode *inode, struct file *filp); 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); /** * @brief Reset hardware sequencers (i2c, command) and initialize framepars structure */ void initSequencers(void) { unsigned long flags; MDF2(printk ("\n")); printk ("initSequencers:resetting both sequencers\n"); #ifdef TEST_DISABLE_CODE local_irq_save(flags); X3X3_SEQ_RESET; i2c_reset_wait(); local_irq_restore(flags); initFramePars(); #endif } /** * @brief reset absolute frame number \b thisFrameNumber to \b frame8 */ void resetFrameNumber(void) { int i; #ifdef TEST_DISABLE_CODE thisFrameNumber= X3X3_I2C_FRAME; #endif MDF2(printk (" thisFrameNumber=0x%lx\n",thisFrameNumber)); // write absolute frame numbers for (i=thisFrameNumber; i<(thisFrameNumber+PARS_FRAMES); i++) framepars[i & PARS_FRAMES_MASK].pars[P_FRAME]=i; /// initialize frameParsDeps.pars masks: } /** * @brief initialize all parameters, set \b thisFrameNumber to \b frame number read from hardware hardware ( 0 after resetting i2c and cmd_seq) */ void initFramePars(void) { int i; memset(framepars, 0, sizeof(framepars)); resetFrameNumber(); /// initialize frameParsDeps.pars masks: for (i=0; i < (sizeof(param_depend_tab)/8); i++) { funcs2call[param_depend_tab[2*i] & 0xffff]=param_depend_tab[2*i+1]; /// remove possible flags MDF2(printk("funcs2call[0x%lx]=0x%08lx\n",param_depend_tab[2*i] & 0xffff,param_depend_tab[2*i+1])); } for (i=0; i < P_SENSOR_NUMREGS; i++) funcs2call[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 chnaged, and if will be it wil cause no action for (i=0; i < P_M10359_NUMREGS; i++) funcs2call[P_M10359_REGS+i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function initMultiPars(); /// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection frameParsInitialized=1; } /** * @brief reset all global parameters, set default for debug mask (if ELPHEL_DEBUG) */ void initGlobalPars(void) { memset(&globalPars[GLOBALS_PRESERVE], 0, sizeof(globalPars)-GLOBALS_PRESERVE*sizeof(globalPars[0])); /// MDF(GLOBALPARS(G_DEBUG) = ELPHEL_DEBUG_STARTUP;// removed - add write to fpga init script MDF(printk("GLOBALPARS(G_DEBUG)=%lx\n",GLOBALPARS(G_DEBUG))); } /** * @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 * @return number of multi-regs */ int initMultiPars(void) { int i,j,n; int ireg=P_MULTI_REGS; /// multi-reg shadows start index unsigned long m; memset(multiSensIndex, 0, sizeof(multiSensIndex)); memset(multiSensRvrsIndex, 0, sizeof(multiSensRvrsIndex)); GLOBALPARS(G_MULTI_NUM)=0; for (i=0;i<8;i++) { m=GLOBALPARS(G_MULTI_REGSM+i); /// 1 bit per register that need individual shadows // MDF(printk("i=%d, m=0x%lx\n",i,m)); for (j= P_SENSOR_REGS +(i<<5); m && (GLOBALPARS(G_MULTI_NUM)>= 1) { if (m & 1) { multiSensIndex[j]=ireg; // MDF(printk("j=0x%x ireg=0x%x\n",j,ireg)); for (n=0;nheight= framepars[findex_this].pars[P_ACTUAL_HEIGHT]; /// NOTE: P_ACTUAL_WIDTH,P_QUALITY copied with memcpy interframe_pars->color= framepars[findex_this].pars[P_COLOR]; interframe_pars->byrshift=framepars[findex_this].pars[P_COMPMOD_BYRSH]; interframe_pars->quality2 |= (framepars[findex_this].pars[P_PORTRAIT] & 1) << 7; } /// copy parameters from findex_future (old "fartherst in the future") to findex_prev (new "fartherst in the future") if it was changed since if ((bmask32=framepars[findex_prev].modsince32)) { MDF7(printk("framepars[%d].modsince32=0x%lx\n",findex_prev,bmask32)); 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]; MDF7(printk("hw=%d framepars[%d].pars[%d]=framepars[%d].pars[%d]=0x%lx\n",frame8, findex_prev,index,findex_future,index,framepars[findex_future].pars[index])); } framepars[findex_prev].modsince[index32]=0; /// mark as not "modified since" (yet) } } framepars[findex_prev].modsince32=0;/// mark as not "modified since" super index } /// clear "modified" and flags on the brand new future frame 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 framepars[findex_prev].pars[P_FRAME]=thisFrameNumber+7; /// 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) if (!(get_globalParam(G_TASKLET_CTL) & (1 << TASKLET_CTL_IGNPAST))) { 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; } } MDF7(printk ("resubmitting past due functions = 0x%lx for frame=%ld (0x%x)\n",framepars[findex_this].functions,thisFrameNumber,findex_this)); } else { MDF(printk ("Ignored past due functions = 0x%lx for frame=%ld (0x%x)\n",framepars[findex_this].functions,thisFrameNumber,findex_this)); } } thisFrameNumber++; } } /** * @brief process parameters that are overdue or due in ASAP mode (not through the sequencer) * Called twice from processPars - at the beginning and at the end to finish off any derivatives (needed?) * @param sensorproc * @param frame8 */ inline void processParsASAP (struct sensorproc_t * sensorproc, int frame8) { unsigned long todo, mask , remain; int pars_ahead; /// considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8 int frame_proc; /// current frame for which parameters are considered struct framepars_t * procpars; struct framepars_t * prevpars ; /// maybe - drop calculation for each function, move it to pgm_* where needed? unsigned long * p_nasap=& GLOBALPARS(G_CALLNASAP); int i; int rslt; #if ELPHEL_DEBUG 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; if (allfunctions) MDF6(printk("frame8=%d, functions: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n", frame8, framepars[0].functions,framepars[1].functions,framepars[2].functions,framepars[3].functions,framepars[4].functions,framepars[5].functions,framepars[6].functions,framepars[7].functions)); #endif /// 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 for (pars_ahead=0; pars_ahead <= 4; pars_ahead++ ) { frame_proc=(frame8 + pars_ahead) & PARS_FRAMES_MASK; procpars = &framepars[frame_proc]; prevpars = &framepars[(frame_proc-1) & PARS_FRAMES_MASK]; i=0; mask=1; remain=0xffffffff; while ((todo=(pars_ahead)? (p_nasap[pars_ahead] & (procpars->functions) & remain): (procpars->functions & remain) )) { ///none, *1, *2,*3,*4 while (!(todo & mask)) { /// skip zeros - todo will stay current (.functions will not change i++; mask <<=1; remain <<=1; } /// now (todo & mask) !=0 MDF6(printk(" todo=0x%08lx (curr=0x%08lx) frame8=%d, pars_ahead=%d, frame_proc=%d i=%d, mask=0x%08lx\n", todo, procpars->functions, frame8,pars_ahead,frame_proc,i,mask)); MDF6(printk(" %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)); if (sensorproc->pgm_func[i]) { rslt=sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, -1); } 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 rslt=sensorproc->pgm_func[i+32] ( &(sensorproc->sensor), procpars, prevpars, -1); } /// Nothing to do with errors here - just report? if (rslt<0) printk("%s:%d:%s - error=%d",__FILE__,__LINE__,__FUNCTION__, rslt); procpars->functions &= ~mask; MDF6(printk(".functions=0x%08lx)\n", procpars->functions)); i++; mask <<=1; remain <<=1; } } } /// Next 5 should go in that sequence //#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) //#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 inline void processParsSeq (struct sensorproc_t * sensorproc, int frame8, int maxahead) { unsigned long todo, mask , remain; int job_ahead; /// doing job "job_ahead" ahead of needed int pars_ahead; /// considering parameter "pars_ahead" of the (frame8+job_ahead) mod 8 int frame_proc; /// current frame for which parameters are considered struct framepars_t * procpars; struct framepars_t * prevpars ; /// maybe - drop calculation fpr each function, move it to pgm_* where needed? unsigned long * p_nasap=& GLOBALPARS(G_CALLNASAP); int seq_frame; /// sequencer frame for which pgm_* function should schedule data int i; int rslt; int max_par_ahead; int this_ahead; 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 for (job_ahead=0; job_ahead <= maxahead; job_ahead++ ) { max_par_ahead=min(5,(PARS_FRAMES-3) -job_ahead); for (pars_ahead=0; pars_ahead < max_par_ahead; pars_ahead++ ) { frame_proc=(frame8 + job_ahead + pars_ahead +1) & PARS_FRAMES_MASK; /// procpars = &framepars[frame_proc]; /// Check if at least one function is needed for frame_proc if (procpars->functions & p_nasap[pars_ahead] & ///all, *1, *2,*3,*4 - for all will have G_CALLNASAP twice p_nasap[0]) { prevpars = &framepars[(frame_proc-1) & PARS_FRAMES_MASK]; // seq_frame= (frame8+job_ahead+1) & PARS_FRAMES_MASK; i=0; mask=1; remain=0xffffffff; while ((todo=procpars->functions & /// 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) i++; mask <<=1; remain <<=1; } /// 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 // seq_frame= (frame8 + job_ahead + this_ahead) & PARS_FRAMES_MASK; seq_frame= (frame_proc+1-this_ahead) & PARS_FRAMES_MASK; MDF6(printk(" todo=0x%08lx (curr=0x%08lx) frame8=%d, frame_proc=%d, seq_frame=%d, i=%d, mask=0x%08lx\n", todo, procpars->functions, frame8,frame_proc,seq_frame,i,mask)); MDF6(printk(" %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)); if (sensorproc->pgm_func[i]) { /// NOTE: Was (frame8+job_ahead +1) & PARS_FRAMES_MASK rslt=sensorproc->pgm_func[i] ( &(sensorproc->sensor), procpars, prevpars, seq_frame); } 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 rslt=sensorproc->pgm_func[i+32] ( &(sensorproc->sensor), procpars, prevpars, seq_frame); } if (rslt >= 0) { procpars->functions &= ~mask; /// mark it done } else { MDF6(printk("Error - function result was %d\n", rslt)); } i++; mask <<=1; remain <<=1; } } } } } /** * @brief Program image acquisition, according to the parameters changed * Called from ISR? * @param sensorproc pointer to sensor static parameters and functions * @param frame8 current hardware frame number * @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 //#define P_CALLASAP 107 // bitmask - what functions work only in the current frame (ASAP) mode void processPars (struct sensorproc_t * sensorproc, int frame8, int maxahead) { frame8 &= PARS_FRAMES_MASK; /// first - do all ASAP tasks (they should not be done ahead of the corresponding interrupt!) // MDF6(printk("before first processParsASAP\n")); processParsASAP (sensorproc, frame8); /// 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 // MDF6(printk("before processParsSeq\n")); processParsSeq (sensorproc, frame8, maxahead); /// re-test ASAP tasks - they might appear as a result of other commands executed // MDF6(printk("before second processParsASAP\n")); processParsASAP (sensorproc, frame8); } /** * @brief schedule pgm_func to be executed for selected frame (frame8) * @param frame8 frame number (3-bit) to schedule a function for * @param func_num function number to schedule */ void schedule_pgm_func(int frame8, int func_num) { MDF1(printk(" frame8=%d, func_num=%d\n", frame8, func_num)); framepars[frame8 & PARS_FRAMES_MASK].functions |= 1 << func_num; } /** * @brief schedule pgm_func to be executed for this_framepars->pars[P_FRAME] & PARS_FRAMES_MASK * @param this_framepars pointer to frame parameters structure * @param func_num number of function to schedule */ void schedule_this_pgm_func(struct framepars_t * this_framepars, int func_num) { int frame8=this_framepars->pars[P_FRAME] & PARS_FRAMES_MASK; MDF1(printk(" frame8=%d, func_num=%d\n", frame8, func_num)); framepars[frame8].functions |= 1 << func_num; } /** * @brief just return current thisFrameNumber * @return current value of thisFrameNumber */ unsigned long getThisFrameNumber(void) { return thisFrameNumber; } /** * @brief Set parameters that will never change (usually after sensor discovery) * @param numPars number of parameters to set * @param pars array of parameters (number/value pairs) * @return always 0 */ int setFrameParsStatic(int numPars, struct frameparspair_t * pars) { int npar,nframe,index; for (npar=0; npar < numPars; npar++) { index=pars[npar].num; 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; } /** * @brief set parameters for the specified frame (atomic, with interrupts off). Used from applications through driver write * @param frameno absolute (full) frame number parameters should be applied to * @param 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) * @param numPars number of parameters to set (0 is OK to just test if it is too early/too late) * @param pars array of parameters (number/value pairs). FRAMEPAIR_FORCE_NEW modifier to parameter number * @return 0 - OK, -ERR_FRAMEPARS_TOOEARLY, -ERR_FRAMEPARS_TOOLATE */ ///TODO: Check that writes never to the future or past frame (only 6 of 8 are allowed). Have seen just_this to flood all int setFrameParsAtomic(unsigned long frameno, int maxLatency, int numPars, struct frameparspair_t * pars) { unsigned long flags; int npar,nframe; unsigned long val, bmask, bmask32; int index,bindex; if (!frameParsInitialized) { initSequencers(); /// Will call initFramePars(); and initialize functions } int findex_this= thisFrameNumber & PARS_FRAMES_MASK; int findex_prev= (findex_this-1) & PARS_FRAMES_MASK; int findex_future=(findex_this-2) & PARS_FRAMES_MASK; /// actually - fartherst in the future?? // int frame8= frameno & PARS_FRAMES_MASK; int frame8; MDF2(printk (": frameno=0x%lx, findex_this=%d (0x%lx) maxLatency=%d, numPars=%d\n",frameno, findex_this, thisFrameNumber, maxLatency, numPars)); D1I(local_irq_save(flags)); PROFILE_NOW(6); if (maxLatency>=0) { if (frameno <= (thisFrameNumber+maxLatency)) { D1I(local_irq_restore(flags)); return -ERR_FRAMEPARS_TOOLATE; } else if (frameno >= (thisFrameNumber+ (PARS_FRAMES-1))) { D1I(local_irq_restore(flags)); return -ERR_FRAMEPARS_TOOEARLY; } } /// not too late, not too early, go ahead for (npar=0; npar < numPars; npar++) { D5(printk(" --pars[%d].num=0x%lx, pars[%d].val=0x%lx",npar,pars[npar].num, npar, pars[npar].val)); // frame8= (pars[npar].num & FRAMEPAR_GLOBALS)? -1: (frameno & PARS_FRAMES_MASK); frame8= frameno & PARS_FRAMES_MASK; val=pars[npar].val; index= pars[npar].num & 0xffff; if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) { D1I(local_irq_restore(flags)); return -ERR_FRAMEPARS_BADINDEX; } D5(printk(" index=0x%x, val=0x%lx",index, val)); 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 val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(index), val); } GLOBALPARS(index)=val; D5(printk(" set GLOBALPARS(0x%x)=0x%lx\n",index,val)); } else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) { funcs2call[index] = val; D5(printk(" set funcs2call[0x%x]=0x%lx\n",index,val)); // } else if ((frameno !=findex_prev) && (frameno != findex_future)) { /// do not write parameters in the future otherwise } else if ((frame8 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame8].pars[index], val); } //TODO: optimize to use mask several parameters together D5(printk(" frame8=0x%x\n",frame8)); if ((framepars[frame8].pars[index]!= val) || (pars[npar].num & FRAMEPAIR_FORCE_NEW)){ bmask= 1 << (index & 31); bindex = index >> 5; bmask32= 1 << bindex; /// Set this parameter for specified frame framepars[frame8].pars[index] = val; framepars[frame8].mod[bindex] |= bmask; framepars[frame8].mod32 |= bmask32; framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters D5(printk(" bindex=0x%x, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",bindex, bmask, bmask32, framepars[frame8].functions)); /// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS) if ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0) { MDF5(printk (": --- setting next frames")); for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) { framepars[nframe].pars[index] = val; D5(printk (" %d",nframe)); } frame8=(frame8-1) & PARS_FRAMES_MASK;/// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does D5(printk ("\n")); } /// Mark this parameter in all previous frames as "modified since" /// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here framepars[nframe].modsince[bindex] |= bmask; framepars[nframe].modsince32 |= bmask32; } } } else { /// error - trying to write "just this" to the "future" - that would stick if allowed D1I(local_irq_restore(flags)); ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num)); return -ERR_FRAMEPARS_TOOEARLY; } } /// Try to process parameters immediately after written. If 0, only non-ASAP will be processed to prevent /// effects of uncertainty of when was it called relative to frame sync /// Changed to all (don't care about uncertainty - they will trigger only if it is too late or during sensor detection/initialization) if (!(get_globalParam(G_TASKLET_CTL) & (1<< TASKLET_CTL_NOSAME))) { // processParsSeq (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet MDF5(printk ("\n")); processPars (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet } PROFILE_NOW(7); D1I(local_irq_restore(flags)); return 0; } //#define FRAMEPAIR_JUST_THIS 0x40000 // write only to this frame, don't propagate // (like "single frame" - compressor, sensor) first write "stop", then - "single" with FRAMEPAIR_JUST_THIS /** * @brief set a single output (calculated) parameter for the frame referenced by this_framepars structure. * Shedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in mindex * @param this_framepars pointer to the current parameters structure * @param mindex parameter number (with optional modifiers in high bits) * @param val parameter value to set * @return 0 - OK, -ERR_FRAMEPARS_BADINDEX */ int setFramePar(struct framepars_t * this_framepars, unsigned long mindex, unsigned long val) { int frame8= (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK; unsigned long flags; int nframe; unsigned long bmask, bmask32 , bindex; int findex_this= thisFrameNumber & PARS_FRAMES_MASK; int findex_prev= (findex_this-1) & PARS_FRAMES_MASK; int findex_future=(findex_this-2) & PARS_FRAMES_MASK; int index= mindex & 0xffff; MDF8(printk (": thisFrameNumber=0x%lx frame8=%d index= %d (0x%lx), val=0x%lx\n", thisFrameNumber, frame8, index, mindex, val)); D1I(local_irq_save(flags)); // if (index > P_MAX_PAR) { if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) { D1I(local_irq_restore(flags)); return -ERR_FRAMEPARS_BADINDEX; } //TODO: optimize to use mask several parameters together 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 val= FRAMEPAIR_FRAME_MASK_NEW(mindex, GLOBALPARS(index), val); } GLOBALPARS(index)=val; } else if (mindex & FRAMEPAIR_FRAME_FUNC) { /// write to func_proc[] instead funcs2call[index] = val; // } else { } else if ((frame8 != findex_future) || ((mindex & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick if (mindex & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one val= FRAMEPAIR_FRAME_MASK_NEW(mindex, framepars[frame8].pars[index], val); } if ((framepars[frame8].pars[index]!= val) || (mindex & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))){ bmask= 1 << (index & 31); bindex = index >> 5; bmask32= 1 << bindex; /// Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED! framepars[frame8].pars[index] = val; framepars[frame8].mod[bindex] |= bmask; framepars[frame8].mod32 |= bmask32; if (mindex & FRAMEPAIR_FORCE_PROC){ framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters } MDF8(printk(" bindex=0x%lx, bmask=0x%08lx, bmask32=0x%08lx, functions=0x%08lx\n",bindex, bmask, bmask32, framepars[frame8].functions)); /// Write parameter to the next frames up to the one that have the same parameter already modified if ((mindex & FRAMEPAIR_JUST_THIS)==0) { MDF8(printk (": --- setting next frames")); // for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[frame8].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) { for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) { framepars[nframe].pars[index] = val; D8(printk (" %d",nframe)); } frame8=(frame8-1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does } // MDF1(printk("\n")); /// Mark this parameter in all previous frames as "modified since" /// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them MDF8(printk (": >>> setting modsince")); // for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here framepars[nframe].modsince[bindex] |= bmask; framepars[nframe].modsince32 |= bmask32; D8(printk (" %d",nframe)); } D8(printk ("\n")); } } else { /// error - trying to write "just this" to the "future" - that would stick if allowed D1I(local_irq_restore(flags)); ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", mindex)); return -ERR_FRAMEPARS_TOOEARLY; } D1I(local_irq_restore(flags)); return 0; } /** * @brief set multiple output (calculated) parameters for the frame referenced by this_framepars structure. * Shedules action only if the FRAMEPAIR_FORCE_PROC modifier bit is set in the particular parameter index * @param this_framepars pointer to the current parameters structure * @param numPars number of parameters to set * @param pars array of parameters (number/value pairs). Parameter numbers accept modifiers * @return 0 - OK, -ERR_FRAMEPARS_BADINDEX */ int setFramePars(struct framepars_t * this_framepars, int numPars, struct frameparspair_t * pars) { int frame8; unsigned long flags; int npar,nframe; unsigned long val, bmask, bmask32; int index,bindex; int findex_this= thisFrameNumber & PARS_FRAMES_MASK; int findex_prev= (findex_this-1) & PARS_FRAMES_MASK; int findex_future=(findex_this-2) & PARS_FRAMES_MASK; MDF8(printk (": this_framepars=0x%x numPars=%d\n",(int) this_framepars, numPars)); D1I(local_irq_save(flags)); for (npar=0; npar < numPars; npar++) { frame8= (this_framepars->pars[P_FRAME]) & PARS_FRAMES_MASK; val=pars[npar].val; index= pars[npar].num & 0xffff; MDF8(printk (": --- frame8=%d index=%d (0x%x) val=0x%x\n", frame8, index, (int) pars[npar].num, (int) val)); if (index> ((index >= FRAMEPAR_GLOBALS)? (P_MAX_GPAR+FRAMEPAR_GLOBALS): P_MAX_PAR)) { D1I(local_irq_restore(flags)); ELP_KERR(printk(" bad index=%d > %d\n", index, P_MAX_PAR)); return -ERR_FRAMEPARS_BADINDEX; } 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 val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, GLOBALPARS(index), val); } GLOBALPARS(index)=val; } else if (pars[npar].num & FRAMEPAIR_FRAME_FUNC) { funcs2call[index] = val; // } else { } else if ((frame8 != findex_future) || ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0)) { /// do not write "JUST_THIS" parameters in the future otherwise they'll stick if (pars[npar].num & FRAMEPAIR_MASK_BYTES) { /// combine new value with the old one val= FRAMEPAIR_FRAME_MASK_NEW(pars[npar].num, framepars[frame8].pars[index], val); } //TODO: optimize to use mask several parameters together if ((framepars[frame8].pars[index]!= val) || (pars[npar].num & (FRAMEPAIR_FORCE_NEW | FRAMEPAIR_FORCE_PROC))){ bmask= 1 << (index & 31); bindex = index >> 5; bmask32= 1 << bindex; /// Set this parameter for specified frame, (for now - unconditionally mark as modified, even if the value is the same as it was - CHANGED! framepars[frame8].pars[index] = val; framepars[frame8].mod[bindex] |= bmask; framepars[frame8].mod32 |= bmask32; if (pars[npar].num & FRAMEPAIR_FORCE_PROC){ framepars[frame8].functions |= funcs2call[index]; ///Mark which functions will be needed to process the parameters } /// Write parameter to the next frames up to the one that have the same parameter already modified (only if not FRAMEPAIR_JUST_THIS) if ((pars[npar].num & FRAMEPAIR_JUST_THIS)==0) { MDF8(printk (": --- setting next frames")); for (nframe=(frame8+1) & PARS_FRAMES_MASK; (nframe != findex_prev) && (!(framepars[nframe].mod[bindex] & bmask)); nframe=(nframe+1) & PARS_FRAMES_MASK) { D8(printk (" %d",nframe)); framepars[nframe].pars[index] = val; } frame8=(frame8-1) & PARS_FRAMES_MASK; /// for " regular parameters "modified since" do not include the target frame itself, for "JUST_THIS" - does D8(printk ("\n")); } /// Mark this parameter in all previous frames as "modified since" /// TODO: consider alternative way - first iterate through all parameters, build masks, then apply them // for (nframe=(frame8-1) & PARS_FRAMES_MASK; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { for (nframe=frame8; nframe != findex_future; nframe=(nframe-1) & PARS_FRAMES_MASK) { ///NOTE: frame8 is modified here framepars[nframe].modsince[bindex] |= bmask; framepars[nframe].modsince32 |= bmask32; } } } else { /// error - trying to write "just this" to the "future" - that would stick if allowed D1I(local_irq_restore(flags)); ELP_KERR(printk("Tried to write JUST_THIS parameter (0x%lx) too far in the future", pars[npar].num)); return -ERR_FRAMEPARS_TOOEARLY; } } D1I(local_irq_restore(flags)); return 0; } ///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) static struct file_operations framepars_fops = { owner: THIS_MODULE, llseek: framepars_lseek, write: framepars_write, open: framepars_open, mmap: framepars_mmap, release: framepars_release }; /** * @brief Driver OPEN method * @param inode inode * @param filp file pointer * @return OK - 0, -EINVAL for wrong minor */ 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); MDF1(printk(": minor=0x%x\n",privData-> minor)); switch (privData-> minor) { case CMOSCAM_MINOR_FRAMEPARS : inode->i_size = 0; //or return 8 - number of frame pages? return 0; default: kfree(filp->private_data); // already allocated return -EINVAL; } return res; } /** * @brief Driver RELEASE method * @param inode inode * @param filp file pointer * @return OK - 0, -EINVAL for wrong minor */ int framepars_release(struct inode *inode, struct file *filp) { int res=0; int p = MINOR(inode->i_rdev); MDF1(printk(": minor=0x%x\n",p)); switch ( p ) { case CMOSCAM_MINOR_FRAMEPARS : break; default: return -EINVAL; //! do not need to free anything - "wrong number" } kfree(filp->private_data); return res; } /** * @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 * @param file * @param offset * @param orig SEEK_SET, SEEK_CUR or SEEK_SET END * @return file position (absolute frame number) */ loff_t framepars_lseek (struct file * file, loff_t offset, int orig) { unsigned long target_frame; MDF1(printk(" offset=0x%x, orig=0x%x\n",(int) offset, (int) orig)); switch(orig) { case SEEK_SET: file->f_pos = offset; break; case SEEK_CUR: if (offset==0) return getThisFrameNumber(); /// do not modify frame number file->f_pos = getThisFrameNumber() + offset; /// modifies frame number, but it is better to use absolute SEEK SET break; case SEEK_END: if (offset <= 0) { break; } else if (offset >= LSEEK_FRAME_WAIT_REL) { if (offset >=LSEEK_FRAME_WAIT_ABS) target_frame=offset-LSEEK_FRAME_WAIT_ABS; /// Wait for absolute frame number else target_frame=getThisFrameNumber()+offset-LSEEK_FRAME_WAIT_REL; /// Skip 0..255 frames wait_event_interruptible (framepars_wait_queue,getThisFrameNumber()>=target_frame); // if (getThisFrameNumber()=target_frame); return getThisFrameNumber(); /// Does not modify current frame pointer? lseek (,0,SEEK_CUR) anyway returns getThisFrameNumber() } else { //! Other lseek commands switch (offset & ~0x1f) { case LSEEK_DAEMON_FRAME: /// wait the daemon enabled and a new frame interrupt (sensor frame sync) wait_event_interruptible (framepars_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f))); break; default: switch (offset) { case LSEEK_GET_FPGA_TIME: //X313_GET_FPGA_TIME( GLOBALPARS(G_SECONDS), GLOBALPARS(G_MICROSECONDS) ); MDF2(printk("X313_GET_FPGA_TIME\n")); break; case LSEEK_SET_FPGA_TIME: /// better to use write, not lseek to set FPGA time //X313_SET_FPGA_TIME( GLOBALPARS(G_SECONDS) , GLOBALPARS(G_MICROSECONDS) ); MDF2(printk("X313_SET_FPGA_TIME\n")); break; case LSEEK_FRAMEPARS_INIT: /// reset hardware sequencers, init framepars structure MDF2(printk("LSEEK_FRAMEPARS_INIT\n")); initGlobalPars();/// reset all global parameters but the first 32 initSequencers(); break; case LSEEK_FRAME_RESET: /// reset absoulte frame number to avoid integer frame number overflow MDF2(printk("LSEEK_FRAME_RESET\n")); resetFrameNumber(); break; case LSEEK_SENSORPROC: /// process modified parameters in frame 0 (to start sensor detection) MDF2(printk("LSEEK_SENSORPROC: framepars[0].functions=0x%08lx\n",framepars[0].functions)); processPars (sensorproc, 0, 8); ///frame0, all 8 frames (maxAhead==8) break; case LSEEK_DMA_INIT: /// initialize ETRAX DMA (normally done in sensor_common.c at driver init MDF2(printk("LSEEK_DMA_INIT\n")); //x313_dma_init(); break; case LSEEK_DMA_STOP: /// stop DMA MDF2(printk("LSEEK_DMA_STOP\n")); //x313_dma_stop(); /// break; case LSEEK_DMA_START: /// start DMA MDF2(printk("LSEEK_DMA_START\n")); //x313_dma_start(); /// break; case LSEEK_COMPRESSOR_RESET: /// reset compressor and buffer pointers MDF2(printk("LSEEK_COMPRESSOR_RESET\n")); reset_compressor(); break; case LSEEK_INTERRUPT_OFF: /// disable camera interrupts MDF2(printk ("LSEEK_INTERRUPT_OFF\n")); camera_interrupts (0); break; case LSEEK_INTERRUPT_ON: /// enable camera interrupts MDF2(printk ("LSEEK_INTERRUPT_ON\n")); camera_interrupts (1); break; } } break; } break; default: return -EINVAL; } return file->f_pos ; } /** * @brief Driver WRITE method * writes all at once, no provisions to continue in the next call * @param file * @param buf * @param count * @param off * @return OK - number of bytes written, negative - errors */ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff_t *off) { struct frameparspair_t pars_static[256];/// will be sufficient for most calls struct frameparspair_t * pars = pars_static; struct framepars_pd * privData = (struct framepars_pd *) file->private_data; unsigned long frame=*off; /// ************* NOTE: Never use file->f_pos in write() and read() !!! int latency=-1; int first=0; int last; int result; MDF1(printk(": file->f_pos=0x%x, *off=0x%x, count=0x%x\n", (int) file->f_pos, (int) *off, (int) count)); count &= ~7; /// sizeof (struct frameparspair_t)==8 switch (privData->minor) { case CMOSCAM_MINOR_FRAMEPARS : if (count>sizeof(pars_static)) /// only allocate if static is not enough pars = (struct frameparspair_t *) kmalloc(count, GFP_KERNEL); if (!pars) return -ENOMEM; count >>=3; /// divide by sizeof(struct frameparspair_t); // 8 if(count) { if(copy_from_user((char *) pars, buf, count<<3)) { if (count>sizeof(pars_static)) kfree(pars); return -EFAULT; } while (first sizeof(pars_static)) kfree(pars); return -EFAULT; } first=last; } } if (count>sizeof(pars_static)) kfree(pars); return count<<3; /// *sizeof(struct frameparspair_t); default: return -EINVAL; } } /** * @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 * much longer retained pastparameters - subset of all parameters * @param file * @param vma * @return OK - 0, negative - errors */ int framepars_mmap (struct file *file, struct vm_area_struct *vma) { int result; struct framepars_pd * privData = (struct framepars_pd *) file->private_data; MDF1(printk(": minor=0x%x\n",privData-> minor)); switch (privData->minor) { case CMOSCAM_MINOR_FRAMEPARS : result=remap_pfn_range(vma, vma->vm_start, ((unsigned long) virt_to_phys(frameparsall)) >> PAGE_SHIFT, // Should be page-aligned vma->vm_end-vma->vm_start, vma->vm_page_prot); MDF1(printk("remap_pfn_range returned=%x\r\n",result)); if (result) return -EAGAIN; return 0; default: return -EINVAL; } } /** * @brief framepars driver probing function * @param[in] pdev pointer to \b platform_device structure * @return 0 on success or negative error code otherwise */ static int framepars_init(struct platform_device *pdev) { int res; struct device *dev = &pdev->dev; const struct of_device_id *match; /* sanity check */ match = of_match_device(elphel393_framepars_of_match, dev); if (!match) return -EINVAL; init_framepars_ptr(); initGlobalPars(); /// sets default debug if enabled - not anymore. Add here? initMultiPars(); /// just clear - needs to be called again when sensor is recognized frameParsInitialized=0; res = register_chrdev(FRAMEPARS_MAJOR, "framepars_operations", &framepars_fops); if(res < 0) { printk(KERN_ERR "\nframepars_init: couldn't get a major number %d.\n",FRAMEPARS_MAJOR); return res; } init_waitqueue_head(&framepars_wait_queue); dev_info(dev, "registered MAJOR: %d\n", FRAMEPARS_MAJOR); return 0; } static int framepars_remove(struct platform_device *pdev) { unregister_chrdev(FRAMEPARS_MAJOR, "framepars_operations"); return 0; } 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 = FRAMEPARS_DRIVER_NAME, .of_match_table = elphel393_framepars_of_match, }, }; module_platform_driver(elphel393_framepars); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Andrey Filippov ."); MODULE_DESCRIPTION(X3X3_FRAMEPARS_DRIVER_NAME);