00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
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>
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"
00104 #include "fpga_io.h"
00105 #include "framepars.h"
00106
00107
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;
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
00160
00161
00162
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
00195
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);
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
00233
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);
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
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