os/linux-2.6-tag--devboard-R2_10-4/arch/cris/arch-v32/drivers/elphel/histograms.c

Go to the documentation of this file.
00001 /*!********************************************************************************
00002 *! FILE NAME  : histograms.c
00003 *! DESCRIPTION: Handles histograms storage, access and percentile calculation
00004 *! Copyright (C) 2008 Elphel, Inc.
00005 *! -----------------------------------------------------------------------------**
00006 *!
00007 *!  This program is free software: you can redistribute it and/or modify
00008 *!  it under the terms of the GNU General Public License as published by
00009 *!  the Free Software Foundation, either version 3 of the License, or
00010 *!  (at your option) any later version.
00011 *!
00012 *!  This program is distributed in the hope that it will be useful,
00013 *!  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 *!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 *!  GNU General Public License for more details.
00016 *!
00017 *!  You should have received a copy of the GNU General Public License
00018 *!  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 *! -----------------------------------------------------------------------------**
00020 *!  $Log: histograms.c,v $
00021 *!  Revision 1.1.1.1  2008/11/27 20:04:00  elphel
00022 *!
00023 *!
00024 *!  Revision 1.17  2008/11/14 07:08:11  elphel
00025 *!  no request for the histogram if past histogram is needed and some exist in the past
00026 *!
00027 *!  Revision 1.16  2008/11/13 05:40:45  elphel
00028 *!  8.0.alpha16 - modified histogram storage, profiling
00029 *!
00030 *!  Revision 1.15  2008/10/29 04:18:28  elphel
00031 *!  v.8.0.alpha10 made a separate structure for global parameters (not related to particular frames in a frame queue)
00032 *!
00033 *!  Revision 1.14  2008/10/28 07:04:28  elphel
00034 *!  driver returns histogram frame number (it lags one frame from the real frame number)
00035 *!
00036 *!  Revision 1.13  2008/10/25 19:59:48  elphel
00037 *!  added lseek() calls to enable/disable daemons at events (compressed frame available, any frame available, histogram-Y and histograms-C available)
00038 *!
00039 *!  Revision 1.12  2008/10/23 18:26:14  elphel
00040 *!  Fixed percentile calculations in histograms
00041 *!
00042 *!  Revision 1.11  2008/10/23 08:05:56  elphel
00043 *!  added 2 wait queues for histogram data - separately for G1 (used as Y for autoexposure) and other color components (for color balancing and histogram display)
00044 *!
00045 *!  Revision 1.10  2008/10/12 16:46:22  elphel
00046 *!  snapshot
00047 *!
00048 *!  Revision 1.9  2008/10/04 16:10:12  elphel
00049 *!  snapshot
00050 *!
00051 *!  Revision 1.8  2008/09/20 00:29:50  elphel
00052 *!  moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h
00053 *!
00054 *!  Revision 1.7  2008/09/12 00:23:59  elphel
00055 *!  removed cc353.c, cc353.h
00056 *!
00057 *!  Revision 1.6  2008/09/07 19:48:09  elphel
00058 *!  snapshot
00059 *!
00060 *!  Revision 1.5  2008/09/05 23:20:26  elphel
00061 *!  just a snapshot
00062 *!
00063 *!  Revision 1.4  2008/07/27 23:25:07  elphel
00064 *!  next snapshot
00065 *!
00066 *!  Revision 1.3  2008/06/16 06:51:21  elphel
00067 *!  work in progress, intermediate commit
00068 *!
00069 *!  Revision 1.2  2008/06/10 00:02:42  elphel
00070 *!  fast calculation of 8-bit reverse functions for "gamma" tables and histograms
00071 *!
00072 *!  Revision 1.1  2008/06/08 23:46:45  elphel
00073 *!  added drivers files for handling quantization tables, gamma tables and the histograms
00074 *!
00075 *!
00076 */
00077 
00078 //copied from cxi2c.c - TODO:remove unneeded 
00079 
00080 #include <linux/module.h>
00081 #include <linux/mm.h>
00082 #include <linux/sched.h>
00083 #include <linux/slab.h>
00084 #include <linux/errno.h>
00085 #include <linux/kernel.h>
00086 #include <linux/fs.h>
00087 #include <linux/string.h>
00088 #include <linux/init.h>
00089 #include <linux/autoconf.h>
00090 #include <linux/vmalloc.h>
00091 
00092 #include <asm/system.h>
00093 #include <asm/byteorder.h> // endians
00094 #include <asm/io.h>
00095 
00096 #include <asm/irq.h>
00097 
00098 #include <asm/delay.h>
00099 #include <asm/uaccess.h>
00100 #include <asm/elphel/driver_numbers.h>
00101 #include <asm/elphel/c313a.h>
00102 #include <asm/elphel/exifa.h>
00103 #include "fpgactrl.h"  // defines port_csp0_addr, port_csp4_addr 
00104 #include "fpga_io.h"//fpga_table_write_nice
00105 #include "framepars.h"        // for debug mask
00106 
00107 //#include "cc3x3.h"
00108 #include "histograms.h"
00109 
00114 #if ELPHEL_DEBUG
00116   #define MDF21(x) { if (GLOBALPARS(G_DEBUG) & (1 <<21)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
00118   #define MDF22(x) { if (GLOBALPARS(G_DEBUG) & (1 <<22)) {printk("%s:%d:%s ",__FILE__,__LINE__,__FUNCTION__);x ;} }
00119 #else
00120   #define MDF21(x)
00121   #define MDF22(x)
00122 #endif
00123 
00124 #define  X3X3_HISTOGRAMS_DRIVER_NAME "Elphel (R) Model 353 Histograms device driver"
00125 
00126 static struct histogram_stuct_t histograms[HISTOGRAM_CACHE_NUMBER] __attribute__ ((aligned (PAGE_SIZE)));
00127 
00128        struct histogram_stuct_t * histograms_p; // to use with mmap
00129 
00130 wait_queue_head_t hist_y_wait_queue;    
00131 wait_queue_head_t hist_c_wait_queue;    
00132 
00133 
00134 struct histograms_pd {
00135     int                minor;
00136     unsigned long      frame;
00137     int                frame_index; 
00138     int                needed;
00139     int                wait_mode;  
00140     int                request_en; 
00141     struct wait_queue *hist_y_wait_queue;    
00142     struct wait_queue *hist_c_wait_queue;    
00143 
00145 };
00146 
00147 int        histograms_open   (struct inode *inode, struct file *file);
00148 int        histograms_release(struct inode *inode, struct file *file);
00149 loff_t     histograms_lseek  (struct file * file, loff_t offset, int orig);
00150 int        histograms_mmap   (struct file *file, struct vm_area_struct *vma);
00151 static int __init histograms_init(void);
00152 
00153 
00154 inline void  histogram_calc_cumul       ( unsigned long * hist,        unsigned long * cumul_hist );
00155 inline void  histogram_calc_percentiles ( unsigned long * cumul_hist,  unsigned char * percentile);
00156 
00157 
00158 /*
00159    unsigned long gtab_r;
00160    unsigned long gtab_g;
00161    unsigned long gtab_gb;
00162    unsigned long gtab_b;
00163 
00164 */
00165 
00169 void init_histograms(void) {
00170   unsigned long flags;
00171   int i;
00172   histograms_p=histograms;
00173   MDF21(printk("\n"));
00174   local_irq_save(flags);
00175   for (i=0; i < HISTOGRAM_CACHE_NUMBER; i++) {
00176     histograms[i].frame=0xffffffff;
00177     histograms[i].valid=0;
00178   }
00179   local_irq_restore(flags);
00180 }
00181 
00193 int set_histograms (unsigned long frame, int needed, unsigned long * gammaHash) {
00194 //  unsigned long flags;
00195 //hist_next_index
00196   int i, color_start;
00197   if (histograms[GLOBALPARS(G_HIST_LAST_INDEX)].frame!=frame) {
00198        GLOBALPARS(G_HIST_LAST_INDEX)=(GLOBALPARS(G_HIST_LAST_INDEX)+1) & (HISTOGRAM_CACHE_NUMBER-1);
00199        histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid=0;     
00200        histograms[GLOBALPARS(G_HIST_LAST_INDEX)].frame=frame; 
00201        memcpy (&(histograms[GLOBALPARS(G_HIST_LAST_INDEX)].gtab_r), gammaHash, 16); // copy provided 4 hash32 values
00202   } else {
00203       needed &= ~histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid; 
00204   }
00205   for (i=0; i<4; i++) if (needed & ( 1 << i )) {
00206     color_start= i<<8 ;
00207     fpga_hist_read_nice (color_start, 256, (unsigned long *) &histograms[GLOBALPARS(G_HIST_LAST_INDEX)].hist[color_start]);
00208     histograms[GLOBALPARS(G_HIST_LAST_INDEX)].valid |= 1 << i;
00209   }
00210   return 0;
00211 }
00212 
00213 
00230 
00231 int get_histograms (unsigned long frame, int needed) {
00232 //  unsigned long flags;
00233 //hist_next_index
00234   int i, color_start;
00235   int index=GLOBALPARS(G_HIST_LAST_INDEX);
00236   int raw_needed=(needed | (needed>>4) | needed>>8) & 0xf;
00237   for (i=0;i<HISTOGRAM_CACHE_NUMBER;i++) {
00238     MDF21(printk("index=%d, needed=0x%x\n",index,needed));
00239     if ((histograms[index].frame <= frame) && ((histograms[index].valid & raw_needed)==raw_needed)) break;
00240     index = (index-1) & (HISTOGRAM_CACHE_NUMBER-1);
00241   }
00242   if (i>=HISTOGRAM_CACHE_NUMBER) {
00243      ELP_KERR(printk("no histograms exist for requested colors (0x$%x), requested 0x%x\n",raw_needed,needed));
00244      return -1; 
00245   }
00246   needed &= ~0x0f; 
00247   MDF22(printk("needed=0x%x\n",needed));
00248   needed |= ((needed >>4) & 0xf0); 
00249   needed &= ~histograms[index].valid;
00251   MDF22(printk("needed=0x%x\n",needed));
00252   if (needed & 0xf0) { 
00253     for (i=0; i<4; i++) if (needed & ( 0x10 << i )) {
00254        color_start= i<<8 ;
00255        histogram_calc_cumul ( (unsigned long *) &histograms[index].hist[color_start],  (unsigned long *) &histograms[index].cumul_hist[color_start] );
00256        histograms[index].valid |= 0x10 << i;
00257     }
00258     MDF21(printk("needed=0x%x, valid=0x%lx\n",needed,histograms[index].valid));
00259   }
00260   if (needed & 0xf00) { 
00261     for (i=0; i<4; i++) if (needed & ( 0x100 << i )) {
00262        color_start= i<<8 ;
00263        histogram_calc_percentiles ( (unsigned long *) &histograms[index].cumul_hist[color_start],  (unsigned char *) &histograms[index].percentile[color_start] );
00264        histograms[index].valid |= 0x100 << i;
00265     }
00266     MDF21(printk("needed=0x%x, valid=0x%lx\n",needed, histograms[index].valid));
00267   }
00268   return index;
00269 }
00270 
00276 inline void  histogram_calc_cumul       ( unsigned long * hist,        unsigned long * cumul_hist ) {
00277   int i;
00278   cumul_hist[0]=hist[0];
00279   for (i=1; i<256;i++) cumul_hist[i]=cumul_hist[i-1]+hist[i];
00280 }
00281 
00300 inline void  histogram_calc_percentiles ( unsigned long * cumul_hist,  unsigned char * percentile) {
00301   unsigned long v256=0; 
00302   unsigned long inc_v256=cumul_hist[255];  
00303   int shiftl=8;
00304   while (inc_v256>0xffffff) { 
00305     inc_v256 >>= 1;
00306     shiftl--;
00307   }
00308   int p=0; 
00309   int x=0; 
00310   while ((p<256) && (x<256)) {
00311     percentile[x]=p;
00312     if ((p<255) && ( (cumul_hist[p] << shiftl) <= v256)) {
00313       p++;
00314     } else {
00315       x++;
00316       v256+=inc_v256;
00317     }
00318   }
00319 }
00320 
00321 
00329 
00333 #define HISTOGRAMS_FILE_SIZE HISTOGRAM_CACHE_NUMBER
00334 static struct file_operations histograms_fops = {
00335    owner:    THIS_MODULE,
00336    llseek:   histograms_lseek,
00337    open:     histograms_open,
00338    mmap:     histograms_mmap,
00339    release:  histograms_release
00340 };
00341 
00348 int histograms_open(struct inode *inode, struct file *file) {
00349    int res;
00350    struct histograms_pd * privData;
00351    privData= (struct histograms_pd *) kmalloc(sizeof(struct histograms_pd),GFP_KERNEL);
00352    if (!privData) return -ENOMEM;
00353    file->private_data = privData;
00354    privData-> minor=MINOR(inode->i_rdev);
00355    MDF21(printk("minor=0x%x\n",privData-> minor));
00356    switch (privData-> minor) {
00357      case  CMOSCAM_MINOR_HISTOGRAMS :
00358         inode->i_size = HISTOGRAMS_FILE_SIZE;
00359         privData->frame=0xffffffff;
00360         privData->frame_index=-1;
00361         privData->needed= 0;
00362         privData->wait_mode=0;  
00363         privData->request_en=1; 
00364         return 0;
00365      default:
00366        kfree(file->private_data); // already allocated
00367        return -EINVAL;
00368    }
00369    file->f_pos = 0;
00370    return res;
00371 }
00372 
00379 int histograms_release(struct inode *inode, struct file *file) {
00380   int res=0;
00381   int p = MINOR(inode->i_rdev);
00382   MDF21(printk("minor=0x%x\n",p));
00383   switch ( p ) {
00384     case  CMOSCAM_MINOR_HISTOGRAMS :
00385         break;
00386     default:
00387         return -EINVAL; 
00388     }
00389   kfree(file->private_data);
00390   return res;
00391 }
00392 
00417 
00418 loff_t histograms_lseek (struct file * file, loff_t offset, int orig) {
00419    struct histograms_pd * privData = (struct histograms_pd *) file->private_data;
00420    unsigned long reqAddr,reqFrame;
00421 
00422  MDF21(printk("offset=0x%x, orig=0x%x\n",(int) offset, (int) orig));
00423    switch (privData->minor) {
00424        case CMOSCAM_MINOR_HISTOGRAMS :
00425          switch(orig) {
00426          case SEEK_CUR: 
00427            offset+=(privData-> wait_mode)?GLOBALPARS(G_HIST_C_FRAME):GLOBALPARS(G_HIST_Y_FRAME);
00428          case SEEK_SET:
00429            privData->frame=offset;
00435            if (privData->request_en) {
00436              reqAddr=(privData-> wait_mode)?P_HISTRQ_C:P_HISTRQ_Y;
00437              reqFrame=getThisFrameNumber();
00438              if (offset > reqFrame) {
00439                if (offset > (reqFrame+5)) reqFrame+=5;
00440                else                       reqFrame=offset;
00441              }
00442              if ((offset < reqFrame) && 
00443                 (((privData->frame_index = get_histograms (offset, privData->needed))) >=0)) {
00444                  file->f_pos=privData->frame_index;
00445                  return file->f_pos;
00446              }
00448              setFramePar(&framepars[reqFrame & PARS_FRAMES_MASK], reqAddr, 1);
00450              if (reqFrame < getThisFrameNumber()) {
00451                setFramePar(&framepars[getThisFrameNumber() & PARS_FRAMES_MASK], reqAddr, 1);
00452              }
00453            }
00454            if (privData-> wait_mode)  wait_event_interruptible (hist_c_wait_queue,GLOBALPARS(G_HIST_C_FRAME)>=offset);
00455            else                       wait_event_interruptible (hist_y_wait_queue,GLOBALPARS(G_HIST_Y_FRAME)>=offset);
00456            privData->frame_index = get_histograms (offset, privData->needed);
00457            if (privData->frame_index <0) {
00458              return -EFAULT;
00459            } else {
00460              file->f_pos=privData->frame_index;
00461              return file->f_pos;
00462            }
00463            break; 
00464          case SEEK_END:
00465            if (offset < 0) {
00466              return -EINVAL;
00467            } else {
00468              if (offset < LSEEK_HIST_NEEDED) {
00469                switch (offset) {
00470                  case 0:
00471                    break;
00472                  case  LSEEK_HIST_REQ_EN: 
00473                    privData->request_en=1; 
00474                    break;
00475                  case  LSEEK_HIST_REQ_DIS: 
00476                    privData->request_en=0;
00477                    break;
00478                  case  LSEEK_HIST_WAIT_Y: 
00479                    privData-> wait_mode=0;
00480                    break;
00481                  case  LSEEK_HIST_WAIT_C: 
00482                    privData-> wait_mode=1;
00483                    break;
00484                  default:
00485                    switch (offset & ~0x1f) {
00486                      case  LSEEK_DAEMON_HIST_Y: 
00487                        MDF21(printk("wait_event_interruptible (hist_y_wait_queue,0x%x & 0x%x)\n",(int) get_imageParamsThis(P_DAEMON_EN), (int) (1<<(offset & 0x1f))));
00488                        wait_event_interruptible (hist_y_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
00489                        break;
00490                      case  LSEEK_DAEMON_HIST_C: 
00491                        MDF21(printk("wait_event_interruptible (hist_c_wait_queue,0x%x & 0x%x)\n",(int) get_imageParamsThis(P_DAEMON_EN), (int) (1<<(offset & 0x1f))));
00492                        wait_event_interruptible (hist_c_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
00493                        break;
00494                      default:
00495                      return -EINVAL;
00496                    }
00497                }
00498              } else if (offset < (LSEEK_HIST_NEEDED + 0x10000)) {
00499                 privData->needed= (offset & 0xffff);
00500              } else  {
00501                return -EINVAL;
00502              }
00503              file->f_pos= HISTOGRAMS_FILE_SIZE;
00504              return file->f_pos;
00505            }
00506            break;
00507          default:  
00508             return -EINVAL;
00509          } 
00510          return  file->f_pos ;
00511        default: 
00512          return -EINVAL;
00513   }
00514 }
00522 int histograms_mmap (struct file *file, struct vm_area_struct *vma) {
00523   int result;
00524   struct histograms_pd * privData = (struct histograms_pd *) file->private_data;
00525   MDF21(printk("minor=0x%x\n",privData-> minor));
00526      switch (privData->minor) {
00527        case  CMOSCAM_MINOR_HISTOGRAMS :
00528            result=remap_pfn_range(vma,
00529                   vma->vm_start,
00530                  ((unsigned long) virt_to_phys(histograms_p)) >> PAGE_SHIFT, 
00531                   vma->vm_end-vma->vm_start,
00532                   vma->vm_page_prot);
00533            MDF21(printk("remap_pfn_range returned=%x\r\n",result));
00534            if (result) return -EAGAIN;
00535            return 0;
00536        default: return -EINVAL;
00537   }
00538 }
00539 
00544 static int __init histograms_init(void) {
00545    int res;
00546    init_histograms();
00547    res = register_chrdev(HISTOGRAMS_MAJOR, "gamma_tables_operations", &histograms_fops);
00548    if(res < 0) {
00549      printk(KERN_ERR "histograms_init: couldn't get a major number %d.\n",HISTOGRAMS_MAJOR);
00550      return res;
00551    }
00552 //   init_waitqueue_head(&histograms_wait_queue);
00553    init_waitqueue_head(&hist_y_wait_queue);    
00554    init_waitqueue_head(&hist_c_wait_queue);    
00555    printk(X3X3_HISTOGRAMS_DRIVER_NAME"\r\n");
00556    return 0;
00557 }
00558 
00559 
00560 module_init(histograms_init);
00561 MODULE_LICENSE("GPLv3.0");
00562 MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
00563 MODULE_DESCRIPTION(X3X3_HISTOGRAMS_DRIVER_NAME);
00564 
00565 
00566 
00567 
00568 
00569 
00570 
00571 
00572 
00573 
00574 
00575 
00576 
00577 
00578 
00579 
00580 
00581 
00582 
00583 
00584 
00585 

Generated on Fri Nov 28 00:06:23 2008 for elphel by  doxygen 1.5.1