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