00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <linux/module.h>
00040 #include <linux/sched.h>
00041 #include <linux/slab.h>
00042 #include <linux/errno.h>
00043 #include <linux/kernel.h>
00044 #include <linux/fs.h>
00045 #include <linux/string.h>
00046 #include <linux/init.h>
00047 #include <linux/autoconf.h>
00048 #include <linux/vmalloc.h>
00049
00050 #include <asm/system.h>
00051
00052 #include <asm/byteorder.h>
00053 #include <asm/io.h>
00054
00055 #include <asm/irq.h>
00056
00057 #include <asm/delay.h>
00058 #include <asm/uaccess.h>
00059 #include <asm/elphel/c313a.h>
00060 #include <asm/elphel/exifa.h>
00061
00062 #include "fpgactrl.h"
00063
00064
00065 #include "cc3x3.h"
00066
00067
00068 #include "exif353.h"
00069
00070 #define D(x)
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 #define X3X3_EXIF_DRIVER_NAME "Elphel (R) model 353 Exif device driver"
00089
00090
00091
00092
00093 static struct exif_dir_table_t dir_table[MAX_EXIF_FIELDS];
00094 static int exif_fields = 0;
00095 static int exif_template_size = 0;
00096 static int exif_meta_size = 0;
00097 static int exif_wp = 1;
00098 static char exif_template[MAX_EXIF_SIZE];
00099
00100 static int exif_enabled = 0;
00101 static int exif_valid = 0;
00102
00103 static char * meta_buffer=NULL;
00104
00105
00106 static struct exif_time_t {
00107 char tomorrow_date[10];
00108 unsigned long tomorrow_sec;
00109 char today_date[10];
00110 unsigned long today_sec;
00111 } exif_time;
00112
00113 static struct exif_datetime_t {
00114 char datetime[20];
00115 char subsec[7];
00116 } now_datetime;
00117
00118
00119 static int exif_open (struct inode *inode, struct file *filp);
00120 static int exif_release(struct inode *inode, struct file *filp);
00121 static loff_t exif_lseek (struct file * file, loff_t offset, int orig);
00122 static ssize_t exif_write (struct file * file, const char * buf, size_t count, loff_t *off);
00123 static ssize_t exif_read (struct file * file, char * buf, size_t count, loff_t *off);
00124 static int __init exif_init(void);
00125
00126 static struct file_operations exif_fops = {
00127 owner: THIS_MODULE,
00128 open: exif_open,
00129 release: exif_release,
00130 read: exif_read,
00131 write: exif_write,
00132 llseek: exif_lseek
00133 };
00134 ssize_t minor_file_size(int minor) {
00135 switch (minor) {
00136 case X3X3_EXIF_TEMPLATE: return exif_template_size;
00137 case X3X3_EXIF_EXIF: return exif_enabled? (exif_template_size * (MAX_EXIF_FRAMES+1)):0;
00138 case X3X3_EXIF_META: return exif_meta_size;
00139 case X3X3_EXIF_METADIR: return exif_fields * sizeof(struct exif_dir_table_t);
00140 case X3X3_EXIF_TIME: return sizeof(struct exif_time_t);
00141 default:return 0;
00142 }
00143 }
00144 ssize_t minor_max_size(int minor) {
00145 switch (minor) {
00146 case X3X3_EXIF_TEMPLATE: return MAX_EXIF_SIZE;
00147 case X3X3_EXIF_EXIF: return MAX_EXIF_SIZE * (MAX_EXIF_FRAMES+1);
00148 case X3X3_EXIF_META: return MAX_EXIF_SIZE;
00149 case X3X3_EXIF_METADIR: return MAX_EXIF_FIELDS * sizeof(struct exif_dir_table_t);
00150 case X3X3_EXIF_TIME: return sizeof(struct exif_time_t);
00151 default:return 0;
00152 }
00153 }
00154 void exif_invalidate(void) {
00155 exif_enabled = 0;
00156 exif_valid = 0;
00157 }
00158
00159
00160 int exif_rebuild(int frames) {
00161 int i,ml;
00162 exif_enabled = 0;
00163 exif_valid = 0;
00164 exif_wp = 1;
00165
00166 if (meta_buffer) {
00167 vfree (meta_buffer);
00168 meta_buffer=NULL;
00169 }
00170
00171 if (exif_fields==0) return 0;
00172 for (i=0; i < exif_fields; i++) {
00173 ml=dir_table[i].src+dir_table[i].len;
00174 if (ml > exif_meta_size) exif_meta_size= ml;
00175 }
00176 if (exif_meta_size>MAX_EXIF_SIZE) {
00177 printk ("%s:%d: Meta frame size (0x%x) is too big (>0x%x)\n",__FILE__,__LINE__, exif_meta_size, MAX_EXIF_SIZE);
00178 return -1;
00179 }
00180 meta_buffer= vmalloc(exif_meta_size * (MAX_EXIF_FRAMES+1));
00181 if (!meta_buffer) {
00182 printk ("%s:%d: Failed to allocate memory (%d bytes)\n",__FILE__,__LINE__, exif_meta_size * (MAX_EXIF_FRAMES+1));
00183 return -1;
00184 }
00185 memset(meta_buffer, 0, exif_meta_size * (MAX_EXIF_FRAMES+1));
00186 exif_valid = 1;
00187 return 0;
00188 }
00189
00190 int exif_enable(int en) {
00191 int rslt;
00192 if (en) {
00193 if (!exif_valid) {
00194 if (((rslt=exif_rebuild(MAX_EXIF_FRAMES))) <0) return rslt;
00195 }
00196 exif_enabled = 1;
00197 } else {
00198 exif_enabled = 0;
00199 }
00200 return 0;
00201 }
00202 int dir_find_tag (unsigned long tag) {
00203 int indx;
00204
00205 for (indx=0; indx < exif_fields; indx++) if (dir_table[indx].ltag==tag) return (int) dir_table[indx].src;
00206 return -1;
00207 }
00208
00209 inline void write_meta_raw_irq(char * data, int offset, int len) {
00210 if (exif_enabled) memcpy(&meta_buffer[ offset], data, len);
00211 }
00212
00213 inline int write_meta_irq(char * data, int * indx, unsigned long ltag, int len) {
00214 int i;
00215 if (!exif_enabled) return 0;
00216 if (indx && (dir_table[* indx].ltag==ltag)) i=*indx;
00217 else {
00218 for (i=0; i<exif_fields; i++) if (dir_table[i].ltag==ltag) break;
00219 if (i>=exif_fields) return -1;
00220 }
00221 if (len==0) len=dir_table[i].len;
00222 memcpy(&meta_buffer[dir_table[i].src], data, len);
00223 if (indx) * indx=i;
00224 return dir_table[i].src;
00225 }
00226
00227 inline void putlong_meta_raw_irq(unsigned long data, int offset) {
00228 unsigned long bedata=__cpu_to_be32(data);
00229 if (exif_enabled) {
00230 memcpy(&meta_buffer[ offset], &bedata, 4);
00231 }
00232 }
00233
00234 inline int putlong_meta_irq(unsigned long data, int * indx, unsigned long ltag) {
00235 int i;
00236 unsigned long bedata=__cpu_to_be32(data);
00237 if (!exif_enabled) return -10;
00238 if (indx && (dir_table[* indx].ltag==ltag)) i=*indx;
00239 else {
00240 for (i=0; i<exif_fields; i++) if (dir_table[i].ltag==ltag) break;
00241 if (i>=exif_fields) return -1;
00242 }
00243 memcpy(&meta_buffer[dir_table[i].src], &bedata, 4);
00244 if (indx) * indx=i;
00245 return dir_table[i].src;
00246 }
00247
00248
00249
00250 void write_meta_raw(char * data, int offset, int len) {
00251 unsigned long flags;
00252 if (exif_enabled) {
00253 local_irq_save(flags);
00254
00255 memcpy(&meta_buffer[ offset], data, len);
00256 local_irq_restore(flags);
00257 }
00258 }
00259 int write_meta(char * data, int * indx, unsigned long ltag, int len) {
00260 int i;
00261 unsigned long flags;
00262 if (!exif_enabled) return 0;
00263 if (indx && (dir_table[* indx].ltag==ltag)) i=*indx;
00264 else {
00265 for (i=0; i<exif_fields; i++) if (dir_table[i].ltag==ltag) break;
00266 if (i>=exif_fields) return -1;
00267 }
00268 if (len==0) len=dir_table[i].len;
00269 local_irq_save(flags);
00270
00271 memcpy(&meta_buffer[dir_table[i].src], data, len);
00272 local_irq_restore(flags);
00273 if (indx) * indx=i;
00274 return dir_table[i].src;
00275 }
00276
00277 void putlong_meta_raw(unsigned long data, int offset) {
00278 unsigned long flags;
00279 unsigned long bedata=__cpu_to_be32(data);
00280 if (exif_enabled) {
00281 local_irq_save(flags);
00282
00283 memcpy(&meta_buffer[ offset], &bedata, 4);
00284 local_irq_restore(flags);
00285 }
00286 }
00287
00288 int putlong_meta(unsigned long data, int * indx, unsigned long ltag) {
00289 int i;
00290 unsigned long flags;
00291 unsigned long bedata=__cpu_to_be32(data);
00292 if (!exif_enabled) return -10;
00293 if (indx && (dir_table[* indx].ltag==ltag)) i=*indx;
00294 else {
00295 for (i=0; i<exif_fields; i++) if (dir_table[i].ltag==ltag) break;
00296 if (i>=exif_fields) return -1;
00297 }
00298 local_irq_save(flags);
00299
00300 memcpy(&meta_buffer[dir_table[i].src], &bedata, 4);
00301 local_irq_restore(flags);
00302 if (indx) * indx=i;
00303 return dir_table[i].src;
00304 }
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 char * encode_time(unsigned long sec, unsigned long usec) {
00327 unsigned long s,d,m,y,y4,lp,h;
00328 if (((sec-exif_time.today_sec)>86400) || (sec < exif_time.today_sec)) {
00329 memcpy(&exif_time.today_date[0],&exif_time.tomorrow_date[0],sizeof(exif_time.today_date)+sizeof(exif_time.today_sec));
00330 if (((sec-exif_time.today_sec)>86400) || (sec < exif_time.today_sec)) {
00331 d=sec/86400;
00332 s=d*86400;
00333 y4=d/1461;
00334 d-=1461*y4;
00335 y=(d- ((d>=1095)?1:0))/365;
00336 d-=y*365-((y>2)?1:0);
00337 lp=(y==2);
00338 y+=4*y4+1970;
00339 if ((!lp) && (d>58)) d++;
00340
00341 D(printk("d=%ld, y=%ld, y4=%ld, lp=%ld\n",d, y, y4, lp));
00342 if (d>181) {
00343 if (d>273) {
00344 if (d>304) {
00345 if (d>334) {m=12;d-=334;}
00346 else {m=11;d-=304;}
00347 } else {m=10;d-=273;}
00348 } else {
00349 if (d>212) {
00350 if (d>243) {m= 9;d-=243;}
00351 else {m= 8;d-=212;}
00352 } else {m= 7;d-=181;}
00353 }
00354 } else {
00355 if (d>90) {
00356 if (d>120) {
00357 if (d>151) {m=6; d-=151;}
00358 else {m=5; d-=120;}
00359 } else {m=4; d-= 90;}
00360 } else {
00361 if (d>30) {
00362 if (d>59) {m=3; d-= 59;}
00363 else {m=2; d-= 30;}
00364 } else {m=1; d++; }
00365 }
00366 }
00367 D(printk("d=%ld, y=%ld, y4=%ld\n",d, y, y4));
00368 sprintf(exif_time.today_date,"%04ld:%02ld:%02ld",y,m,d);
00369 exif_time.today_sec=s;
00370 }
00371 memcpy (&now_datetime.datetime[0],exif_time.today_date,10);
00372 now_datetime.datetime[10]=' ';
00373 now_datetime.datetime[19]='\0';
00374 now_datetime.subsec[6]='\0';
00375 }
00376
00377 s=sec-exif_time.today_sec;
00378 h= s/3600;
00379 s-= 3600*h;
00380 m= s/60;
00381 s-= 60*m;
00382 sprintf(&now_datetime.datetime[11],"%02ld:%02ld:%02ld",h,m,s);
00383 sprintf(&now_datetime.subsec[0],"%06ld",usec);
00384 return &now_datetime.datetime[0];
00385 }
00386
00387 int store_meta(void) {
00388 if (!exif_enabled) return 0;
00389 int retval=exif_wp;
00390 memcpy(&meta_buffer[exif_wp*exif_meta_size],meta_buffer,exif_meta_size);
00391 exif_wp++;
00392 if (exif_wp > MAX_EXIF_FRAMES) exif_wp=1;
00393 return retval;
00394 }
00395
00397
00398 static int exif_open(struct inode *inode, struct file *filp) {
00399 int p = MINOR(inode->i_rdev);
00400 int * pd= (int *) &(filp->private_data);
00401 switch (p) {
00402 case X3X3_EXIF_EXIF:
00403 case X3X3_EXIF_META:
00404 case X3X3_EXIF_TEMPLATE:
00405 case X3X3_EXIF_METADIR:
00406 case X3X3_EXIF_TIME:
00407 break;
00408 default:return -EINVAL;
00409 }
00410
00411 D(printk("exif_open, minor=%d\n",p));
00412 inode->i_size=minor_file_size(p);
00413 pd[0]=p;
00414 return 0;
00415 }
00416
00418
00419 static int exif_release(struct inode *inode, struct file *filp){
00420 int p = MINOR(inode->i_rdev);
00421 int * pd= (int *) &(filp->private_data);
00422 switch (p) {
00423 case X3X3_EXIF_EXIF:
00424 break;
00425 case X3X3_EXIF_META:
00426 break;
00427 case X3X3_EXIF_TEMPLATE:
00428 break;
00429 case X3X3_EXIF_METADIR:
00430 break;
00431 case X3X3_EXIF_TIME:
00432 break;
00433 default:return -EINVAL;
00434 }
00435
00436 D(printk("exif_open, minor=%d\n",p));
00437 inode->i_size=minor_file_size(p);
00438 pd[0]=p;
00439 return 0;
00440 }
00441
00443
00444 static loff_t exif_lseek (struct file * file, loff_t offset, int orig) {
00445 int p=(int)file->private_data;
00446 int thissize=minor_file_size(p);
00447 int maxsize=minor_max_size(p);
00448 int fp;
00449 switch (orig) {
00450 case SEEK_SET:
00451 file->f_pos = offset;
00452 break;
00453 case SEEK_CUR:
00454 file->f_pos += offset;
00455 break;
00456 case SEEK_END:
00458 if (offset<=0) {
00459 file->f_pos = thissize + offset;
00460 } else {
00461
00462 switch (p) {
00463 case X3X3_EXIF_TEMPLATE:
00464 switch (offset) {
00465 case EXIF_LSEEK_DISABLE:
00466 exif_enable(0);
00467 break;
00468 case EXIF_LSEEK_ENABLE:
00469 if (exif_enable(1)<0) return -EOVERFLOW;
00470 break;
00471 case EXIF_LSEEK_INVALIDATE:
00472 exif_invalidate();
00473 break;
00474 case EXIF_LSEEK_REBUILD:
00475 if (exif_rebuild(MAX_EXIF_FRAMES)<0) return -EOVERFLOW;
00476 break;
00477 default:return -EINVAL;
00478 }
00479 break;
00480 case X3X3_EXIF_EXIF:
00481 if (offset > MAX_EXIF_FRAMES) return -EOVERFLOW;
00482
00483 file->f_pos=exif_template_size * offset;
00484
00485 break;
00486 case X3X3_EXIF_META:
00487 fp= dir_find_tag (offset);
00488 if (fp < 0) return -EOVERFLOW;
00489 file->f_pos=fp;
00490 break;
00491 case X3X3_EXIF_METADIR:
00492 file->f_pos=offset*sizeof(struct exif_dir_table_t);
00493 break;
00494 case X3X3_EXIF_TIME:
00495 switch (offset) {
00496 case EXIF_LSEEK_TOMORROW_DATE:
00497 file->f_pos=exif_time.tomorrow_date - ((char *) &exif_time);
00498 break;
00499 case EXIF_LSEEK_TOMORROW_SEC:
00500 file->f_pos=((char *) &exif_time.tomorrow_sec) - ((char *) &exif_time);
00501 break;
00502 case EXIF_LSEEK_TODAY_DATE:
00503 file->f_pos=exif_time.today_date - ((char *) &exif_time);
00504 break;
00505 case EXIF_LSEEK_TODAY_SEC:
00506 file->f_pos=((char *) &exif_time.today_sec) - ((char *) &exif_time);
00507 break;
00508 default:return -EINVAL;
00509 }
00510 break;
00511 default:return -EINVAL;
00512 }
00513 }
00514 break;
00515 default:
00516 return -EINVAL;
00517 }
00518
00519 if (file->f_pos < 0) {
00520 file->f_pos = 0;
00521 return (-EOVERFLOW);
00522 }
00523
00524 if (file->f_pos > maxsize) {
00525 file->f_pos = maxsize;
00526 return (-EOVERFLOW);
00527 }
00528 return (file->f_pos);
00529 }
00530
00532
00533 static ssize_t exif_write (struct file * file, const char * buf, size_t count, loff_t *off) {
00534 int p=(int)file->private_data;
00535
00536 int maxsize=minor_max_size(p);
00537 char * cp;
00538 char tmp[MAX_EXIF_SIZE];
00539 unsigned long flags;
00540 int disabled_err=0;
00541 if ((*off+count)>maxsize) {
00542 printk ("%s:%d: Data (0x%x) does not fit into 0x%x bytes\n",__FILE__,__LINE__, (int) (*off+count), maxsize);
00543 return -EOVERFLOW;
00544 }
00545 switch (p) {
00546 case X3X3_EXIF_TEMPLATE:
00547 exif_invalidate();
00548 if (copy_from_user(&exif_template[*off], buf, count)) return -EFAULT;
00549 exif_template_size=*off+count;
00550 break;
00551 case X3X3_EXIF_METADIR:
00552 exif_invalidate();
00553 cp= (char *) &dir_table;
00554 if (copy_from_user(&cp[*off], buf, count)) return -EFAULT;
00555 exif_fields=(*off+count)/sizeof(struct exif_dir_table_t);
00556 break;
00557 case X3X3_EXIF_TIME:
00558 cp= (char *) &exif_time;
00559 if (copy_from_user(&cp[*off], buf, count)) return -EFAULT;
00560 break;
00561 case X3X3_EXIF_META:
00562 if (copy_from_user(tmp, buf, count)) return -EFAULT;
00563 local_irq_save(flags);
00564
00565 if (exif_enabled) memcpy(&meta_buffer[*off], tmp, count);
00566 else disabled_err=1;
00567 local_irq_restore(flags);
00568 if (disabled_err) {
00569 D(printk("tried to write meta while disabled\n"));
00570 count=0;
00571 }
00572 break;
00573 case X3X3_EXIF_EXIF:
00574 return -EINVAL;
00575 break;
00576 default:return -EINVAL;
00577 }
00578 *off+=count;
00579 D(printk("count= 0x%x, pos= 0x%x\n", (int) count, (int)*off));
00580 return count;
00581 }
00582
00584
00585 static ssize_t exif_read (struct file * file, char * buf, size_t count, loff_t *off) {
00586 int p=(int)file->private_data;
00587 int thissize=minor_file_size(p);
00588
00589 char * cp, * metap;
00590 int start_p, page_p,i;
00591
00592 char tmp[MAX_EXIF_SIZE];
00593
00594
00595
00596
00597
00598
00599
00600 if (*off > thissize) {
00601 return 0;
00602 }
00603 if ((*off + count) > thissize) {
00604 count=thissize-*off;
00605 }
00606
00607 switch (p) {
00608 case X3X3_EXIF_TEMPLATE:
00609 if (copy_to_user(buf, &exif_template[*off], count)) return -EFAULT;
00610 break;
00611 case X3X3_EXIF_METADIR:
00612 cp= (char *) &dir_table;
00613 if (copy_to_user(buf, &cp[*off], count)) return -EFAULT;
00614 break;
00615 case X3X3_EXIF_TIME:
00616 cp= (char *) &exif_time;
00617 if (copy_to_user(buf, &cp[*off], count)) return -EFAULT;
00618 break;
00619 case X3X3_EXIF_META:
00620 if (!exif_enabled) return 0;
00621 if (copy_to_user(buf, &meta_buffer[*off], count)) return -EFAULT;
00622 break;
00623 case X3X3_EXIF_EXIF:
00624
00625 if (!exif_enabled) return 0;
00626 i=((int) *off) / exif_template_size;
00627 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));
00628
00629 start_p=i*exif_template_size;
00630 page_p= *off - start_p;
00631 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));
00632
00633
00634 metap= &meta_buffer[i*exif_meta_size];
00635 if ((page_p+count) > exif_template_size) count=exif_template_size-page_p;
00636 memcpy(tmp,exif_template, exif_template_size);
00637 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));
00638 for (i=0;i<exif_fields;i++){
00639 memcpy(&tmp[dir_table[i].dst],&metap[dir_table[i].src], dir_table[i].len);
00640 }
00641 if (copy_to_user(buf, &tmp[page_p], count)) return -EFAULT;
00642 break;
00643 default:return -EINVAL;
00644 }
00645 *off+=count;
00646 D(printk("count= 0x%x, pos= 0x%x\n", (int) count, (int)*off));
00647 return count;
00648 }
00649
00650
00652
00653 static int __init exif_init(void) {
00654 int res;
00655 res = register_chrdev(X3X3_EXIF, "Exif", &exif_fops);
00656 if(res < 0) {
00657 printk(KERN_ERR "exif_init: couldn't get a major number %d.\n",X3X3_EXIF);
00658 return res;
00659 }
00660 printk(X3X3_EXIF_DRIVER_NAME);
00661 return 0;
00662 }
00663
00664 module_init(exif_init);
00665 MODULE_LICENSE("GPL");
00666 MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
00667 MODULE_DESCRIPTION(X3X3_EXIF_DRIVER_NAME);