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

Go to the documentation of this file.
00001 /*
00002  * histogram for autoexposure and control
00003  *
00004  *  This program is free software: you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation, either version 3 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Copyright (C) 2005-2007 Elphel, Inc
00018  *
00019  * Author: Mikhajlo Malishko <spectr@gmail.com>
00020  *
00021  */
00022 
00023 #include <linux/kernel.h>
00024 #include <linux/sched.h>
00025 #include <linux/mm.h>
00026 //#include <linux/tqueue.h>
00027 #include <linux/wait.h>
00028 
00029 #include <asm/unistd.h>
00030 #include <asm/semaphore.h>
00031 //#include <asm/smplock.h>
00032 #include <asm/atomic.h>
00033 
00034 #include <linux/module.h>
00035 #include <linux/slab.h>
00036 #include <linux/errno.h>
00037 #include <linux/fs.h>
00038 #include <linux/string.h>
00039 #include <linux/init.h>
00040 #include <linux/mm.h>
00041 //#include <linux/iobuf.h>
00042 //#include <linux/compatmac.h>
00043 #include <linux/vmalloc.h>
00044 #include <linux/rwsem.h>
00045 
00046 #include <linux/netdevice.h>
00047 #include <linux/skbuff.h>
00048 #include <linux/time.h>
00049 #include <linux/wait.h>
00050 #include <asm/io.h>
00051 #include <asm/atomic.h>
00052 #include <asm/page.h>
00053 //#include <linux/wrapper.h>
00054 
00055 #include "fpgactrl.h"  // defines port_csp0_addr, port_csp4_addr 
00056 
00057 #include <asm/elphel/c313a.h>
00058 #include <asm/elphel/hist.h>
00059 #include <asm/elphel/autoexp.h>
00060 
00061 #include "cc3x3.h"
00062 #include "cxdma.h"
00063 #include "x3x3.h"
00064 #include "hist.h"
00065 #include "fpga_io.h"
00066 
00067 //#include "helper.h"
00068 
00069 #define HIST_MAJOR 130
00070 #define AUTOEXP_MAJOR 131
00071 
00072 #if ELPHEL_DEBUG
00073  #define MD1(x) printk("%s:%d:",__FILE__,__LINE__);x
00074   //#define MD1(x)
00075 #else
00076   #define MD1(x)
00077 #endif
00078 
00079 
00080 
00081 /* log data... */
00082 DECLARE_MUTEX(ae_log_lock);
00083 static struct autoexp_log_t ae_log_buf[LOG_C];
00084 static struct autoexp_log_t *ae_log_p = &ae_log_buf[LOG_C - 1];
00085 static unsigned ae_log_c = 0;
00086 
00087 DECLARE_MUTEX(sensor_lock);
00088 atomic_t sensor_refresh;
00089 DECLARE_MUTEX(iface_lock);
00090 atomic_t autoexp_on;
00091 atomic_t autoexp_enable;
00092 DECLARE_WAIT_QUEUE_HEAD(wq_hist);
00093 static int first_exp = 0;
00094 
00095 DECLARE_MUTEX(autoexp_iface_lock);
00096 
00097 #define BUF_C   2
00098 
00099 struct gamma_t {
00100         unsigned short *buf;
00101         struct timeval tv;
00102 };
00103 struct gamma_t gamma[BUF_C];
00104 
00105 /* RGGB + white reverse + white original */
00106 static unsigned short gamma_table_1[256 * 6];
00107 static unsigned short gamma_table_2[256 * 6];
00108 
00109 static unsigned long c_gamma = 0;
00110 static unsigned long c_hist = 0;
00111 
00112 DECLARE_MUTEX(gamma_lock);
00113 static unsigned short gamma_table[256 * 6] __attribute__ ((aligned (PAGE_SIZE))); // aligne for remap_pfn_range
00114 struct timeval tv_gamma;
00115 
00116 /* --==-- */
00117 struct buf_t {
00118         unsigned long *buf;
00119         struct timeval tv;
00120         struct semaphore lock;
00121 };
00122 struct buf_t buf[BUF_C];
00123 
00124 DECLARE_MUTEX(hist0_lock);
00125 static struct timeval tv_gamma_hb_0;
00126 static unsigned long hb_0[TABLES_LEN] __attribute__ ((aligned (PAGE_SIZE)));
00127 
00128 static unsigned long hb_1[256 * 4 + 256 * 2] __attribute__ ((aligned (PAGE_SIZE)));
00129 static unsigned long hb_2[256 * 4 + 256 * 2] __attribute__ ((aligned (PAGE_SIZE)));
00130 
00131 #define HIST_TABLE_SIZE (256 * 4 * sizeof(u32))
00132 
00133 #define HIST_EXP_MAX_START              4000
00134 #define HIST_OVEREXP_MAX_START  50
00135 #define HIST_EXP_START                  1000
00136 
00137 DECLARE_MUTEX(autoexp_conf_lock);
00138 int autoexp_conf_new = 1;
00140 #if 0
00141 struct autoexp_t autoexp_conf = {
00142         .on = 1,
00143         .width = 80,    /* in percent */
00144         .height = 80,
00145         .left = 50,
00146         .top = 50,
00147         .exp_max = HIST_EXP_MAX_START,
00148         .overexp_max = HIST_OVEREXP_MAX_START,
00149         .s_index = 0,
00150         .s_percent = 0,
00151         .exp = HIST_EXP_START,
00152         .skip_pmin = 500,
00153         .skip_pmax = 5000,
00154         .skip_t = 2,
00155 };
00156 #endif
00158 #if 0
00159 struct autoexp_t state = {
00160         .on = 1,
00161         .exp_max = HIST_EXP_MAX_START,
00162         .overexp_max = HIST_OVEREXP_MAX_START,
00163         .exp = HIST_EXP_START,
00164         .s_index = 0,
00165         .s_percent = 0,
00166         .skip_pmin = 500,
00167         .skip_pmax = 5000,
00168         .skip_t = 2,
00169 };
00170 #endif
00171 int tv_less(struct timeval *tv_1, struct timeval *tv_2) {
00172         if(tv_1->tv_sec < tv_2->tv_sec)
00173                 return 1;
00174         if(tv_1->tv_sec == tv_2->tv_sec)
00175                 if(tv_1->tv_usec <= tv_2->tv_usec)
00176                         return 1;
00177         return 0;
00178 }
00179 
00180 #define GAMMA_COUNT                     200
00181 //#define GAMMA_TABLE_SIZE      256
00182 #define GAMMA_TABLE_SIZE        257
00183 #define _GAMMA_TABLE_SIZE       257
00184 
00185 static unsigned short gamma_tbl[_GAMMA_TABLE_SIZE * GAMMA_COUNT];
00186 //static unsigned short *gamma_ptr = gamma_tbl;
00187 static unsigned short *gamma_ptr = NULL;
00188 //static unsigned long gamma_ptr_order = 0;
00189 
00190 
00191 /*******************************************************************************
00192  * image primitives
00193  */
00194 /*
00195 struct aexp_window_t {
00196         unsigned long width;
00197         unsigned long height;
00198         unsigned long top;
00199         unsigned long left;
00200 };
00201 */
00202 /* real histogram window size & offset */
00204 #if 0
00205 struct aexp_window_t window = {
00206         .width = 0,
00207         .height = 0,
00208         .left = 0,
00209         .top = 0,
00210 };
00211 #endif
00212 /* image from sensor size */
00213 struct aexp_window_t window_sensor = {
00214         .width = 0,
00215         .height = 0,
00216 };
00218 #if 0
00219 /* windows size in percent from user settings */
00220 struct aexp_window_t window_set = {
00221         .width = 80,
00222         .height = 80,
00223         .left = 50,
00224         .top = 50,
00225 };
00226 #endif
00227 atomic_t image_new;
00228 atomic_t image_reprogrammed;
00229 DECLARE_MUTEX(image_lock);
00230 atomic_t sensor_window;
00231 
00232 struct hist_sensor_t sensor_desc;
00233 /*******************************************************************************
00234  *
00235  * init
00236  */
00237 
00238 static int hist__open(struct inode *inode, struct file *filp);
00239 static int hist__release(struct inode *inode, struct file *filp);
00240 static int hist__ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
00241 static int hist__mmap(struct file *filp, struct vm_area_struct *vma);
00242 
00243 static struct file_operations hist__fops = {
00244         owner:          THIS_MODULE,
00245         open:           hist__open,
00246         release:        hist__release,
00247         ioctl:          hist__ioctl,
00248         mmap:           hist__mmap,
00249 };
00250 
00251 static int autoexp__open(struct inode *inode, struct file *filp);
00252 static int autoexp__release(struct inode *inode, struct file *filp);
00253 static ssize_t autoexp__write(struct file *filp, const char *buf, size_t count, loff_t *offp);
00254 static int autoexp__ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
00255 static int autoexp__mmap(struct file *filp, struct vm_area_struct *vma);
00256 
00257 static struct file_operations autoexp__fops = {
00258         owner:          THIS_MODULE,
00259         open:           autoexp__open,
00260         release:        autoexp__release,
00261         write:          autoexp__write,
00262         ioctl:          autoexp__ioctl,
00263         mmap:           autoexp__mmap,
00264 };
00265 
00266 static int __init hist__init(void) {
00267         int i, j;
00268         int res;
00270     autoexp_set->on = 1;
00271     autoexp_set->width = 80;    /* in percent */
00272     autoexp_set->height = 80;
00273     autoexp_set->left = 50;
00274     autoexp_set->top = 50;
00275     autoexp_set->exp_max = HIST_EXP_MAX_START;
00276     autoexp_set->overexp_max = HIST_OVEREXP_MAX_START;
00277     autoexp_set->s_index = 0;
00278     autoexp_set->s_percent = 0;
00279     autoexp_set->exp = HIST_EXP_START;
00280     autoexp_set->skip_pmin = 500;
00281     autoexp_set->skip_pmax = 5000;
00282     autoexp_set->skip_t = 2;
00283 
00284     autoexp_state->on = 1;
00285     autoexp_state->exp_max = HIST_EXP_MAX_START;
00286     autoexp_state->overexp_max = HIST_OVEREXP_MAX_START;
00287     autoexp_state->exp = HIST_EXP_START;
00288     autoexp_state->s_index = 0;
00289     autoexp_state->s_percent = 0;
00290     autoexp_state->skip_pmin = 500;
00291     autoexp_state->skip_pmax = 5000;
00292     autoexp_state->skip_t = 2;
00293 
00294         gamma_ptr = gamma_tbl;
00295 
00296 //static unsigned short gamma_tbl[_GAMMA_TABLE_SIZE * GAMMA_COUNT];
00297 //static unsigned short *gamma_ptr = gamma_tbl;
00298 //      gamma_ptr = (unsigned short *)kmalloc(GAMMA_TABLE_SIZE * GAMMA_COUNT * 2, GFP_ATOMIC);
00299 /*
00300         int size = GAMMA_TABLE_SIZE * GAMMA_COUNT * 2;
00301         printk("gamma sizes == %d\n", size);
00302 //      if(size % PAGE_SIZE != 0)
00303 //              gamma_ptr_order = 1;
00304 //      gamma_ptr_order += size / PAGE_SIZE;
00305         if(size % PAGE_SIZE != 0)
00306                 size += PAGE_SIZE;
00307         size /= PAGE_SIZE;
00308         gamma_ptr_order = 0;
00309         while(size) {
00310                 gamma_ptr_order++;
00311                 size >>= 1;
00312         }
00313 //      gamma_ptr = (unsigned short *)kmalloc(GFP_KERNEL, GAMMA_TABLE_SIZE * GAMMA_COUNT * 4);
00314         gamma_ptr = (unsigned short *)kmalloc(GAMMA_TABLE_SIZE * GAMMA_COUNT * 4, GFP_KERNEL);
00315         gamma_ptr = (unsigned short *)__get_free_pages(GFP_KERNEL, gamma_ptr_order);
00316 printk("gamma_ptr == 0x%08X, order == %d\n", gamma_ptr, gamma_ptr_order);
00317 */
00318         /* register autoexposure device */
00319         res = register_chrdev(HIST_MAJOR, "hist", &hist__fops);
00320         if(res < 0) {
00321                 printk(KERN_ERR "hist: couldn't get a major number.\n");
00322                 return res;
00323         }
00324         /* init buffers */
00325         buf[0].buf = hb_1;
00326         buf[1].buf = hb_2;
00327         for(i = 0; i < BUF_C; i++) {
00328                 buf[i].tv.tv_sec = 0;
00329                 buf[i].tv.tv_usec = 0;
00330                 init_MUTEX(&buf[i].lock);
00331         }
00332         gamma[0].buf = gamma_table_1;
00333         gamma[1].buf = gamma_table_2;
00334         gamma[0].tv.tv_sec = 0;
00335         gamma[0].tv.tv_usec = 0;
00336         gamma[1].tv.tv_sec = 0;
00337         gamma[1].tv.tv_usec = 1;
00338         tv_gamma.tv_sec = 0;
00339         tv_gamma.tv_usec = 0;
00340         tv_gamma_hb_0.tv_sec = 0;
00341         tv_gamma_hb_0.tv_usec = 0;
00342         printk("hist: init ok\n");
00343         /* register control device */
00344         res = register_chrdev(AUTOEXP_MAJOR, "autoexp", &autoexp__fops);
00345         if(res < 0) {
00346                 printk(KERN_ERR "autoexp: couldn't get a major number.\n");
00347                 return res;
00348         }
00349         /* -==- */
00350         for(i = 0; i < 4; i++)
00351                 for(j = 0; j < 256; j++)
00352                         hb_0[i * 256 + j] = j;
00353         for(i = 0; i < 6; i++)
00354                 for(j = 0; j < 256; j++) {
00355                         gamma_table[i * 256 + j] = j + (j << 8);
00356                         gamma_table_1[i * 256 + j] = j + (j << 8);
00357                         gamma_table_2[i * 256 + j] = j + (j << 8);
00358                 }
00359         /* set it for correct start stepping */
00360         atomic_set(&sensor_refresh, 1);
00361         return res;
00362 }
00363 
00364 static void __exit hist__exit(void) {
00365         unregister_chrdev(HIST_MAJOR, "autoexp");
00366         printk("autoexp: exit ok\n");
00367         unregister_chrdev(HIST_MAJOR, "hist");
00368         printk("hist: exit ok\n");
00369 //      __free_pages((unsigned long)gamma_ptr, gamma_ptr_order);
00370 //      kfree(gamma_ptr);
00371 }
00372 
00373 module_init(hist__init);
00374 module_exit(hist__exit);
00375 
00376 /*******************************************************************************
00377  *
00378  * io
00379  */
00380 
00381 
00382 int hist__open(struct inode *inode, struct file *filp) {
00383         if(down_trylock(&iface_lock))
00384                 return -EBUSY;
00385         atomic_set(&autoexp_on, 1);
00386         if(autoexp_state->on)
00387                 atomic_set(&autoexp_enable, 1);
00388         printk("/dev/hist: open()\r\n");
00389         return 0;
00390 }
00391 
00392 int hist__release(struct inode *inode, struct file *filp) {
00393         printk("/dev/hist: release()\r\n");
00394         up(&iface_lock);
00395         /* free/reinit all lock and flags */
00396         atomic_set(&autoexp_on, 0);
00397         atomic_set(&autoexp_enable, 0);
00398         atomic_set(&image_new, 0);
00399         atomic_set(&sensor_window, 0);
00400         init_MUTEX(&sensor_lock);
00401         return 0;
00402 }
00403 
00404 int hist__ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) {
00405         int i;
00406         struct autoexp_t set;
00407         struct autoexp_log_t log;
00408 
00409         switch(_IOC_TYPE(cmd)) {
00410         case IOC_HIST_SET:
00411                 copy_from_user(&set, (const void *)arg, sizeof(set));
00412                 /* refresh sensor */
00413                 if(down_interruptible(&sensor_lock))
00414                         return -EFAULT;
00415                 if(set.exp != 0) {
00416                         if(first_exp >= 3) {
00417                                 sensor_desc.exposure = set.exp;
00418                                 autoexp_set->exp = set.exp;
00419                                 atomic_set(&sensor_refresh, 1);
00420                         }
00421                 }
00422                 up(&sensor_lock);
00423                 /*
00424                  * FPGA window must be refresh immediatelly after done_compress IRQ!
00425                  * in this place - with settin up flag "for_fist"
00426                  */
00427                 if(down_interruptible(&image_lock) == 0) {
00428                         if(aexp_window_set->width != set.width || aexp_window_set->height != set.height || aexp_window_set->left != set.left || aexp_window_set->top != set.top) {
00429                                 if(set.width != HIST_NOT_CHANGE)
00430                                         aexp_window_set->width = set.width;
00431                                 if(set.height != HIST_NOT_CHANGE)
00432                                         aexp_window_set->height = set.height;
00433                                 if(set.left != HIST_NOT_CHANGE)
00434                                         aexp_window_set->left = set.left;
00435                                 if(set.top != HIST_NOT_CHANGE)
00436                                         aexp_window_set->top = set.top;
00437                                 atomic_set(&image_new, 1);
00438                         }
00439                         up(&image_lock);
00440                 }
00441 
00442                 break;
00443         case IOC_HIST_SET_LOG:
00444                 copy_from_user(&log, (const void *)arg, sizeof(log));
00445                 down(&ae_log_lock);
00446                 if(ae_log_p == ae_log_buf)
00447                         ae_log_p = &ae_log_buf[LOG_C - 1];
00448                 else
00449                         ae_log_p--;
00450                 if(ae_log_c < LOG_C)
00451                         ae_log_c++;
00452                 port_csp0_addr[X313_WA_RTC_LATCH] = 0xFF;
00453                 log.tv_sec = port_csp0_addr[X313_RA_RTC_SEC];
00454                 log.tv_usec = port_csp0_addr[X313_RA_RTC_USEC];
00455                 memcpy((void *)ae_log_p, (void *)&log, sizeof(struct autoexp_log_t));
00456                 up(&ae_log_lock);
00457                 break;
00458         case IOC_HIST_GET:
00459                 /* wait for new, or if exist, last, histogramm */
00460                 while(1) {
00461                         /* check for new settings... */
00462                         i = 0;
00463                         down(&autoexp_conf_lock);
00464                         if(autoexp_conf_new) {
00465                                 autoexp_conf_new = 0;
00466 //                              copy_to_user((void *)arg, &autoexp_conf, sizeof(autoexp_conf));
00467                                 copy_to_user((void *)arg, autoexp_set, sizeof(*autoexp_set));
00468                                 i = 1;
00469                         }
00470                         up(&autoexp_conf_lock);
00471                         if(i != 0)
00472                                 return REZ_HIST_CONF;
00473                         /* try to get new histogramm */
00474                         for(i = 0; i < BUF_C; i++) {
00475                                 if(down_trylock(&buf[i].lock))
00476                                         continue;
00477                                 if(buf[i].tv.tv_sec == 0 && buf[i].tv.tv_usec == 0) {
00478                                         up(&buf[i].lock);
00479                                         continue;
00480                                 }
00481                                 /* copy image size to user */
00482                                 filp->private_data = (void *)&buf[i];
00483                                 return REZ_HIST_TABLE;
00484                         }
00485                         interruptible_sleep_on(&wq_hist);
00486                 }
00487                 break;
00488         default:
00489                 return -EFAULT;
00490         }
00491         return 0;
00492 }
00493 
00494 static void hist__vma_open(struct vm_area_struct *vma);
00495 static void hist__vma_close(struct vm_area_struct *vma);
00496 static struct vm_operations_struct hist__vm_ops = {
00497         .open = hist__vma_open,
00498         .close = hist__vma_close,
00499 };
00500 
00501 int hist__mmap(struct file *filp, struct vm_area_struct *vma) {
00502         int res = 0;
00503         struct buf_t *b;
00504 
00505         b = (struct buf_t *)filp->private_data;
00506         if(b == NULL)
00507                 return -EFAULT;
00508         if(b->tv.tv_sec == 0 && b->tv.tv_usec == 0)
00509                 return -EFAULT;
00510         vma->vm_private_data = filp->private_data;
00511         vma->vm_ops = &hist__vm_ops;
00512 //printk("vma->vm_start == %d; vma->vm_end == %d\r\n", vma->vm_start, vma->vm_end);
00513 //      res = remap_page_range(   vma->vm_start, virt_to_phys(b->buf), vma->vm_end - vma->vm_start, vma->vm_page_prot);
00514 
00515 //NOTE: hope b->buf is one of aligned (PAGE_SIZE)
00516    res = remap_pfn_range(vma,vma->vm_start, virt_to_phys(b->buf) >> PAGE_SHIFT,vma->vm_end-vma->vm_start,vma->vm_page_prot);
00517 
00518         hist__vma_open(vma);
00519         return res;
00520 }
00521 
00522 void hist__vma_open(struct vm_area_struct *vma) {
00523 }
00524 
00525 void hist__vma_close(struct vm_area_struct *vma) {
00526         struct buf_t *b;
00527         b = (struct buf_t *)vma->vm_private_data;
00528         b->tv.tv_sec = 0;
00529         b->tv.tv_usec = 0;
00530         up(&b->lock);
00531 }
00532 
00533 /*******************************************************************************
00534  *
00535  * work
00536  */
00537 
00538 #define STEP_INIT       0x00
00539 #define STEP_1          0x01
00540 #define STEP_2          0x02
00541 #define STEP_3          0x03
00542 #define STEP_4          0x04
00543 
00544 //extern int program_sensor_exposition(void);
00545 
00546 void hist_irq(unsigned long src) {
00547         static int step = STEP_INIT;
00548 //      static int may_read_histogram = 0;
00549 //      static int window_changed = 0;
00550         int i;
00551         int flag;
00552 //      static int ae_on_last = 0;
00553         int ae_on = 0;
00554         struct timeval tv;
00555 
00556         struct buf_t *b;
00557         unsigned short *_g;
00558         struct gamma_t *g_1;
00559         struct gamma_t *g_2;
00560 
00561         do_gettimeofday(&tv);
00562 
00563 //printk("\n\nhist_irq\n");
00564         if(atomic_read(&autoexp_enable) != 0)
00565                 ae_on = 1;
00566         /* reprogramm FPGA histogram window... */
00567         /*
00568          * after this - start to STEP_2
00569          */
00570         if(atomic_read(&sensor_window) != 0) {
00571                 atomic_set(&sensor_window, 0);
00572                 step = STEP_1;
00573         }
00574         if(atomic_read(&image_new) != 0) {
00575                 /* not "real" lock - simple check for correct struct! */
00576                 if(!down_trylock(&image_lock)) {
00577                         atomic_set(&image_new, 0);
00578                         /* calculate window width */
00579                         aexp_window->width = (window_sensor.width * aexp_window_set->width) / 100;
00580                         aexp_window->left = ((window_sensor.width - aexp_window->width) * aexp_window_set->left) / 100;
00581                         aexp_window->left += 2;
00582                         aexp_window->height = (window_sensor.height * aexp_window_set->height) / 100;
00583                         aexp_window->top = ((window_sensor.height - aexp_window->height) * aexp_window_set->top) / 100;
00584                         aexp_window->top += 2;
00585                         aexp_window->top &= 0xFFFE;
00586                         /* align histogram window */
00587                         if(aexp_window->width != 0 && aexp_window->height != 0) {
00588                                 port_csp0_addr[X313_WA_HIST_SIZE] = (((aexp_window->height - 1) & 0xFFFF) << 16) + ((aexp_window->width - 1) & 0xFFFF);
00589                                 port_csp0_addr[X313_WA_HIST_POS] = ((aexp_window->top & 0xFFFF) << 16) + (aexp_window->left & 0xFFFF);
00590                         }
00591                         if(step != STEP_INIT)
00592                                 step = STEP_2;
00593                         else
00594                                 step = STEP_1;
00595                         up(&image_lock);
00596                 }
00597         }
00598         /*
00599          * reprogram sensor exposition time...
00600          * start in STEP_1
00601          */
00602         if(ae_on) {
00603                 if(atomic_read(&sensor_refresh) != 0) {
00604                         if(program_sensor_exposition() != 0)
00605                                 return;
00606                         atomic_set(&sensor_refresh, 0);
00607                         step = STEP_1;
00608                 }
00609         }
00610         /*
00611          * if histogramm is really correct...
00612          * if apply any changes - step != STEP_4 in previous code, and histogramm changes skipped
00613          */
00614 //      if(step == STEP_4 || ae_on == 0) {
00615         if(step == STEP_4) {
00616                 for(i = 0; i < 256 * 4; i++) {
00617                         port_csp0_addr[X313_WA_HIST_ADDR] = i;
00618                         hb_0[i] = port_csp4_addr[X313_RA_HIST_DATA];
00619                 }
00620                 memcpy(((void *)hb_0) + OFFSET_HIST_C, &c_hist, 4);
00621                 c_hist++;
00622                 /* update gamma, if needed... */
00623                 if(tv_less(&tv_gamma_hb_0, &tv_gamma)) {
00624                         if(!down_trylock(&gamma_lock)) {
00625                                 memcpy(((void *)hb_0) + 256 * 4 * 4, (void *)gamma_table, 256 * 6 * 2);
00626 //                              do_gettimeofday(&tv_gamma_hb_0);
00627                                 tv_gamma_hb_0 = tv;
00628                                 up(&gamma_lock);
00629                         }
00630                 }
00631         }
00632         /* check steps */
00633 //      if(ae_on == 1 && ae_on_last == 0)
00634 //              step = STEP_4;
00635 //      ae_on_last = ae_on;
00636 //      if(ae_on == 0 )
00637 //              return;
00638 
00639         switch(step) {
00640         /* in this part - wait for camera initialization... */
00641         case STEP_INIT:
00642                 break;
00643         /* in this step, some parts reprogrammed - and changes apply only in STEP_2 */
00644         case STEP_1:
00645                 step = STEP_2;
00646                 break;
00647         /* changes applyed - and this frame is "bad" - skip it! */
00648         case STEP_2:
00649                 step = STEP_3;
00650                 break;
00651         /* this frame is "good" - wait to result of this frame... */
00652         case STEP_3:
00653                 step = STEP_4;
00654                 break;
00655         /* ok! - this time histogramm is correct... */
00656         case STEP_4:
00657                 if(ae_on == 0)
00658                         break;
00659                 /* ...write histogram in free buffer... */
00660                 flag = 1;
00661                 for(i = 0; i < BUF_C; i++) {
00662                         if(down_trylock(&buf[i].lock))
00663                                 continue;
00664                         flag = 0;
00665                         b = &buf[i];
00666                         _g = (unsigned short *)(((void *)b->buf) + 1024 * 4);
00667                         memcpy((void *)b->buf, (void *)hb_0, 256 * 4 * 4);
00668                         b->tv = tv;
00669                         /* copy reverse and original gamma */
00670                         if(tv_less(&gamma[0].tv, &gamma[1].tv)) {
00671                                 g_1 = &gamma[0];
00672                                 g_2 = &gamma[1];
00673                         } else {
00674                                 g_1 = &gamma[1];
00675                                 g_2 = &gamma[0];
00676                         }
00677                         if(g_1->tv.tv_sec == 0)
00678                                 g_1 = g_2;
00679                         else {
00680                                 if(tv_less(&b->tv, &g_2->tv))
00681                                         g_1 = g_1;
00682                                 else
00683                                         g_1 = g_2;
00684                         }
00685                         memcpy((void *)_g, (void *)g_1->buf + 256 * 4 * 2, 256 * 2 * 2);
00686                         /* --==-- */
00687                         up(&b->lock);
00688                         break;
00689                 }
00690                 /* ...and awake for mmap */
00691                 if(flag == 0)
00692                         wake_up_interruptible(&wq_hist);
00693                 /*
00694                  * ok - not apply changes - only wait for sensor_refresh to change step, if application want it
00695                  * or - window changed, and step's cycle restart...
00696                  * i.e. in this part step not changed directly!
00697                  */
00698                 break;
00699         default:
00700                 break;
00701         }
00702 
00703         return;
00704 }
00705 
00706 void hist_irq__(unsigned long src) {
00707 
00708         static int step = STEP_INIT;
00709 
00710         unsigned long i;
00711         struct buf_t *b;
00712         static unsigned long _width = 0;
00713         static unsigned long _height = 0;
00714         unsigned short *_g;
00715         struct gamma_t *g_1;
00716         struct gamma_t *g_2;
00717         struct timeval tv;
00718 
00719         static int src_done_c = 0;
00720         int in_busy_skip = 1;
00721 
00723         if(src == IRQ_SRC_VACT)
00724                 src_done_c = 0;
00725         else {
00726                 src_done_c++;
00727                 if(src_done_c < 2)
00728                         return;
00729                 src_done_c--;
00730         }
00731         do_gettimeofday(&tv);
00732 //*/
00733         /* --==-- */
00734         for(i = 0; i < 256 * 4; i++) {
00735                 port_csp0_addr[X313_WA_HIST_ADDR] = i;
00736                 hb_0[i] = port_csp4_addr[X313_RA_HIST_DATA];
00737                 if((hb_0[i] & 0xFFFC0000) != 0x00000000)
00738                         printk("hist[%ld] == 0x%08lX (0x%08lX) - %d:%d\r\n", i, hb_0[i], hb_0[i] & 0xFFFC0000, (int) tv.tv_sec, (int) tv.tv_usec);
00739         }
00740         memcpy(((void *)hb_0) + OFFSET_HIST_C, &c_hist, 4);
00741         c_hist++;
00742         /* update gamma, if needed... */
00743         if(tv_less(&tv_gamma_hb_0, &tv_gamma)) {
00744                 if(down_trylock(&gamma_lock)) {
00745                         memcpy(((void *)hb_0) + 256 * 4 * 4, (void *)gamma_table, 256 * 6 * 2);
00746                         do_gettimeofday(&tv_gamma_hb_0);
00747                         up(&gamma_lock);
00748                 }
00749         }
00750         /* this work not needed for any - skip */
00751         if(atomic_read(&autoexp_enable) == 0) {
00752                 /* reset stepping cycle */
00753                 if(step != STEP_INIT)
00754                         step = STEP_1;
00755                 return;
00756         }
00757         /* 4 - stepping cycle */
00758 restep:
00759         switch(step) {
00760         /* all driver system not initialized - check for image reprogramming, and skip next frame  */
00761         case STEP_INIT:
00762                 if(atomic_read(&image_reprogrammed) != 0)
00763                         atomic_inc(&image_reprogrammed);
00764                 if(atomic_read(&image_reprogrammed) == 3) {
00765                         atomic_set(&image_reprogrammed, 0);
00766                         step = STEP_1;
00767 //                      atomic_set(&sensor_refresh, 1);
00768                         goto restep;
00769                 }
00770                 break;
00771         /*
00772          * apply (new histogram windowing) and new exposure
00773          */
00774         case STEP_1:
00775                 if(atomic_read(&image_reprogrammed) == 1) {
00776                         step = STEP_INIT;
00777                         goto restep;
00778                 }
00779 //              atomic_set(&image_reprogrammed, 0);
00780                 /* set new histogram window */
00781                 _width = aexp_window->width;
00782                 _height = aexp_window->height;
00783                 if(atomic_read(&image_new) != 0) {
00784                         /* not "real" lock - simple check for correct struct! */
00785                         if(down_trylock(&image_lock))
00786                                 break;
00787                         atomic_set(&image_new, 0);
00788                         /* calculate window width */
00789                         aexp_window->width = (window_sensor.width * aexp_window_set->width) / 100;
00790                         aexp_window->left = ((window_sensor.width - aexp_window->width) * aexp_window_set->left) / 100;
00791                         aexp_window->left += 2;
00792                         aexp_window->height = (window_sensor.height * aexp_window_set->height) / 100;
00793                         aexp_window->top = ((window_sensor.height - aexp_window->height) * aexp_window_set->top) / 100;
00794                         aexp_window->top += 2;
00795                         aexp_window->top &= 0xFFFE;
00796                         /* align histogram window */
00797                         if(aexp_window->width != 0 && aexp_window->height != 0) {
00798                                 port_csp0_addr[X313_WA_HIST_SIZE] = (((aexp_window->height - 1) & 0xFFFF) << 16) + ((aexp_window->width - 1) & 0xFFFF);
00799                                 port_csp0_addr[X313_WA_HIST_POS] = ((aexp_window->top & 0xFFFF) << 16) + (aexp_window->left & 0xFFFF);
00800                         }
00801                         up(&image_lock);
00802                 }
00803                 /* reprogram sensor exposition time */
00804                 /* wait for new exposure value */
00805                 if(atomic_read(&sensor_refresh) == 0)
00806                         return;
00807                 if(program_sensor_exposition() != 0)
00808                         break;
00809 //              atomic_set(&sensor_refresh, 0);
00810                 atomic_set(&image_reprogrammed, 0);
00811                 step = STEP_2;
00812 /*
00813                 if(atomic_read(&image_reprogrammed) == 1) {
00814                         step = STEP_INIT;
00815                         goto restep;
00816                 }
00817 */
00818                 break;
00819         /*
00820          * it's bad frame - just skip it, and relook if image reprogramming - return to STEP_1
00821          */
00822         case STEP_2:
00823                 if(atomic_read(&image_reprogrammed) != 0) {
00824                         step = STEP_1;
00825                         goto restep;
00826                 }
00827                 step = STEP_3;
00828                 break;
00829         /*
00830          * it's good frame - simple wait for next interrupt with 'good' histogram, if image reprogramming - return to STEP_2
00831          */
00832         case STEP_3:
00833                 if(atomic_read(&image_reprogrammed) != 0) {
00834                         step = STEP_1;
00835                         goto restep;
00836                 }
00837                 step = STEP_4;
00838                 break;
00839         /*
00840          * ok - now return correct histogram and wait for results in next interrupt
00841          */
00842         case STEP_4:
00843                 /* previous histogram not correct programmed - wait for new... */
00844                 if(_width == 0 || _height == 0) {
00845                         step = STEP_1;
00846                         return;
00847                 }
00848                 /* ...read histogram in free buffer... */
00849                 for(i = 0; i < BUF_C; i++) {
00850                         if(down_trylock(&buf[i].lock))
00851                                 continue;
00852                         in_busy_skip = 0;
00853                         b = &buf[i];
00854                         _g = (unsigned short *)(((void *)b->buf) + 1024 * 4);
00855                         memcpy((void *)b->buf, (void *)hb_0, 256 * 4 * 4);
00856                         b->tv = tv;
00857                         /* copy reverse and original gamma */
00858                         if(tv_less(&gamma[0].tv, &gamma[1].tv)) {
00859                                 g_1 = &gamma[0];
00860                                 g_2 = &gamma[1];
00861                         } else {
00862                                 g_1 = &gamma[1];
00863                                 g_2 = &gamma[0];
00864                         }
00865                         if(g_1->tv.tv_sec == 0)
00866                                 g_1 = g_2;
00867                         else {
00868                                 if(tv_less(&b->tv, &g_2->tv))
00869                                         g_1 = g_1;
00870                                 else
00871                                         g_1 = g_2;
00872                         }
00873                         memcpy((void *)_g, (void *)g_1->buf + 256 * 4 * 2, 256 * 2 * 2);
00874                         /* --==-- */
00875                         up(&b->lock);
00876                         break;
00877                 }
00878                 /* ...and awake for mmap */
00879                 if(in_busy_skip == 0) {
00880                         wake_up_interruptible(&wq_hist);
00881                         step = STEP_1;
00882                 }
00883                 break;
00884         default:
00885                 return;
00886         }
00887 }
00888 
00889 struct hist_sensor_t *hist_sensor_lock(void) {
00890         if(atomic_read(&autoexp_enable) == 0)
00891                 return NULL;
00892         if(down_interruptible(&sensor_lock))
00893                 return NULL;
00894         if(first_exp < 3) {
00895                 first_exp++;
00896 //printk("hist_sensor_up: autoexp_state->exp = %lu, first_exp == %d\r\n", autoexp_state->exp, first_exp);
00897                 sensor_desc.exposure = autoexp_state->exp;
00898         }
00899         return &sensor_desc;
00900 }
00901 
00902 void hist_sensor_unlock(void) {
00903         up(&sensor_lock);
00904 }
00905 
00906 void hist_image_exp(unsigned long exp) {
00907         if(first_exp < 3) {
00908                 autoexp_set->exp = exp;
00909                 autoexp_state->exp = exp;
00910 //printk("hist_image_exp: exp == %lu\r\n", exp);
00911         }
00912 }
00913 
00914 void hist_image_size(unsigned long width, unsigned long height) {
00915         if(window_sensor.width != width || window_sensor.height != height) {
00916                 down(&image_lock);
00917                 window_sensor.width = width - 4;
00918                 window_sensor.height = height - 4;
00919                 atomic_set(&image_new, 1);
00920 //              atomic_set(&image_reprogrammed, 1);
00921                 atomic_set(&sensor_window, 1);
00922                 up(&image_lock);
00923         }
00924 }
00925 
00926 void window2state (void) {
00927                         autoexp_state->width = aexp_window_set->width;
00928                         autoexp_state->height = aexp_window_set->height;
00929                         autoexp_state->left = aexp_window_set->left;
00930                         autoexp_state->top = aexp_window_set->top;
00931 //                      autoexp_state->exp = sensor_desc.exposure;
00932                         autoexp_state->exp = get_imageParamsR(P_EXPOS);
00933 //                      copy_to_user((void *)arg, &state, sizeof(state));
00934 }
00935 void get_autoexposure_parameters(void) 
00936 {
00937                 if(down_interruptible(&autoexp_conf_lock) == 0) {
00938 //                      copy_from_user(autoexp_set, (const void *)arg, sizeof(*autoexp_set));
00939                         window2state();
00940                         up(&autoexp_conf_lock);
00941                 }
00942 }
00943 
00944 
00945 void set2state(void) 
00946 {
00947                         autoexp_conf_new = 1;
00948                         if(autoexp_set->on != 0 && autoexp_set->on != HIST_NOT_CHANGE) {
00949                                 autoexp_state->on = 1;
00950 //                              if(atomic_read(&autoexp_on) != 0)
00951                                 atomic_set(&autoexp_enable, 1);
00952                         }
00953                         if(autoexp_set->on == 0) {
00954                                 autoexp_state->on = 0;
00955                                 atomic_set(&autoexp_enable, 0);
00956                                 exposition_unlock();
00957 //printk("");
00958                         }
00959                         if(autoexp_set->s_index != HIST_NOT_CHANGE)
00960                                 autoexp_state->s_index = autoexp_set->s_index;
00961                         if(autoexp_set->s_percent != HIST_NOT_CHANGE)
00962                                 autoexp_state->s_percent = autoexp_set->s_percent;
00963                         if(autoexp_set->overexp_max != HIST_NOT_CHANGE)
00964                                 autoexp_state->overexp_max = autoexp_set->overexp_max;
00965                         if(autoexp_set->exp_max != HIST_NOT_CHANGE)
00966                                 autoexp_state->exp_max = autoexp_set->exp_max;
00967                         if(autoexp_set->skip_pmin != HIST_NOT_CHANGE)
00968                                 autoexp_state->skip_pmin = autoexp_set->skip_pmin;
00969                         if(autoexp_set->skip_pmax != HIST_NOT_CHANGE)
00970                                 autoexp_state->skip_pmax = autoexp_set->skip_pmax;
00971                         if(autoexp_set->skip_t != HIST_NOT_CHANGE)
00972                                 autoexp_state->skip_t = autoexp_set->skip_t;
00973 }
00974 void set_autoexposure_parameters(void) 
00975 {
00976                 if(down_interruptible(&autoexp_conf_lock) == 0) {
00977 //                      copy_from_user(autoexp_set, (const void *)arg, sizeof(*autoexp_set));
00978                         set2state(); 
00979                         up(&autoexp_conf_lock);
00980                         wake_up_interruptible(&wq_hist);
00981                 }
00982 }
00983 
00984 /*******************************************************************************
00985  *
00986  * gamma
00987  */
00988 
00989 /*
00990 #define GAMMA_COUNT                     200
00991 //#define GAMMA_TABLE_SIZE      256
00992 #define GAMMA_TABLE_SIZE        257
00993 #define _GAMMA_TABLE_SIZE       257
00994 
00995 //static unsigned short gamma_tbl[_GAMMA_TABLE_SIZE * GAMMA_COUNT];
00996 //static unsigned short *gamma_ptr = gamma_tbl;
00997 static unsigned short *gamma_ptr = NULL;
00998 */
00999 
01000 void __add_gamma(unsigned short index, unsigned short *table) {
01001         unsigned short *ptr;
01002         unsigned short value;
01003         int i;
01004 
01005         if(index >= GAMMA_COUNT) {
01006                 printk("gamma fault! index == %d\r\n", index);
01007                 return;
01008         }
01009         value = table[0];
01010         if(value == 0 || value > GAMMA_COUNT) {
01011                 printk("gamma fault! value == %d\r\n", value);
01012                 return;
01013         }
01014         ptr = gamma_ptr + (value - 1) * GAMMA_TABLE_SIZE;
01015         for(i = 0; i < GAMMA_TABLE_SIZE; i++)
01016                 ptr[i] = (table[i + 1] >> 8) + (0xFF00 & (table[i + 1] << 8));
01017 }
01018 
01019 /*******************************************************************************
01020  *
01021  * autoexp
01022  */
01023 
01024 extern unsigned long *ccam_dma;
01025 
01026 #define _WRITE_GAMMA                    0x10
01027 #define _WRITE_GAMMA_BUF                (2 + _GAMMA_TABLE_SIZE * 2)
01028 
01029 struct autoexp_context_t {
01030         int write;
01031         int count;
01032         unsigned char *buf;
01033         int buf_fill;
01034         int c;
01035 };
01036 
01037 static int autoexp__open(struct inode *inode, struct file *filp) {
01038         filp->private_data = NULL;
01039         return 0;
01040 }
01041 
01042 static int autoexp__release(struct inode *inode, struct file *filp) {
01043         if(filp->private_data)
01044                 kfree(filp->private_data);
01045         return 0;
01046 }
01047 
01048 static int fill_buffer(int c_query, const char *buf, size_t count, size_t *offset, struct autoexp_context_t *c) {
01049         int r = 0;
01050         int len;
01051 
01052         len = c_query - c->buf_fill;
01053         if(len > count)
01054                 len = count;
01055         r = copy_from_user((void *)&c->buf[c->buf_fill], &buf[*offset], len);
01056         c->buf_fill += len;
01057         *offset += len;
01058         return len;
01059 }
01060 
01061 static ssize_t autoexp__write(struct file *filp, const char *buf, size_t count, loff_t *offp) {
01062         struct autoexp_context_t *c;
01063         size_t offset = 0;
01064         size_t ret = count;
01065 
01066         c = (struct autoexp_context_t *)filp->private_data;
01067         if(c == NULL) {
01068                 return -EFAULT;
01069 //              printk("filp->private_data == NULL\n");
01070         }
01071         switch(c->write) {
01072                 case _WRITE_GAMMA:
01073                         while(count) {
01074                                 count -= fill_buffer(_WRITE_GAMMA_BUF, buf, count, &offset, c);
01075                                 if(c->buf_fill == _WRITE_GAMMA_BUF) {
01076                                         __add_gamma(c->c, (unsigned short *)c->buf);
01077                                         c->c++;
01078                                         c->buf_fill = 0;
01079                                 }
01080                         }
01081                         break;
01082                 default: {
01083 //                      printk("c->write != _WRITE_GAMMA\n");
01084                         return -EFAULT;
01085                 }
01086         }
01087         *offp += ret;
01088         return ret;
01089 }
01090 
01091 static int autoexp__ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) {
01092         struct autoexp_context_t *c;
01093         int ae_c;
01094         int r, t;
01095 
01096         switch(_IOC_TYPE(cmd)) {
01097         case IOC_AUTOEXP_GET_LOG:
01098                 ae_c = _IOC_NR(cmd);
01099                 if(ae_c > LOG_C)
01100                         return -EFAULT;
01101                 if(ae_log_c == 0)
01102                         return -EFAULT;
01103                 if(down_interruptible(&ae_log_lock))
01104                         return -EFAULT;
01105                 if(ae_c > ae_log_c)
01106                         ae_c = ae_log_c;
01107                 r = ae_c;
01108                 if(ae_log_c == LOG_C) {
01109                         t = &ae_log_buf[LOG_C] - ae_log_p;
01110                         if(ae_c <= t) {
01111                                 copy_to_user((void *)arg, (void *)ae_log_p, ae_c * sizeof(struct autoexp_log_t));
01112                         } else {
01113                                 copy_to_user((void *)arg, (void *)ae_log_p, t * sizeof(struct autoexp_log_t));
01114                                 ae_c -= t;
01115                                 copy_to_user((void *)(arg + sizeof(struct autoexp_log_t) * t), (void *)ae_log_buf, ae_c * sizeof(struct autoexp_log_t));
01116                         }
01117                 } else {
01118                         copy_to_user((void *)arg, (void *)ae_log_p, ae_c * sizeof(struct autoexp_log_t));
01119                 }
01120                 up(&ae_log_lock);
01121                 return r;
01122         case IOC_AUTOEXP_SET:
01123                 /* if width and height changed - refresh */
01124 //printk("s ");
01125                 if(down_interruptible(&autoexp_conf_lock) == 0) {
01126 //                      copy_from_user(&autoexp_conf, (const void *)arg, sizeof(autoexp_conf));
01127                         copy_from_user(autoexp_set, (const void *)arg, sizeof(*autoexp_set));
01128                         set2state(); 
01129 #if 0
01130                         autoexp_conf_new = 1;
01131                         if(autoexp_set->on != 0 && autoexp_set->on != HIST_NOT_CHANGE) {
01132                                 autoexp_state->on = 1;
01133 //                              if(atomic_read(&autoexp_on) != 0)
01134                                 atomic_set(&autoexp_enable, 1);
01135                         }
01136                         if(autoexp_set->on == 0) {
01137                                 autoexp_state->on = 0;
01138                                 atomic_set(&autoexp_enable, 0);
01139                                 exposition_unlock();
01140 //printk("");
01141                         }
01142                         if(autoexp_set->s_index != HIST_NOT_CHANGE)
01143                                 autoexp_state->s_index = autoexp_set->s_index;
01144                         if(autoexp_set->s_percent != HIST_NOT_CHANGE)
01145                                 autoexp_state->s_percent = autoexp_set->s_percent;
01146                         if(autoexp_set->overexp_max != HIST_NOT_CHANGE)
01147                                 autoexp_state->overexp_max = autoexp_set->overexp_max;
01148                         if(autoexp_set->exp_max != HIST_NOT_CHANGE)
01149                                 autoexp_state->exp_max = autoexp_set->exp_max;
01150                         if(autoexp_set->skip_pmin != HIST_NOT_CHANGE)
01151                                 autoexp_state->skip_pmin = autoexp_set->skip_pmin;
01152                         if(autoexp_set->skip_pmax != HIST_NOT_CHANGE)
01153                                 autoexp_state->skip_pmax = autoexp_set->skip_pmax;
01154                         if(autoexp_set->skip_t != HIST_NOT_CHANGE)
01155                                 autoexp_state->skip_t = autoexp_set->skip_t;
01156 #endif
01157                         up(&autoexp_conf_lock);
01158                         wake_up_interruptible(&wq_hist);
01159                 }
01160 //printk("S ");
01161                 break;
01162         case IOC_AUTOEXP_GET:
01163 //printk("g ");
01164                 if(down_interruptible(&autoexp_conf_lock) == 0) {
01165          window2state();
01166 #if 0
01167 //                      autoexp_state->exp_max = autoexp_set->exp_max;
01168 //                      autoexp_state->overexp_max = autoexp_set->overexp_max;
01169 //                      autoexp_state->exp = autoexp_set->exp;
01170 //                      autoexp_state->on = atomic_read(&autoexp_on);
01172                         autoexp_state->width = aexp_window_set->width;
01173                         autoexp_state->height = aexp_window_set->height;
01174                         autoexp_state->left = aexp_window_set->left;
01175                         autoexp_state->top = aexp_window_set->top;
01176 //                      autoexp_state->exp = sensor_desc.exposure;
01177                         autoexp_state->exp = get_imageParamsR(P_EXPOS);
01178 #endif
01179 //                      copy_to_user((void *)arg, &state, sizeof(state));
01180                         copy_to_user((void *)arg, autoexp_state, sizeof(*autoexp_state));
01181                         up(&autoexp_conf_lock);
01182                 }
01183 //printk("G ");
01184                 break;
01185         case IOC_AUTOEXP_GAMMA_TABLE:
01186 //printk("set wrote gamma table\n");
01187                 c = (struct autoexp_context_t *)kmalloc(sizeof(struct autoexp_context_t), GFP_KERNEL);
01188                 if(c == NULL) {
01189                         printk("fail kmalloc context\r\n");
01190                         return -EFAULT;
01191                 }
01192                 c->write = _WRITE_GAMMA;
01193                 c->count = 0;
01194                 c->c = 0;
01195                 c->buf_fill = 0;
01196                 c->buf = (unsigned char *)ccam_dma;
01197                 filp->private_data = (void *)c;
01198                 break;
01199         default:
01200                 return -EFAULT;
01201         }
01202         return 0;
01203 }
01204 
01205 static void autoexp__vma_close(struct vm_area_struct *vma);
01206 static struct vm_operations_struct autoexp__vm_ops = {
01207         .close = autoexp__vma_close,
01208 };
01209 
01210 int autoexp__mmap(struct file *filp, struct vm_area_struct *vma) {
01211 
01212         vma->vm_ops = &autoexp__vm_ops;
01213         if(vma->vm_start == 0x00) {
01214 //printk("m1 ");
01215 //              return remap_page_range(   vma->vm_start, virt_to_phys(hb_0),              vma->vm_end - vma->vm_start, vma->vm_page_prot);
01216       return remap_pfn_range(vma,vma->vm_start, virt_to_phys(hb_0) >> PAGE_SHIFT,vma->vm_end - vma->vm_start, vma->vm_page_prot);
01217         }
01218         if(vma->vm_start == 0x10000000) {
01219 //printk("m2 ");
01220 //              return remap_page_range   (vma->vm_start, virt_to_phys(gamma_table),              vma->vm_end - vma->vm_start, vma->vm_page_prot);
01221       return remap_pfn_range(vma,vma->vm_start, virt_to_phys(gamma_table) >> PAGE_SHIFT,vma->vm_end - vma->vm_start, vma->vm_page_prot);
01222         }
01223         return -EFAULT;
01224 }
01225 
01226 void autoexp__vma_close(struct vm_area_struct *vma) {
01227 //printk("Mx ");
01228 }
01229 
01230 /*******************************************************************************
01231  *
01232  *
01233  */
01234 
01235 static unsigned long _gamma = 0xFFFFFFFF;
01236 static unsigned long _black = 0x00;
01237 
01238 static unsigned short _scale_red = 0x0100;
01239 static unsigned short _scale_green = 0x0100;
01240 static unsigned short _scale_blue = 0x0100;
01241 static unsigned short _scale_green1 = 0x0100; 
01242 
01243 #define FPGA333_TABLE_ADDR_GAMMA        0x0400
01244 
01245 // make a interpolation of the value between of the two table values;
01246 // index is a X coordinate of the point in 8.8 fixed point format
01247 unsigned long gamma_v(unsigned long index, unsigned short *table) {
01248         unsigned long v1, v2;
01249         unsigned long i;
01250         unsigned long step;
01251         unsigned long delta;
01252 
01253         if(index >= 0xFF00)
01254                 return 0xFFFF;
01255         i = index >> 8;
01256         v1 = table[i];
01257         v2 = table[i + 1];
01258         step = index & 0xFF;
01259         delta = v2 - v1;
01260         delta = (step * delta) >> 8;
01261         v1 += delta;
01262         if(v1 > 0xFFFF)
01263                 v1 = 0xFFFF;
01264         return v1;
01265 }
01266 
01267 unsigned short _gamma_table_or[GAMMA_TABLE_SIZE];
01268 unsigned short _gamma_table[256 * 6];
01269 unsigned long gamma_table_to_fpga[256 * 4];
01270 
01271 void set_gamma(unsigned long __gamma, unsigned long black, unsigned long scale_red, unsigned long scale_green, unsigned long scale_blue, unsigned long scale_green1) {
01272         u16 *g;
01273         u32 v;
01274         int i;
01275         int j;
01276         int k;
01277         int l;
01278         long x1, y1, x2, y2, a, b;
01279         long value;
01280         unsigned long scale = 0x100;
01281         unsigned short *_gt;
01282 /*
01283         unsigned short _gamma_table[256 * 6];
01284         unsigned long gamma_table_to_fpga[256 * 4];
01285 */
01286 
01287 //      unsigned short *_gamma_table;
01288 //      unsigned long *gamma_table_to_fpga;
01289         
01290         struct timeval tv;
01291         int base, diff, d;
01292 
01293 MD1(printk("!!! ----->>>>>>  set gamma: 0x%08X  <<<<<<<<---------- !!!!!!!!!!\n", __gamma));
01294 //printk("\n\nscale_red == 0x%04X; scale_green == 0x%04X; scale_blue == 0x%04X\n", scale_red, scale_green, scale_blue);
01295 
01296         // TODO - use from 100 to 199 for the custom tables, from the start - fill it with a linear tables (i.e. gamma == 1.0)
01297         if(__gamma >= 200)
01298                 __gamma = 199;
01299         if(black > 32)
01300                 black = 32;
01301         if(black > 256)
01302                 black = 0;
01303         if(_gamma == __gamma && black == _black && scale_red == _scale_red && scale_green == _scale_green && scale_blue == _scale_blue  && scale_green1 == _scale_green1)
01304                 return;
01305 /*
01306         if(_gamma == __gamma && black == _black && scale_red == _scale_red && scale_green == _scale_green && scale_blue == _scale_blue  && scale_green1 == _scale_green1) {
01307                 printk("set gamma - skip\n");
01308                 return;
01309         } else {
01310                 printk("_gamma == %d, __gamma == %d\n", _gamma, __gamma);
01311                 printk("black == %d, _black == %d\n", black, _black);
01312                 printk("scale_red == %d, _scale_red == %d\n", scale_red, _scale_red);
01313                 printk("scale_green == %d, _scale_green == %d\n", scale_green, _scale_green);
01314                 printk("scale_blue == %d, _scale_blue == %d\n", scale_blue, _scale_blue);
01315                 printk("scale_green1 == %d, _scale_green1 == %d\n", scale_green1, _scale_green1);
01316                 printk("set gamma...\n");
01317         }
01318 */
01319 //      _gamma_table = (unsigned short *)kmalloc(GFP_ATOMIC, 256 * 6 * sizeof(unsigned short));
01320 //      gamma_table_to_fpga = (unsigned long *)kmalloc(GFP_ATOMIC, 256 * 4 * sizeof(unsigned long));
01322 //      unsigned short *_gamma_table = (unsigned short *)kmalloc(GFP_KERNEL, 256 * 6 * sizeof(unsigned short));
01323 //      unsigned long *gamma_table_to_fpga = (unsigned long *)kmalloc(GFP_KERNEL, 256 * 4 * sizeof(unsigned long));
01324 //      unsigned short *_gamma_table_or = (unsigned short *)kmalloc(GFP_KERNEL, GAMMA_TABLE_SIZE * sizeof(unsigned short));
01325 //printk("_gamma_table == 0x%08X\n", _gamma_table);
01326 //printk("gamma_table_to_fpga == 0x%08X\n", gamma_table_to_fpga);
01327 //printk("_gamma_table_or == 0x%08X\n", _gamma_table_or);
01328 //*/
01329 
01330         _gamma = __gamma;
01331         _black = black;
01332         _scale_red = scale_red;
01333         _scale_green = scale_green;
01334         _scale_blue = scale_blue;
01335         _scale_green1 = scale_green1;
01336         g = (u16 *)(gamma_ptr + (_gamma * _GAMMA_TABLE_SIZE));
01337         // recalculate and write gamma table
01338         l = 0;
01339         int skip_interpolation = 0;
01340         if(_black == 0 && scale_red == 0x100 && scale_green == 0x100 && scale_blue == 0x100 && scale_green1 == 0x100) {
01341 //printk("for the gamma - must to skip interpolation\n");
01342                 skip_interpolation = 1;
01343         }
01344         for(j = 0; j < 4; j++) {
01345                 if(skip_interpolation) {
01346 //printk("........gamma - ........skip interpolation\n");
01347                         for(i = 0; i < GAMMA_TABLE_SIZE; i++) {
01348                                 if(i > 0) {
01349                                         _gamma_table[j * 256 + i - 1] = g[i - 1] & 0xFFFF;
01350                                 }
01351                                 _gamma_table_or[i] = g[i] & 0xFFFF;
01352                         }
01353                 } else {
01354                         switch(j) {
01355                                 case 0: scale = scale_red;              break;
01356                                 case 1: scale = scale_green;    break;
01357                                 case 2: scale = scale_green1;   break;
01358                                 case 3: scale = scale_blue;             break;
01359                         }
01360                         // Y = A * X + B
01361                         // calculate A & -B factors in fixed point 8.8 format
01362                         x1 = (_black << 8);
01363                         y1 = 0;
01364                         x2 = 0xFFFFFF / scale;
01365                         y2 = 0xFFFF;
01366                         a = ((y2 - y1) << 8) / (x2 - x1);
01367                         b = ((a * x2) >> 8) - y2;
01368                         for(i = 0; i < GAMMA_TABLE_SIZE; i++) {
01369                                 if(i <= _black) {
01370                                         value = 0x00;
01371                                 } else {
01372                                         v = (a * ((i << 8) + i)) >> 8;
01373                                         value = gamma_v(v - b, g);
01374                                         if(value > 0xFFFF)
01375                                                 value = 0xFFFF;
01376                                 }
01377                                 if(i + 1 == GAMMA_TABLE_SIZE)
01378                                         value = 0xFFFF;
01379                                 if(i > 0) {
01380 //                                      _gamma_table[j * 256 + i - 1] = g[i] & 0xFFFF;
01381                                         _gamma_table[j * 256 + i - 1] = value & 0xFFFF;
01382                                 }
01383                                 _gamma_table_or[i] = (value & 0xFFFF) >> 6;
01384                         }
01385                 }
01386                 // convert gamma table to FPGA format
01387                 for(i = 0; i < 256; i++) {
01388                         base = _gamma_table_or[i];
01389                         diff = _gamma_table_or[i + 1];
01390                         diff -= base;
01391                         if((diff > 63) || (diff < -64)) {
01392                                 diff = (diff + 8) >> 4;
01393                                 d = (base & 0x3ff) | ((diff & 0x7f) << 10) | (1 << 17);
01394                         } else {
01395                                 d = (base & 0x3ff) | ((diff & 0x7f) << 10);
01396                         }
01397                         gamma_table_to_fpga[l] = d;  // 18-bit data, will autoincrement address
01398                         l++;
01399                 }
01400         }
01401 //      fpga_table_write(FPGA333_TABLE_ADDR_GAMMA, gamma_table_to_fpga, 256 * 4);
01403         // write gamma table to FPGA
01404         fpga_table_write(FPGA333_TABLE_ADDR_GAMMA, gamma_table_to_fpga, 256 * 4);
01405 /*
01406         port_csp0_addr[0x0E] = FPGA333_TABLE_ADDR_GAMMA;
01407         for(i = 0; i < 256 * 4; i++) {
01408                         port_csp0_addr[0x0F] = gamma_table_to_fpga[i];
01409         }
01410         // to flush the last write data
01411         port_csp0_addr[0x0E] = FPGA333_TABLE_ADDR_GAMMA;
01412 */
01413 //*/
01414 
01415         // calculate reversed gamma
01416 //printk("g2 ");
01417         // clear gamma table
01418         _gt = _gamma_table + 256 * 4;
01419         memset((void *)_gt, 0, 256 * 2);
01420         if(_scale_red < _scale_green && _scale_red < _scale_blue && _scale_red < _scale_green1)
01421                 k = 0;
01422         else {
01423                 if(_scale_green < _scale_blue  && _scale_green < _scale_green1) { 
01424                         k = 256;
01425                 } else {        
01426                         if(_scale_green1 < _scale_blue) {
01427                                 k = 512;
01428                         } else {        
01429                                 k = 768;
01430                         }
01431                 }
01432         }
01433 //printk("g3 ");
01434         // simple copy
01435         for(i = 0; i < 256; i++)
01436                 _gt[_gamma_table[i + k] >> 8] = i << 8;
01437         // make interpolation
01438         for(i = 1; i < 256; i++) {
01439                 if(_gt[i] == 0) {
01440                         for(j = i; j < 256; j++) {
01441                                 if(_gt[j] != 0)
01442                                         break;
01443                         }
01444                         a = 0x100 / (j - i + 1);
01445                         for(; i < j; i++)
01446                                 _gt[i] = _gt[i - 1] + a;
01447                 }
01448         }
01449 //printk("g4 ");
01450         // make copy of original gamma
01451         _gt = _gamma_table + 256 * 5;
01452         memcpy((void *)_gt, (void *)g, 256 * 2);
01453         // set new gamma table...
01454         do_gettimeofday(&tv);
01455 //printk("gl ");
01456         if(down_interruptible(&gamma_lock) == 0) {
01457                 tv_gamma = tv;
01458                 memcpy((void *)gamma_table, (void *)_gamma_table, 256 * 6 * 2);
01459                 memcpy(((void *)hb_0) + OFFSET_GAMMA_C, &c_gamma, 4);
01460                 c_gamma++;
01461                 up(&gamma_lock);
01462         }
01463 
01464 MD1(printk("gamma... OK!\n"));
01466 //      kfree((void *)_gamma_table);
01467 //      kfree((void *)gamma_table_to_fpga);
01468 //      kfree((void *)_gamma_table_or);
01469 //*/
01470 }
01471 

Generated on Thu Aug 7 16:19:00 2008 for elphel by  doxygen 1.5.1