Commit 03c34e84 authored by Andrey Filippov's avatar Andrey Filippov

intermediate state, not working

parent 39680a19
......@@ -15,7 +15,7 @@ obj-$(CONFIG_ELPHEL393) += clock10359.o
#obj-$(CONFIG_ELPHEL393_EXTERNAL) += fpgajtag.o
obj-$(CONFIG_ELPHEL393) += framepars.o
obj-$(CONFIG_ELPHEL393) += sensor_common.o x393.o
obj-$(CONFIG_ELPHEL393) += quantization_tables.o
obj-$(CONFIG_ELPHEL393) += circbuf.o jpeghead.o
#obj-$(CONFIG_ELPHEL393) += sensor_common.o x393.o
#obj-$(CONFIG_ELPHEL393) += quantization_tables.o
#obj-$(CONFIG_ELPHEL393) += circbuf.o jpeghead.o
/*!********************************************************************************
*! FILE NAME : exif353.c
*! DESCRIPTION: Drivers for Exif manipulation
*! Copyright (C) 2008 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*! -----------------------------------------------------------------------------**
*! $Log: exif353.c,v $
*! Revision 1.2 2009/02/18 06:27:34 elphel
*! fixed system date calculation fro Exif (was 2 days ahead in the years after leap)
*!
*! Revision 1.1.1.1 2008/11/27 20:04:00 elphel
*!
*!
*! Revision 1.3 2008/09/20 00:29:49 elphel
*! moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h
*!
*! Revision 1.2 2008/09/12 00:23:59 elphel
*! removed cc353.c, cc353.h
*!
*! Revision 1.4 2008/04/25 21:28:56 elphel
*! added more functions for access from the IRQ, changed them to inline
*!
*! Revision 1.3 2008/04/11 23:16:51 elphel
*! removed unneeded local_irq_disable() after local_irq_save_flags()
*!
*! Revision 1.2 2008/04/07 09:45:30 elphel
*! removed unused variable
*!
*! Revision 1.1 2008/04/07 09:09:07 elphel
*! New driver to handle Exif
*!
*!
*/
//copied freom cxi2c.c - TODO:remove unneeded
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/init.h>
//#include <linux/autoconf.h>
#include <linux/vmalloc.h>
//#include <asm/system.h>
//#include <asm/svinto.h>
#include <asm/byteorder.h> // endians
//#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
#include <elphel/driver_numbers.h>
#include <elphel/c313a.h>
#include <elphel/exifa.h>
//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
//
//#include "x3x3.h"
//#include "cc3x3.h"
#include "exif393.h"
#define D(x)
//#define D(x) printk("%s:%d:",__FILE__,__LINE__);x
//Major
//#define X3X3_EXIF 136
//Minors
//#define X3X3_EXIF_EXIF 0 // read encoded Exif data (SEEK_END,
//#define X3X3_EXIF_META 1 // write metadata, concurently opened files. All writes atomic
// control/setup devices
//#define X3X3_EXIF_TEMPLATE 2 // write Exif template
//#define X3X3_EXIF_METADIR 3 // write metadata to Exif header translation (dir_table[MAX_EXIF_FIELDS])
// those 2 files will disable exif_enabled and exif_valid, truncate file size to file pointer on release.
//#define X3X3_EXIF_TIME 4 // write today/tomorrow date (YYYY:MM:DD) and number of seconds at today/tomorrow
// midnight (00:00:00) in seconds from epoch (long, startting from LSB)
#define X3X3_EXIF_DRIVER_NAME "Elphel (R) model 353 Exif device driver"
static DEFINE_SPINLOCK(lock);
//#define MAX_EXIF_FIELDS 256 // number of Exif tags in the header
//#define MAX_EXIF_SIZE 4096 // Exif data size
static struct exif_dir_table_t dir_table[MAX_EXIF_FIELDS];
static int exif_fields = 0; // total number of the Exif fields in the header
static int exif_template_size = 0; // size of Exif template
static char exif_template[MAX_EXIF_SIZE];
static int aexif_meta_size[SENSOR_PORTS] = {0,0,0,0}; // size of Exif meta data page (is it the same for all ports?) 393: set as individual
static int aexif_wp[SENSOR_PORTS] = {1,1,1,1}; // frame write pointer in the meta_buffer
static int aexif_enabled[SENSOR_PORTS] = {0,0,0,0}; // enable storing of frame meta data, enable reading Exif data
static int aexif_valid[SENSOR_PORTS] = {0,0,0,0}; // Exif tables and buffer are valid.
static char * ameta_buffer[SENSOR_PORTS]= {NULL,NULL,NULL,NULL}; // dynamically allocated buffer to store frame meta data.
//static char * meta_buffer=NULL; // dynamically allocated buffer to store frame meta data.
// page 0 - temporary storage, 1..MAX_EXIF_FRAMES - buffer
// Common for all sensor ports
struct exif_time_t {
char tomorrow_date[10]; //!"YYYY:MM:DD"
unsigned long tomorrow_sec; //!seconds from epoch tomorrow at 00:00
char today_date[10]; //!"YYYY:MM:DD"
unsigned long today_sec; //!seconds from epoch today at 00:00
} exif_time;
static struct exif_datetime_t {
char datetime[20]; //!"YYYY:MM:DD HH:MM:SS\0"
char subsec[7]; //!ASCII microseconds (0-padded), ."\0"
} now_datetime;
static int exif_open (struct inode *inode, struct file *filp);
static int exif_release(struct inode *inode, struct file *filp);
static loff_t exif_lseek (struct file * file, loff_t offset, int orig);
static ssize_t exif_write (struct file * file, const char * buf, size_t count, loff_t *off);
static ssize_t exif_read (struct file * file, char * buf, size_t count, loff_t *off);
static int __init exif_init(void);
static struct file_operations exif_fops = {
owner: THIS_MODULE,
open: exif_open,
release: exif_release,
read: exif_read,
write: exif_write,
llseek: exif_lseek
};
ssize_t minor_file_size(int minor) { //return current file size for different minors
int sensor_port;
switch (minor) {
case X3X3_EXIF_TEMPLATE:
return exif_template_size;
case X3X3_EXIF_EXIF_CHN_0:
case X3X3_EXIF_EXIF_CHN_1:
case X3X3_EXIF_EXIF_CHN_2:
case X3X3_EXIF_EXIF_CHN_3:
sensor_port = minor - X3X3_EXIF_EXIF_CHN_0;
return aexif_enabled[sensor_port]? (exif_template_size * (MAX_EXIF_FRAMES+1)):0;
case X3X3_EXIF_META_CHN_0:
case X3X3_EXIF_META_CHN_1:
case X3X3_EXIF_META_CHN_2:
case X3X3_EXIF_META_CHN_3:
sensor_port = minor - X3X3_EXIF_META_CHN_0;
return aexif_meta_size[sensor_port];
case X3X3_EXIF_METADIR:
return exif_fields * sizeof(struct exif_dir_table_t);
case X3X3_EXIF_TIME:
return sizeof(struct exif_time_t);
default:return 0;
}
}
ssize_t minor_max_size(int minor) { //return max file size for different minors
switch (minor) {
case X3X3_EXIF_TEMPLATE: return MAX_EXIF_SIZE;
case X3X3_EXIF_EXIF: return MAX_EXIF_SIZE * (MAX_EXIF_FRAMES+1);
case X3X3_EXIF_META: return MAX_EXIF_SIZE;
case X3X3_EXIF_METADIR: return MAX_EXIF_FIELDS * sizeof(struct exif_dir_table_t);
case X3X3_EXIF_TIME: return sizeof(struct exif_time_t);
default:return 0;
}
}
void exif_invalidate(void) { // 393: OK, only invalidates all ayt once
int sensor_port;
for (sensor_port =0; sensor_port < SENSOR_PORTS; sensor_port++){
aexif_enabled[sensor_port] = 0;
aexif_valid[sensor_port] = 0;
}
}
//reallocate meta buffer to store per-frame meta data (later output as Exif)
// 393: Make both individual and all at once
int exif_rebuild(int frames) {
int sensor_port,rslt;
for (sensor_port =0; sensor_port < SENSOR_PORTS; sensor_port++){
if ((rslt = exif_rebuild_chn(sensor_port, frames)) <0){
return rslt;
}
}
return 0;
}
int exif_rebuild_chn(int sensor_port, int frames) {
int i,ml;
char * meta_buffer = ameta_buffer[sensor_port];
aexif_enabled[sensor_port] = 0;
aexif_valid[sensor_port] = 0;
aexif_wp[sensor_port] = 1;
// free buffer, if allocated
if (meta_buffer) {
vfree (meta_buffer);
meta_buffer=NULL;
}
// calculate page size
if (exif_fields==0) return 0; // exif_valid==0;
for (i=0; i < exif_fields; i++) {
ml=dir_table[i].src+dir_table[i].len;
if (ml > aexif_meta_size[sensor_port]) aexif_meta_size[sensor_port] = ml;
}
if (aexif_meta_size[sensor_port] > MAX_EXIF_SIZE) {
printk ("%s:%d: Meta frame size (0x%x) is too big (>0x%x)\n",__FILE__,__LINE__, aexif_meta_size[sensor_port], MAX_EXIF_SIZE);
return -1;
}
meta_buffer= vmalloc(aexif_meta_size[sensor_port] * (MAX_EXIF_FRAMES+1));
if (!meta_buffer) {
printk ("%s:%d: Failed to allocate memory (%d bytes)\n",__FILE__,__LINE__, aexif_meta_size[sensor_port] * (MAX_EXIF_FRAMES+1));
return -1;
}
memset(meta_buffer, 0, aexif_meta_size[sensor_port] * (MAX_EXIF_FRAMES+1));
aexif_valid[sensor_port] = 1;
return 0;
}
int exif_enable(int en) {
int sensor_port,rslt;
for (sensor_port =0; sensor_port < SENSOR_PORTS; sensor_port++){
if ((rslt = exif_enable_chn(sensor_port, en)) <0){
return rslt;
}
}
return 0;
}
int exif_enable_chn(int sensor_port, int en) {
int rslt;
if (en) {
if (!aexif_valid[sensor_port]) {
if (((rslt=exif_rebuild_chn(sensor_port, MAX_EXIF_FRAMES))) <0) return rslt;
}
aexif_enabled[sensor_port] = 1;
} else {
aexif_enabled[sensor_port] = 0;
}
return 0;
}
int dir_find_tag (unsigned long tag) { //find location of the tag field in meta page
int indx;
for (indx=0; indx < exif_fields; indx++) if (dir_table[indx].ltag==tag) return (int) dir_table[indx].src;
return -1;
}
inline void write_meta_raw_irq(int sensor_port, char * data, int offset, int len) { //write data to meta, called from IRQ
if (aexif_enabled[sensor_port])
memcpy(&ameta_buffer[sensor_port][offset], data, len);
}
inline int write_meta_irq(int sensor_port, char * data, int * indx, unsigned long ltag, int len) { //write data to meta, called from IRQ(len==0 => use field length)
int i;
if (!aexif_enabled[sensor_port]) return 0;
if (indx && (dir_table[* indx].ltag==ltag)) i=*indx;
else {
for (i=0; i<exif_fields; i++) if (dir_table[i].ltag==ltag) break;
if (i>=exif_fields) return -1; //ltag not found
}
if (len==0) len=dir_table[i].len;
memcpy(&ameta_buffer[sensor_port][dir_table[i].src], data, len);
if (indx) * indx = i;
return dir_table[i].src;
}
inline void putlong_meta_raw_irq(int sensor_port, unsigned long data, int offset) { //write data to meta (4 bytes, big endian), called from IRQ
unsigned long bedata=__cpu_to_be32(data);
if (aexif_enabled[sensor_port]) {
memcpy(&ameta_buffer[sensor_port][ offset], &bedata, 4);
}
}
inline int putlong_meta_irq(int sensor_port, unsigned long data, int * indx, unsigned long ltag) { //write data to meta (4 bytes, big endian), from IRQ
int i;
unsigned long bedata=__cpu_to_be32(data);
if (!aexif_enabled[sensor_port]) return -10;
if (indx && (dir_table[* indx].ltag==ltag)) i=*indx;
else {
for (i=0; i<exif_fields; i++) if (dir_table[i].ltag==ltag) break;
if (i>=exif_fields) return -1; //ltag not found
}
memcpy(&ameta_buffer[sensor_port][dir_table[i].src], &bedata, 4);
if (indx) * indx=i;
return dir_table[i].src;
}
void write_meta_raw(int sensor_port, char * data, int offset, int len) { //write data to meta, called from outside IRQ (atomic)
unsigned long flags;
if (aexif_enabled[sensor_port]) {
local_irq_save(flags);
//local_irq_disable();
memcpy(&ameta_buffer[sensor_port][ offset], data, len);
local_irq_restore(flags);
}
}
int write_meta(int sensor_port, char * data, int * indx, unsigned long ltag, int len) { //write data to meta, from outside IRQ (atomic) (len==0 => use field length)
int i;
unsigned long flags;
if (!aexif_enabled[sensor_port]) return 0;
if (indx && (dir_table[* indx].ltag==ltag)) i=*indx;
else {
for (i=0; i<exif_fields; i++) if (dir_table[i].ltag==ltag) break;
if (i>=exif_fields) return -1; //ltag not found
}
if (len==0) len=dir_table[i].len;
local_irq_save(flags);
memcpy(&ameta_buffer[sensor_port][dir_table[i].src], data, len);
local_irq_restore(flags);
if (indx) * indx=i;
return dir_table[i].src;
}
void putlong_meta_raw(int sensor_port, unsigned long data, int offset) { //write data to meta (4 bytes, big endian), called from outside IRQ (atomic)
unsigned long flags;
unsigned long bedata=__cpu_to_be32(data);
if (aexif_enabled[sensor_port]) {
local_irq_save(flags);
//local_irq_disable();
memcpy(&ameta_buffer[sensor_port][ offset], &bedata, 4);
local_irq_restore(flags);
}
}
int putlong_meta(int sensor_port, unsigned long data, int * indx, unsigned long ltag) { //write data to meta (4 bytes, big endian), from outside IRQ (atomic)
int i;
unsigned long flags;
unsigned long bedata=__cpu_to_be32(data);
if (!aexif_enabled[sensor_port]) return -10;
if (indx && (dir_table[* indx].ltag==ltag)) i=*indx;
else {
for (i=0; i<exif_fields; i++) if (dir_table[i].ltag==ltag) break;
if (i>=exif_fields) return -1; //ltag not found
}
local_irq_save(flags);
memcpy(&ameta_buffer[sensor_port][dir_table[i].src], &bedata, 4);
local_irq_restore(flags);
if (indx) * indx=i;
return dir_table[i].src;
}
// The next function is normally called from the interrupt service routine
// Encode time (epoch sec, usec) into static buffer, return pointer to the buffer
// Uses struct exif_time that should be updated from the user space (once a day),
// calculates date/time ignoring leap seconds if not updated in time
/*
* 393: Continue to use same static buffers for exif_time
*/
char * encode_time(char buf[27], unsigned long sec, unsigned long usec) {
unsigned long s,d,m,y,y4,lp,h;
spin_lock(&lock);
if (((sec-exif_time.today_sec)>86400) || (sec < exif_time.today_sec)) {// today's time is not valid, try tomorrow:
memcpy(&exif_time.today_date[0],&exif_time.tomorrow_date[0],sizeof(exif_time.today_date)+sizeof(exif_time.today_sec));
if (((sec-exif_time.today_sec)>86400) || (sec < exif_time.today_sec)) {// today's time is _still_ not valid, has to do it itself :-(
d=sec/86400;
s=d*86400;
y4=d/1461; // number of 4-year periods
d-=1461*y4; //days after 1970, 1974, ...
y=(d- ((d>=1095)?1:0))/365;
d-=y*365+((y>2)?1:0);
lp=(y==2);
y+=4*y4+1970;
if ((!lp) && (d>58)) d++;
// d+=(lp && (d>58))?1:0;
D(printk("d=%ld, y=%ld, y4=%ld, lp=%ld\n",d, y, y4, lp));
if (d>181) {
if (d>273) {
if (d>304) {
if (d>334) {m=12;d-=334;} // December
else {m=11;d-=304;} // November
} else {m=10;d-=273;} // October
} else {
if (d>212) {
if (d>243) {m= 9;d-=243;} // September
else {m= 8;d-=212;} // August
} else {m= 7;d-=181;} // July
}
} else {
if (d>90) {
if (d>120) {
if (d>151) {m=6; d-=151;} // June
else {m=5; d-=120;} // May
} else {m=4; d-= 90;} // April
} else {
if (d>30) {
if (d>59) {m=3; d-= 59;} // March
else {m=2; d-= 30;} // February
} else {m=1; d++; } // January
}
}
D(printk("d=%ld, y=%ld, y4=%ld\n",d, y, y4));
sprintf(exif_time.today_date,"%04ld:%02ld:%02ld",y,m,d);
exif_time.today_sec=s;
}
memcpy (&now_datetime.datetime[0],exif_time.today_date,10);
now_datetime.datetime[10]=' ';
now_datetime.datetime[19]='\0';
now_datetime.subsec[6]='\0';
}
// now we have valid exif_time.today_date, exif_time.today_sec;
s=sec-exif_time.today_sec;
h= s/3600;
s-= 3600*h;
m= s/60;
s-= 60*m;
sprintf(&now_datetime.datetime[11],"%02ld:%02ld:%02ld",h,m,s);
sprintf(&now_datetime.subsec[0],"%06ld",usec);
memcpy(buf,&now_datetime.datetime[0],sizeof(now_datetime));
// return &now_datetime.datetime[0];
spin_unlock(&lock);
return buf;
}
int store_meta(int sensor_port) { //called from IRQ service - put current metadata to meta_buffer, return page index
if (!aexif_enabled[sensor_port]) return 0;
int retval=aexif_wp[sensor_port];
memcpy(&ameta_buffer[sensor_port][aexif_wp[sensor_port] * aexif_meta_size[sensor_port]], ameta_buffer[sensor_port],aexif_meta_size[sensor_port]);
aexif_wp[sensor_port]++;
if (aexif_wp[sensor_port] > MAX_EXIF_FRAMES) aexif_wp[sensor_port] = 1;
return retval;
}
//!++++++++++++++++++++++++++++++++++++ open() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
static int exif_open(struct inode *inode, struct file *filp) {
int p = MINOR(inode->i_rdev);
int * pd= (int *) &(filp->private_data);
switch (p) {
case X3X3_EXIF_EXIF_CHN_0:
case X3X3_EXIF_EXIF_CHN_1:
case X3X3_EXIF_EXIF_CHN_2:
case X3X3_EXIF_EXIF_CHN_3:
case X3X3_EXIF_META_CHN_0:
case X3X3_EXIF_META_CHN_1:
case X3X3_EXIF_META_CHN_2:
case X3X3_EXIF_META_CHN_3:
case X3X3_EXIF_TEMPLATE:
case X3X3_EXIF_METADIR:
case X3X3_EXIF_TIME:
break;
default:return -EINVAL;
}
D(printk("exif_open, minor=%d\n",p));
inode->i_size=minor_file_size(p);
pd[0]=p; // just a minor number
return 0;
}
//!++++++++++++++++++++++++++++++++++++ release() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
static int exif_release(struct inode *inode, struct file *filp){
int p = MINOR(inode->i_rdev);
int * pd= (int *) &(filp->private_data);
switch (p) {
case X3X3_EXIF_EXIF_CHN_0:
case X3X3_EXIF_EXIF_CHN_1:
case X3X3_EXIF_EXIF_CHN_2:
case X3X3_EXIF_EXIF_CHN_3:
break;
case X3X3_EXIF_META_CHN_0:
case X3X3_EXIF_META_CHN_1:
case X3X3_EXIF_META_CHN_2:
case X3X3_EXIF_META_CHN_3:
break;
case X3X3_EXIF_TEMPLATE:
break;
case X3X3_EXIF_METADIR:
break;
case X3X3_EXIF_TIME:
break;
default:return -EINVAL;
}
D(printk("exif_open, minor=%d\n",p));
inode->i_size=minor_file_size(p);
pd[0]=p; // just a minor number
return 0;
}
//!++++++++++++++++++++++++++++++++++++ lseek() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
static loff_t exif_lseek (struct file * file, loff_t offset, int orig) {
int p=(int)file->private_data;
int thissize=minor_file_size(p);
int maxsize=minor_max_size(p);
// int sensor_port;
int fp;
switch (orig) {
case SEEK_SET:
file->f_pos = offset;
break;
case SEEK_CUR:
file->f_pos += offset;
break;
case SEEK_END:
//!overload
if (offset<=0) {
file->f_pos = thissize + offset;
} else {
switch (p) {
case X3X3_EXIF_TEMPLATE: //enable/disable
switch (offset) {
case EXIF_LSEEK_DISABLE:
exif_enable(0);
break;
case EXIF_LSEEK_ENABLE:
if (exif_enable(1)<0) return -EOVERFLOW; //TODO: change code
break;
case EXIF_LSEEK_INVALIDATE:
exif_invalidate();
break;
case EXIF_LSEEK_REBUILD:
if (exif_rebuild(MAX_EXIF_FRAMES)<0) return -EOVERFLOW; //TODO: change code
break;
default:return -EINVAL;
}
break;
case X3X3_EXIF_EXIF_CHN_0:
case X3X3_EXIF_EXIF_CHN_1:
case X3X3_EXIF_EXIF_CHN_2:
case X3X3_EXIF_EXIF_CHN_3:
// sensor_port = p - X3X3_EXIF_EXIF_CHN_0;
if (offset > MAX_EXIF_FRAMES) return -EOVERFLOW; //larger than buffer
// file->f_pos=exif_meta_size * offset;
file->f_pos=exif_template_size * offset;
break;
case X3X3_EXIF_META: // iterate
fp= dir_find_tag (offset);
if (fp < 0) return -EOVERFLOW; // tag is not in the directory
file->f_pos=fp;
break;
case X3X3_EXIF_META_CHN_0:
case X3X3_EXIF_META_CHN_1:
case X3X3_EXIF_META_CHN_2:
case X3X3_EXIF_META_CHN_3:
file->f_pos=offset*sizeof(struct exif_dir_table_t);
break;
case X3X3_EXIF_TIME:
switch (offset) {
case EXIF_LSEEK_TOMORROW_DATE:
file->f_pos=exif_time.tomorrow_date - ((char *) &exif_time);
break;
case EXIF_LSEEK_TOMORROW_SEC:
file->f_pos=((char *) &exif_time.tomorrow_sec) - ((char *) &exif_time);
break;
case EXIF_LSEEK_TODAY_DATE:
file->f_pos=exif_time.today_date - ((char *) &exif_time);
break;
case EXIF_LSEEK_TODAY_SEC:
file->f_pos=((char *) &exif_time.today_sec) - ((char *) &exif_time);
break;
default:return -EINVAL;
}
break;
default:return -EINVAL;
}
}
break;
default:
return -EINVAL;
}
/* truncate position */
if (file->f_pos < 0) {
file->f_pos = 0;
return (-EOVERFLOW);
}
if (file->f_pos > maxsize) {
file->f_pos = maxsize;
return (-EOVERFLOW);
}
return (file->f_pos);
}
//!++++++++++++++++++++++++++++++++++++ write() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
static ssize_t exif_write (struct file * file, const char * buf, size_t count, loff_t *off) {
int p=(int)file->private_data;
int sensor_port;
// int thissize=minor_file_size(p);
int maxsize=minor_max_size(p);
char * cp;
char tmp[MAX_EXIF_SIZE]; //! Or is it possible to disable IRQ while copy_from_user()?
unsigned long flags;
int disabled_err=0;
if ((*off+count)>maxsize) {
printk ("%s:%d: Data (0x%x) does not fit into 0x%x bytes\n",__FILE__,__LINE__, (int) (*off+count), maxsize);
return -EOVERFLOW;
}
switch (p) {
case X3X3_EXIF_TEMPLATE:
exif_invalidate();
if (copy_from_user(&exif_template[*off], buf, count)) return -EFAULT;
exif_template_size=*off+count;
break;
case X3X3_EXIF_METADIR:
exif_invalidate();
cp= (char *) &dir_table;
if (copy_from_user(&cp[*off], buf, count)) return -EFAULT;
exif_fields=(*off+count)/sizeof(struct exif_dir_table_t);
break;
case X3X3_EXIF_TIME: //write date/time first, then - midnight seconds
cp= (char *) &exif_time;
if (copy_from_user(&cp[*off], buf, count)) return -EFAULT;
break;
case X3X3_EXIF_META_CHN_0:
case X3X3_EXIF_META_CHN_1:
case X3X3_EXIF_META_CHN_2:
case X3X3_EXIF_META_CHN_3:
sensor_port = p - X3X3_EXIF_META_CHN_0;
if (copy_from_user(tmp, buf, count)) return -EFAULT;
local_irq_save(flags);
//local_irq_disable();
if (aexif_enabled[sensor_port]) memcpy(&ameta_buffer[sensor_port][*off], tmp, count);
else disabled_err=1;
local_irq_restore(flags);
if (disabled_err) {
D(printk("tried to write meta channel %d while disabled\n",sensor_port));
count=0;
}
break;
case X3X3_EXIF_EXIF_CHN_0:
case X3X3_EXIF_EXIF_CHN_1:
case X3X3_EXIF_EXIF_CHN_2:
case X3X3_EXIF_EXIF_CHN_3:
return -EINVAL; // no writing - read only
break;
default:return -EINVAL;
}
*off+=count;
D(printk("count= 0x%x, pos= 0x%x\n", (int) count, (int)*off));
return count;
}
//!++++++++++++++++++++++++++++++++++++ read() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
static ssize_t exif_read (struct file * file, char * buf, size_t count, loff_t *off) {
int p=(int)file->private_data;
int thissize=minor_file_size(p);
char * cp, * metap;
int start_p, page_p,i;
int sensor_port;
char tmp[MAX_EXIF_SIZE]; //! Or is it possible to disable IRQ while copy_from_user()?
/*
Does not work with PHP - always read 8192 bytes
if ((*off+count)>maxsize) {
printk ("%s:%d: Data (0x%x) does not fit into 0x%x bytes\n",__FILE__,__LINE__, (int) (*off+count), maxsize);
return -EOVERFLOW;
}
*/
if (*off > thissize) {
return 0; // nothing to read
}
if ((*off + count) > thissize) {
count=thissize-*off;
}
switch (p) {
case X3X3_EXIF_TEMPLATE:
if (copy_to_user(buf, &exif_template[*off], count)) return -EFAULT;
break;
case X3X3_EXIF_METADIR:
cp= (char *) &dir_table;
if (copy_to_user(buf, &cp[*off], count)) return -EFAULT;
break;
case X3X3_EXIF_TIME:
cp= (char *) &exif_time;
if (copy_to_user(buf, &cp[*off], count)) return -EFAULT;
break;
case X3X3_EXIF_META_CHN_0:
case X3X3_EXIF_META_CHN_1:
case X3X3_EXIF_META_CHN_2:
case X3X3_EXIF_META_CHN_3:
sensor_port = p - X3X3_EXIF_META_CHN_0;
if (!aexif_enabled[sensor_port]) return 0;
if (copy_to_user(buf, &ameta_buffer[sensor_port][*off], count)) return -EFAULT;
break;
case X3X3_EXIF_EXIF_CHN_0:// generates exif data by merging exif_template with the selected meta_buffer page
case X3X3_EXIF_EXIF_CHN_1:
case X3X3_EXIF_EXIF_CHN_2:
case X3X3_EXIF_EXIF_CHN_3:
sensor_port = p - X3X3_EXIF_EXIF_CHN_0;
//will truncate by the end of current page
if (!aexif_enabled[sensor_port]) return 0;
i=((int) *off) / exif_template_size;
D(printk("count= 0x%x, *off= 0x%x, i=0x%x, exif_template_size=0x%x\n", (int) count, (int) *off, (int) i, (int) exif_template_size));
//arch/cris/arch-v32/drivers/elphel/exif353.c:590:count= 0x2000, *off= 0x410, i=0x82, exif_template_size=0x208
start_p=i*exif_template_size;
page_p= *off - start_p;
D(printk("count= 0x%x, pos= 0x%x, start_p=0x%x, page_p=0x%x, i=0x%x, exif_template_size=0x%x\n", (int) count, (int) *off, (int)start_p, (int)page_p,(int) i, (int) exif_template_size));
//arch/cris/arch-v32/drivers/elphel/exif353.c:591:count= 0x2000, pos= 0x410, start_p=0x10810, page_p=0xfffefc00, i=0x82, exif_template_size=0x208
metap= &ameta_buffer[sensor_port][i*aexif_meta_size[sensor_port]]; // pointer to the start of the selected page in frame meta_buffer
if ((page_p+count) > exif_template_size) count=exif_template_size-page_p;
memcpy(tmp,exif_template, exif_template_size);
D(printk("count= 0x%x, pos= 0x%x, start_p=0x%x, page_p=0x%x\n", (int) count, (int) *off, (int)start_p, (int)page_p));
for (i=0;i<exif_fields;i++){
memcpy(&tmp[dir_table[i].dst],&metap[dir_table[i].src], dir_table[i].len);
}
if (copy_to_user(buf, &tmp[page_p], count)) return -EFAULT;
break;
default:return -EINVAL;
}
*off+=count;
D(printk("count= 0x%x, pos= 0x%x\n", (int) count, (int)*off));
return count;
}
//!++++++++++++++++++++++++++++++++++++ _init() ++++++++++++++++++++++++++++++++++++++++++++++++++++++
static int __init exif_init(void) {
int res;
res = register_chrdev(X3X3_EXIF_MAJOR, "Exif", &exif_fops);
if(res < 0) {
printk(KERN_ERR "\nexif_init: couldn't get a major number %d.\n",X3X3_EXIF_MAJOR);
return res;
}
printk(X3X3_EXIF_DRIVER_NAME" - %d\n",X3X3_EXIF_MAJOR);
return 0;
}
module_init(exif_init);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(X3X3_EXIF_DRIVER_NAME);
/*
exif353.h
*/
#ifndef _EXIF_H
#define _EXIF_H
#if 0
struct exif_time_t {
char tomorrow_date[10]; //!"YYYY:MM:DD"
unsigned long tomorrow_sec; //!seconds from epoch tomorrow at 00:00
char today_date[10]; //!"YYYY:MM:DD"
unsigned long today_sec; //!seconds from epoch today at 00:00
} exif_time;
struct exif_datetime_t {
char datetime[20]; //!"YYYY:MM:DD HH:MM:SS\0"
char subsec[7]; //!ASCII microseconds (0-padded), ."\0"
} now_datetime;
#endif
void exif_invalidate(void);
int exif_rebuild_chn(int sensor_port, int frames);// reallocate meta buffer to store per-frame meta data (later output as Exif)
int exif_rebuild(int frames); // rebuild for all sensor ports
int exif_enable_chn(int sensor_port, int en); // enable/disable Exif processing (both W/R)
int exif_enable(int en); // For all sensor ports
int dir_find_tag (unsigned long tag); //!find location of the tag field in meta page using long tag (Exif tag and tag group)
inline void write_meta_raw_irq(int sensor_port, char * data, int offset, int len); //write data to meta, called from IRQ
inline int write_meta_irq(int sensor_port, char * data, int * indx, unsigned long ltag, int len); //write data to meta, called from IRQ(len==0 => use field length)
inline void putlong_meta_raw_irq(int sensor_port, unsigned long data, int offset); //write data to meta (4 bytes, big endian), called from IRQ
inline int putlong_meta_irq(int sensor_port, unsigned long data, int * indx, unsigned long ltag); //write data to meta (4 bytes, big endian), from IRQ
//void write_meta_raw_irq(char * data, int offset, int len); //write data to meta, called from IRQ
//int write_meta_irq(char * data, int * indx, unsigned long ltag, int len); //write data to meta, called from IRQ(len==0 => use field length). Returns index of the written data, -1 if not written
void write_meta_raw(int sensor_port, char * data, int offset, int len); //write data to meta, called from outside IRQ (atomic)
int write_meta(int sensor_port, char * data, int * indx, unsigned long ltag, int len); //write data to meta, from outside IRQ (atomic) (len==0 => use field length). Returns index of the written data, -1 if not written
void putlong_meta_raw(int sensor_port, unsigned long data, int offset); //write data to meta (4 bytes, big endian), called from outside IRQ (atomic)
int putlong_meta(int sensor_port, unsigned long data, int * indx, unsigned long ltag); //write data to meta (4 bytes, big endian), from outside IRQ (atomic). Returns index of the written data, -1 if not written
char * encode_time(unsigned long sec, unsigned long usec);
int store_meta(int sensor_port); //called from IRQ service - put current metadata to meta_buffer, return page index
#endif
......@@ -62,6 +62,8 @@
//#include "cci2c.h" // to use void i2c_reset_wait(void), reset shadow static 'i2c_hardware_on'
#include "x393_macro.h"
#include "x393.h"
//#undef _LINUX_WAIT_H
//#include <linux/wait.h>
/**
* \def MDF1(x) optional debug output
......@@ -142,7 +144,32 @@ unsigned long *aglobalPars[SENSOR_PORTS]; /// parameters that
unsigned long *amultiSensIndex[SENSOR_PORTS]; /// index for per-sensor alternatives
unsigned long *amultiSensRvrsIndex[SENSOR_PORTS]; /// reverse index (to parent) for the multiSensIndex
wait_queue_head_t aframepars_wait_queue[SENSOR_PORTS];/// used to wait for the frame to be acquired
wait_queue_head_t framepars_wait_queue; /// used to wait for the frame to be acquired
/* Remove after compilation OK */
struct sensorproc_t * sensorproc = NULL;
void camera_interrupts (int on) {}
#if 0
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
might_sleep(); \
if (!(condition)) \
__ret = __wait_event_interruptible(wq, condition); \
__ret; \
})
#define __wait_event_interruptible_timeout(wq, condition, timeout) \
___wait_event(wq, ___wait_cond_timeout(condition), \
TASK_INTERRUPTIBLE, 0, timeout, \
__ret = schedule_timeout(__ret))
#define __wait_event_interruptible(wq, condition) \
___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \
schedule())
#endif
//wait_queue_head_t framepars_wait_queue; /// used to wait for the frame to be acquired
/**
* @brief file private data
......@@ -253,7 +280,7 @@ void initFramePars(int sensor_port)
/// Same for 10359 registers - will not change anything if there is no 10359 - these registers will not be changed, and if will be it wil cause no action
for (i = 0; i < P_M10359_NUMREGS; i++) afuncs2call[sensor_port][P_M10359_REGS + i] = ONCHANGE_SENSORREGS; /// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
initMultiPars(); /// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
initMultiPars(sensor_port); /// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
frameParsInitialized = 1;
}
......@@ -335,7 +362,7 @@ inline unsigned long get_imageParamsPrev(int sensor_port, int n)
* @param d data to write to the selected parameter
*/
inline void set_imageParamsThis(int sensor_port, int sensor_port, int n, unsigned long d)
inline void set_imageParamsThis(int sensor_port, int n, unsigned long d)
{
aframepars[sensor_port][thisFrameNumber(sensor_port) & PARS_FRAMES_MASK].pars[n] = d;
}
......@@ -490,7 +517,6 @@ inline void processParsASAP(int sensor_port, struct sensorproc_t * sensorproc, i
unsigned long * p_nasap = &GLOBALPARS(sensor_port, G_CALLNASAP);
int i;
int rslt;
struct framepars_t *framepars = aframepars[sensor_port];
#if ELPHEL_DEBUG
unsigned long allfunctions = framepars[0].functions | framepars[1].functions | framepars[2].functions | framepars[3].functions |
framepars[4].functions | framepars[5].functions | framepars[6].functions | framepars[7].functions;
......@@ -727,7 +753,7 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
struct framepars_t *framepars = aframepars[sensor_port];
unsigned long *funcs2call =afuncs2call[sensor_port];
if (!frameParsInitialized) {
initSequencers(); /// Will call initFramePars(); and initialize functions
initSequencers(sensor_port); /// Will call initFramePars(); and initialize functions
}
int findex_this = thisFrameNumber(sensor_port) & PARS_FRAMES_MASK;
int findex_prev = (findex_this - 1) & PARS_FRAMES_MASK;
......@@ -810,10 +836,10 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
/// Try to process parameters immediately after written. If 0, only non-ASAP will be processed to prevent
/// effects of uncertainty of when was it called relative to frame sync
/// Changed to all (don't care about uncertainty - they will trigger only if it is too late or during sensor detection/initialization)
if (!(get_globalParam(G_TASKLET_CTL) & (1 << TASKLET_CTL_NOSAME))) {
if (!(get_globalParam(sensor_port, G_TASKLET_CTL) & (1 << TASKLET_CTL_NOSAME))) {
// processParsSeq (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet
MDF5(printk("\n"));
processPars(sensorproc, thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet
processPars(sensor_port, sensorproc, thisFrameNumber(sensor_port) & PARS_FRAMES_MASK, 0); ///maxahead=0, the rest will be processed after frame sync, from the tasklet
}
PROFILE_NOW(7);
D1I(local_irq_restore(flags));
......@@ -1088,6 +1114,7 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig)
unsigned long target_frame;
struct framepars_pd * privData = (struct framepars_pd*) file -> private_data;
int sensor_port = privData -> minor - CMOSCAM_MINOR_FRAMEPARS_CHN_0;
struct framepars_t *framepars = aframepars[sensor_port];
MDF1(printk(" offset=0x%x, orig=0x%x, sensor_port = %d\n", (int)offset, (int)orig, sensor_port));
switch (orig) {
case SEEK_SET:
......@@ -1105,15 +1132,14 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig)
else target_frame = getThisFrameNumber(sensor_port) + offset - LSEEK_FRAME_WAIT_REL;
/// Skip 0..255 frames
// wait_event_interruptible (framepars_wait_queue, getThisFrameNumber()>=target_frame);
wait_event_interruptible (framepars_wait_queue, 1);
wait_event_interruptible(aframepars_wait_queue[sensor_port], getThisFrameNumber(sensor_port) >= target_frame);
// if (getThisFrameNumber()<target_frame) wait_event_interruptible (framepars_wait_queue,getThisFrameNumber()>=target_frame);
return getThisFrameNumber(); /// Does not modify current frame pointer? lseek (,0,SEEK_CUR) anyway returns getThisFrameNumber()
return getThisFrameNumber(sensor_port); /// Does not modify current frame pointer? lseek (,0,SEEK_CUR) anyway returns getThisFrameNumber()
} else { //! Other lseek commands
switch (offset & ~0x1f) {
case LSEEK_DAEMON_FRAME: /// wait the daemon enabled and a new frame interrupt (sensor frame sync)
wait_event_interruptible(framepars_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1 << (offset & 0x1f)));
wait_event_interruptible(aframepars_wait_queue[sensor_port], get_imageParamsThis(sensor_port, P_DAEMON_EN) & (1 << (offset & 0x1f)));
break;
default:
switch (offset) {
......@@ -1127,16 +1153,16 @@ loff_t framepars_lseek(struct file * file, loff_t offset, int orig)
break;
case LSEEK_FRAMEPARS_INIT: /// reset hardware sequencers, init framepars structure
MDF2(printk("LSEEK_FRAMEPARS_INIT\n"));
initGlobalPars(); /// reset all global parameters but the first 32
initSequencers();
initGlobalPars(sensor_port); /// reset all global parameters but the first 32
initSequencers(sensor_port);
break;
case LSEEK_FRAME_RESET: /// reset absoulte frame number to avoid integer frame number overflow
case LSEEK_FRAME_RESET: /// reset absolute frame number to avoid integer frame number overflow
MDF2(printk("LSEEK_FRAME_RESET\n"));
resetFrameNumber();
resetFrameNumber(sensor_port);
break;
case LSEEK_SENSORPROC: /// process modified parameters in frame 0 (to start sensor detection)
MDF2(printk("LSEEK_SENSORPROC: framepars[0].functions=0x%08lx\n", framepars[0].functions));
processPars(sensorproc, 0, 8); ///frame0, all 8 frames (maxAhead==8)
processPars(sensor_port, sensorproc, 0, 8); ///frame0, all 8 frames (maxAhead==8)
break;
case LSEEK_DMA_INIT: /// initialize ETRAX DMA (normally done in sensor_common.c at driver init
MDF2(printk("LSEEK_DMA_INIT\n"));
......@@ -1187,6 +1213,8 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
struct frameparspair_t pars_static[256]; /// will be sufficient for most calls
struct frameparspair_t * pars = pars_static;
struct framepars_pd * privData = (struct framepars_pd*)file->private_data;
int sensor_port = privData -> minor - CMOSCAM_MINOR_FRAMEPARS_CHN_0;
// struct framepars_t *framepars = aframepars[sensor_port];
unsigned long frame = *off; /// ************* NOTE: Never use file->f_pos in write() and read() !!!
int latency = -1;
int first = 0;
......@@ -1213,7 +1241,7 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
frame = pars[first].val;
break;
case FRAMEPARS_SETFRAMEREL:
frame = pars[first].val + getThisFrameNumber();
frame = pars[first].val + getThisFrameNumber(sensor_port);
break;
case FRAMEPARS_SETLATENCY:
latency = (pars[first].val & 0x80000000) ? -1 : pars[first].val;
......@@ -1231,7 +1259,7 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
}
last = first + 1;
while ((last < count) && ((pars[last].num & 0xff00) != 0xff00)) last++; // skip to the end or next special instructions
result = setFrameParsAtomic(frame, latency, last - first, &pars[first]);
result = setFrameParsAtomic(sensor_port,frame, latency, last - first, &pars[first]);
MDF1(printk("setFrameParsAtomic(%ld, %d, %d)\n", frame, latency, last - first));
if (result < 0) {
if (count > sizeof(pars_static)) kfree(pars);
......@@ -1249,7 +1277,7 @@ ssize_t framepars_write(struct file * file, const char * buf, size_t count, loff
/**
* @brief Driver MMAP method (should be used read only)
* provides access to both 8-frame parameters (including future ones), frame - 0 - some static ones too and
* much longer retained pastparameters - subset of all parameters
* much longer retained past parameters - subset of all parameters
* @param file
* @param vma
* @return OK - 0, negative - errors
......@@ -1258,13 +1286,14 @@ int framepars_mmap(struct file *file, struct vm_area_struct *vma)
{
int result;
struct framepars_pd * privData = (struct framepars_pd*)file->private_data;
int sensor_port = privData -> minor - CMOSCAM_MINOR_FRAMEPARS_CHN_0;
MDF1(printk(": minor=0x%x\n", privData->minor));
switch (privData->minor) {
case CMOSCAM_MINOR_FRAMEPARS:
result = remap_pfn_range(vma,
vma->vm_start,
((unsigned long)virt_to_phys(frameparsall)) >> PAGE_SHIFT, // Should be page-aligned
((unsigned long)virt_to_phys(&aframeparsall[sensor_port])) >> PAGE_SHIFT, // Should be page-aligned
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
MDF1(printk("remap_pfn_range returned=%x\r\n", result));
......@@ -1284,18 +1313,22 @@ int framepars_init(struct platform_device *pdev)
int res;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
int sensor_port;
init_framepars_ptr();
initGlobalPars(); /// sets default debug if enabled - not anymore. Add here?
initMultiPars(); /// just clear - needs to be called again when sensor is recognized
for (sensor_port = 0; sensor_port < SENSOR_PORTS; sensor_port++) {
init_framepars_ptr(sensor_port);
initGlobalPars(sensor_port); /// sets default debug if enabled - not anymore. Add here?
initMultiPars(sensor_port); /// just clear - needs to be called again when sensor is recognized
}
frameParsInitialized = 0;
res = register_chrdev(FRAMEPARS_MAJOR, "framepars_operations", &framepars_fops);
if (res < 0) {
printk(KERN_ERR "\nframepars_init: couldn't get a major number %d.\n", FRAMEPARS_MAJOR);
return res;
}
init_waitqueue_head(&framepars_wait_queue);
for (sensor_port = 0; sensor_port < SENSOR_PORTS; sensor_port++) {
init_waitqueue_head(&aframepars_wait_queue[sensor_port]);
}
dev_info(dev, "registered MAJOR: %d\n", FRAMEPARS_MAJOR);
return 0;
......@@ -1308,23 +1341,23 @@ int framepars_remove(struct platform_device *pdev)
return 0;
}
//static const struct of_device_id elphel393_framepars_of_match[] = {
// { .compatible = "elphel,elphel393-framepars-1.00" },
// { /* end of list */ }
//};
//MODULE_DEVICE_TABLE(of, elphel393_framepars_of_match);
//
//static struct platform_driver elphel393_framepars = {
// .probe = framepars_init,
// .remove = framepars_remove,
// .driver = {
// .name = FRAMEPARS_DRIVER_NAME,
// .of_match_table = elphel393_framepars_of_match,
// },
//};
//
//module_platform_driver(elphel393_framepars);
//
//MODULE_LICENSE("GPL");
//MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
//MODULE_DESCRIPTION(X3X3_FRAMEPARS_DRIVER_NAME);
static const struct of_device_id elphel393_framepars_of_match[] = {
{ .compatible = "elphel,elphel393-framepars-1.00" },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_framepars_of_match);
static struct platform_driver elphel393_framepars = {
.probe = framepars_init,
.remove = framepars_remove,
.driver = {
.name = FRAMEPARS_DRIVER_NAME,
.of_match_table = elphel393_framepars_of_match,
},
};
module_platform_driver(elphel393_framepars);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(X3X3_FRAMEPARS_DRIVER_NAME);
......@@ -9,7 +9,7 @@ extern struct framepars_past_t *apastpars[SENSOR_PORTS];
extern unsigned long *aglobalPars[SENSOR_PORTS];
extern unsigned long *amultiSensIndex[SENSOR_PORTS];
extern unsigned long *amultiSensRvrsIndex[SENSOR_PORTS];
extern wait_queue_head_t framepars_wait_queue[SENSOR_PORTS];
extern wait_queue_head_t aframepars_wait_queue[SENSOR_PORTS];
///TODO: init framepars (zero parameters) before initscripts (not when detecting the sensors) - then initscript will be able to overwrite some
void init_framepars_ptr(int sensor_port);
......
......@@ -68,7 +68,7 @@
#include "sensor_common.h"
//#include "pgm_functions.h"
#include "circbuf.h"
//#include "exif353.h"
#include "exif393.h"
//#include "histograms.h"
//#include "gamma_tables.h"
#include "quantization_tables.h"
......@@ -115,47 +115,47 @@ struct image_acq_pd_t {
struct jpeg_ptr_t jpeg_ptr[IMAGE_CHN_NUM];
};
static struct image_acq_pd_t image_acq_priv;
static struct image_acq_pd_t aimage_acq_priv[SENSOR_PORTS];
static volatile int JPEG_wp;
static volatile int JPEG_rp;
static int fpga_counter_prev=0; /// Previous value of the FPGA transfer counter (to find out if it did change)
static struct meta_offsets_t { // works like a cache to time save on looking for tags in the directory (forced to recalcualte if does not match)
static volatile int aJPEG_wp[SENSOR_PORTS];
static volatile int aJPEG_rp;
static int afpga_counter_prev[SENSOR_PORTS]; /// Previous value of the FPGA transfer counter (to find out if it did change)
static struct meta_offsets_t { // works like a cache to time save on looking for tags in the directory (forced to recalcualte if does not match)
int Image_DateTime; // will have offset of the Exif_Image_DateTime data in meta page (Exif_Photo_SubSecTime should go immediately after in meta page)
int Photo_DateTimeOriginal;
int Photo_ExposureTime;
int Image_FrameNumber;
int Image_Orientation;
int Photo_MakerNote;
} meta_offsets;
} meta_offsets;
#ifdef TEST_DISABLE_CODE
int camSeqGetJPEG_wp(void) {return JPEG_wp;}
int camSeqGetJPEG_rp(void) {return JPEG_rp;}
void camSeqSetJPEG_rp(int p) {
JPEG_rp=p;
set_globalParam(G_CIRCBUFRP, p<< 2);
set_globalParam(G_FREECIRCBUF,
(((get_globalParam(G_CIRCBUFRP) <= get_globalParam(G_CIRCBUFWP))?
get_globalParam(G_CIRCBUFSIZE):0)+ get_globalParam(G_CIRCBUFRP))
- get_globalParam(G_CIRCBUFWP));
//#ifdef TEST_DISABLE_CODE
int camSeqGetJPEG_wp(int sensor_port) {return aJPEG_wp[sensor_port];}
int camSeqGetJPEG_rp(int sensor_port) {return aJPEG_rp[sensor_port];}
void camSeqSetJPEG_rp(int sensor_port, int p) {
aJPEG_rp[sensor_port]=p;
set_globalParam(sensor_port, G_CIRCBUFRP, p<< 2);
set_globalParam(sensor_port, G_FREECIRCBUF,
(((get_globalParam(sensor_port, G_CIRCBUFRP) <= get_globalParam(sensor_port, G_CIRCBUFWP))?
get_globalParam(sensor_port, G_CIRCBUFSIZE):0)+ get_globalParam(sensor_port, G_CIRCBUFRP))
- get_globalParam(sensor_port, G_CIRCBUFWP));
}
#endif /* TEST_DISABLE_CODE */
//#endif /* TEST_DISABLE_CODE */
int camseq_get_jpeg_wp(unsigned int chn)
int camseq_get_jpeg_wp(int sensor_port, unsigned int chn)
{
return (chn < IMAGE_CHN_NUM) ? image_acq_priv.jpeg_ptr[chn].jpeg_wp : 0;
return (chn < IMAGE_CHN_NUM) ? aimage_acq_priv.jpeg_ptr[chn].jpeg_wp : 0;
}
int camseq_get_jpeg_rp(unsigned int chn)
int camseq_get_jpeg_rp(int sensor_port, unsigned int chn)
{
return (chn < IMAGE_CHN_NUM) ? image_acq_priv.jpeg_ptr[chn].jpeg_rp : 0;
return (chn < IMAGE_CHN_NUM) ? aimage_acq_priv[sensor_port].jpeg_ptr[chn].jpeg_rp : 0;
}
void camseq_set_jpeg_rp(unsigned int chn, int ptr)
void camseq_set_jpeg_rp(int sensor_port, unsigned int chn, int ptr)
{
if (chn < IMAGE_CHN_NUM) {
image_acq_priv.jpeg_ptr[chn].jpeg_rp = ptr;
aimage_acq_priv[sensor_port].jpeg_ptr[chn].jpeg_rp = ptr;
}
}
......@@ -163,40 +163,43 @@ void camseq_set_jpeg_rp(unsigned int chn, int ptr)
End of compressor-related code - TODO: move to a separate file?
*/
static void dump_priv_data(int chn)
static void dump_priv_data(int sensor_port, int chn)
{
int i;
if (chn < IMAGE_CHN_NUM) {
printk(KERN_DEBUG "jpeg_wp (in bytes): 0x%x\n", image_acq_priv.jpeg_ptr[chn].jpeg_wp << 2);
printk(KERN_DEBUG "jpeg_rp (in bytes): 0x%x\n", image_acq_priv.jpeg_ptr[chn].jpeg_rp << 2);
printk(KERN_DEBUG "fpga_cntr_prev: 0x%x\n", image_acq_priv.jpeg_ptr[chn].fpga_cntr_prev);
printk(KERN_DEBUG "irq_num_comp: 0x%x\n", image_acq_priv.jpeg_ptr[chn].irq_num_comp);
printk(KERN_DEBUG "irq_num_sens: 0x%x\n", image_acq_priv.jpeg_ptr[chn].irq_num_sens);
printk(KERN_DEBUG "chn_num: 0x%x\n", image_acq_priv.jpeg_ptr[chn].chn_num);
printk(KERN_DEBUG "flags: 0x%x\n", image_acq_priv.jpeg_ptr[chn].flags);
printk(KERN_DEBUG "jpeg_wp (in bytes): 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].jpeg_wp << 2);
printk(KERN_DEBUG "jpeg_rp (in bytes): 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].jpeg_rp << 2);
printk(KERN_DEBUG "fpga_cntr_prev: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].fpga_cntr_prev);
printk(KERN_DEBUG "irq_num_comp: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].irq_num_comp);
printk(KERN_DEBUG "irq_num_sens: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].irq_num_sens);
printk(KERN_DEBUG "chn_num: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].chn_num);
printk(KERN_DEBUG "flags: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].flags);
} else {
for (i = 0; i < IMAGE_CHN_NUM; i++) {
printk(KERN_DEBUG "jpeg_wp: 0x%x\n", image_acq_priv.jpeg_ptr[i].jpeg_wp);
printk(KERN_DEBUG "jpeg_rp: 0x%x\n", image_acq_priv.jpeg_ptr[i].jpeg_rp);
printk(KERN_DEBUG "fpga_cntr_prev: 0x%x\n", image_acq_priv.jpeg_ptr[i].fpga_cntr_prev);
printk(KERN_DEBUG "irq_num_comp: 0x%x\n", image_acq_priv.jpeg_ptr[i].irq_num_comp);
printk(KERN_DEBUG "irq_num_sens: 0x%x\n", image_acq_priv.jpeg_ptr[i].irq_num_sens);
printk(KERN_DEBUG "chn_num: 0x%x\n", image_acq_priv.jpeg_ptr[i].chn_num);
printk(KERN_DEBUG "flags: 0x%x\n", image_acq_priv.jpeg_ptr[i].flags);
printk(KERN_DEBUG "jpeg_wp: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].jpeg_wp);
printk(KERN_DEBUG "jpeg_rp: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].jpeg_rp);
printk(KERN_DEBUG "fpga_cntr_prev: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].fpga_cntr_prev);
printk(KERN_DEBUG "irq_num_comp: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].irq_num_comp);
printk(KERN_DEBUG "irq_num_sens: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].irq_num_sens);
printk(KERN_DEBUG "chn_num: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].chn_num);
printk(KERN_DEBUG "flags: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].flags);
}
}
}
static const struct of_device_id elphel393_sensor_of_match[];
static struct sensorproc_t s_sensorproc; // sensor parameters and functions to call
struct sensorproc_t * sensorproc = NULL;
static struct sensorproc_t as_sensorproc[SENSOR_PORTS]; // sensor parameters and functions to call
struct sensorproc_t * asensorproc = NULL;
//EXPORT_SYMBOL_GPL(sensorproc);
//wait_queue_head_t image_acq_wait_queue; /// queue for the sensor frame interrupts
void tasklet_fpga_function(unsigned long arg);
void tasklet_fpga_function_chn0(unsigned long arg);
void tasklet_fpga_function_chn1(unsigned long arg);
void tasklet_fpga_function_chn2(unsigned long arg);
void tasklet_fpga_function_chn3(unsigned long arg);
/**
* @brief Copy #sensorproc structure, needed for multisensor board to be able
......@@ -204,10 +207,10 @@ void tasklet_fpga_function(unsigned long arg);
* @param[in] copy pointer to a copy structure
* @return pointer to a \b copy structure
*/
struct sensorproc_t * copy_sensorproc (struct sensorproc_t * copy)
struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * copy)
{
/** copy sensor functions */
memcpy(copy, sensorproc, sizeof(struct sensorproc_t));
memcpy(copy, asensorproc[sensor_port], sizeof(struct sensorproc_t));
return copy;
}
......@@ -225,9 +228,12 @@ struct sensorproc_t * copy_sensorproc (struct sensorproc_t * copy)
///#define CCAM_VSYNC_ON port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,0)
///#define CCAM_VSYNC_OFF port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,1)
///
int init_acq_sensor(void);
int init_acq_sensor(void); // Never used?
DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_chn0, tasklet_fpga_function_chn0, 0); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_chn1, tasklet_fpga_function_chn1, 1); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_chn2, tasklet_fpga_function_chn2, 2); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_chn3, tasklet_fpga_function_chn3, 3); /// 0 - no arguments for now
......@@ -242,11 +248,10 @@ DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); /// 0 - no arguments fo
*/
static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
{
int xferred; /// number of 32-byte chunks transferred since compressor was reset
int xferred; /// number of 32-byte chunks transferred since compressor was reset
x393_afimux_status_t stat = x393_afimux0_status(jptr->chn_num);
//int circbuf_size = get_globalParam(G_CIRCBUFSIZE) >> 2;
int circbuf_size = get_globalParam(G_CIRCBUFSIZE);
int circbuf_size = get_globalParam(jptr->chn_num, G_CIRCBUFSIZE);
xferred = stat.offset256 - jptr->fpga_cntr_prev;
if (xferred == 0)
return 0; /// no advance (compressor was off?)
......@@ -281,6 +286,8 @@ inline void updateIRQFocus(struct jpeg_ptr_t *jptr)
//set_globalParam (G_GFOCUS_VALUE, X313_HIGHFREQ);
//set_imageParamsThis (P_FOCUS_VALUE, X313_HIGHFREQ);
u32 high_freq = x393_cmprs_hifreq(jptr->chn_num);
set_globalParam (jptr->chn_num, G_GFOCUS_VALUE, high_freq);
set_imageParamsThis (jptr->chn_num, P_FOCUS_VALUE, high_freq);
}
inline static void set_default_interframe(struct interframe_params_t *params)
......@@ -326,7 +333,7 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
set_default_interframe(interframe);
set_globalParam(G_FRAME_SIZE, jpeg_len);
set_globalParam(jptr->chn_num, G_FRAME_SIZE, jpeg_len);
return interframe;
}
......@@ -335,9 +342,10 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
* @brief Fill exif data with the current frame data, save pointer to Exif page in the interframe area
* @param interframe pointer to interframe parameters structure
*/
inline void updateIRQ_Exif(struct interframe_params_t* interframe) {
int index_time = JPEG_wp-11; if (index_time<0) index_time+=get_globalParam (G_CIRCBUFSIZE)>>2;
#ifdef TES_DISABLE_CODE
inline void updateIRQ_Exif(int sensor_port, struct interframe_params_t* interframe) {
int index_time = aJPEG_wp-11[sensor_port]; if (index_time<0) index_time+=get_globalParam (sensor_port, G_CIRCBUFSIZE)>>2;
// struct exif_datetime_t
//#ifdef TES_DISABLE_CODE
/// calculates datetime([20] and subsec[7], returns pointer to char[27]
char * exif_meta_time_string=encode_time(ccam_dma_buf_ptr[index_time], ccam_dma_buf_ptr[index_time+1]);
/// may be split in datetime/subsec - now it will not notice missing subseq field in template
......@@ -397,7 +405,7 @@ inline void updateIRQ_Exif(struct interframe_params_t* interframe) {
}
interframe->meta_index=store_meta();
#endif /* TES_DISABLE_CODE */
//#endif /* TES_DISABLE_CODE */
}
......@@ -408,7 +416,8 @@ inline void updateIRQ_Exif(struct interframe_params_t* interframe) {
* @param dev_id
* @return
*/
/*static irqreturn_t elphel_FPGA_interrupt(int irq, void *dev_id) {
#ifdef X353
static irqreturn_t elphel_FPGA_interrupt(int irq, void *dev_id) {
unsigned long irq_state;
irq_state = X313_IRQSTATE; //!making dummy read - see c353.h
......@@ -436,8 +445,8 @@ inline void updateIRQ_Exif(struct interframe_params_t* interframe) {
EN_INTERRUPT(SMART);
return IRQ_HANDLED;
}*/
}
#endif
/**
* @brief Handle interrupts from sensor channels. This handler is installed without SA_INTERRUPT
* flag meaning that interrupts are enabled during processing. Such behavior is recommended in LDD3.
......@@ -448,10 +457,10 @@ inline void updateIRQ_Exif(struct interframe_params_t* interframe) {
*/
static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id)
{
struct jpeg_ptr_t *priv = dev_id;
struct jpeg_ptr_t *jptr = dev_id;
update_frame_pars();
wake_up_interruptible(&framepars_wait_queue);
wake_up_interruptible(&aframepars_wait_queue[jptr->chn_num]);
tasklet_schedule(&tasklet_fpga);
return IRQ_HANDLED;
......@@ -555,7 +564,7 @@ void tasklet_fpga_function(unsigned long arg) {
default: /// calculate always (safer)
hist_en=1;
}
#ifdef TEST_DISABLE_CODE
//#ifdef TEST_DISABLE_CODE
if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1]
set_histograms (prevFrameNumber, (1 << COLOR_Y_NUMBER), hash32p, framep); /// 0x2 Green1
......@@ -570,17 +579,17 @@ void tasklet_fpga_function(unsigned long arg) {
wake_up_interruptible(&hist_y_wait_queue); /// wait queue for the G1 histogram (used as Y)
}
#endif
#endif /* TEST_DISABLE_CODE */
//#endif /* TEST_DISABLE_CODE */
/// Process parameters
if ((tasklet_disable & (1 << TASKLET_CTL_PGM)) == 0) {
processPars (sensorproc, getThisFrameNumber(), get_globalParam(G_MAXAHEAD)); /// program parameters
PROFILE_NOW(4);
}
#ifdef TEST_DISABLE_CODE
//#ifdef TEST_DISABLE_CODE
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
/// Are C histograms needed?
#endif /* TEST_DISABLE_CODE */
//#endif /* TEST_DISABLE_CODE */
switch ((tasklet_disable >> TASKLET_CTL_HISTC_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate
hist_en=0;
......@@ -608,7 +617,7 @@ GLOBALPARS(0x1042)=((thisFrameNumber & 7) ==0);
GLOBALPARS(0x1043)=hist_en;
GLOBALPARS(0x1044)=thisFrameNumber;
*/
#ifdef TEST_DISABLE_CODE
//#ifdef TEST_DISABLE_CODE
if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1]
set_histograms (prevFrameNumber, 0xf, hash32p, framep); /// all 4 colors, including Y (it will be skipped)
......@@ -623,7 +632,7 @@ GLOBALPARS(0x1044)=thisFrameNumber;
wake_up_interruptible(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color)
}
#endif
#endif /* TEST_DISABLE_CODE */
//#endif /* TEST_DISABLE_CODE */
}
//#endif /* TEST_DISABLE_CODE */
......@@ -705,7 +714,7 @@ int image_acq_init(struct platform_device *pdev)
if (!match)
return -EINVAL;*/
sensorproc= &s_sensorproc;
asensorproc= &as_sensorproc[0];
//MDD1(printk("sensorproc=0x%x\n",(int) sensorproc));
dev_dbg(dev, "sensorproc address: 0x%x\n", (int)sensorproc);
......
......@@ -84,11 +84,21 @@
#define FPGA_SJTAG_MINOR_OFFSET 8 // Minors range start for the sensor port JTAG
#define FPGA_SJTAG_BOUNDARY_OFFSET 12 // Minors range start for the sensor port boundary
#define X3X3_EXIF_EXIF 0 // read encoded Exif data (SEEK_END,
#define X3X3_EXIF_META 1 // write metadata, concurently opened files. All writes atomic
//#define X3X3_EXIF_EXIF 0 // read encoded Exif data (SEEK_END,
//#define X3X3_EXIF_META 1 // write metadata, concurently opened files. All writes atomic
// control/setup devices
#define X3X3_EXIF_TEMPLATE 2 // write Exif template
#define X3X3_EXIF_METADIR 3 // write metadata to Exif header translation (dir_table[MAX_EXIF_FIELDS])
// those 2 files will disable exif_enable and exif_valid, truncate file size to file pointer on release.
#define X3X3_EXIF_TIME 4 // write today/tomorrow date (YYYY:MM:DD) and number of seconds at today/tomorrow
// midnight (00:00:00) in seconds from epoch (long, startting from LSB)
#define X3X3_EXIF_EXIF_CHN_0 0x10 // read encoded Exif data (SEEK_END,
#define X3X3_EXIF_EXIF_CHN_1 0x11 // read encoded Exif data (SEEK_END,
#define X3X3_EXIF_EXIF_CHN_2 0x12 // read encoded Exif data (SEEK_END,
#define X3X3_EXIF_EXIF_CHN_3 0x13 // read encoded Exif data (SEEK_END,
#define X3X3_EXIF_META_CHN_0 0x20 // write metadata, concurently opened files. All writes atomic
#define X3X3_EXIF_META_CHN_1 0x21 // write metadata, concurently opened files. All writes atomic
#define X3X3_EXIF_META_CHN_2 0x22 // write metadata, concurently opened files. All writes atomic
#define X3X3_EXIF_META_CHN_3 0x23 // write metadata, concurently opened files. All writes atomic
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment