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

Go to the documentation of this file.
00001 /*!********************************************************************************
00002 *! FILE NAME  : exif353.c
00003 *! DESCRIPTION: Drivers for Exif manipulation
00004 *! Copyright (C) 2008 Elphel, Inc.
00005 *! -----------------------------------------------------------------------------**
00006 *!
00007 *!  This program is free software: you can redistribute it and/or modify
00008 *!  it under the terms of the GNU General Public License as published by
00009 *!  the Free Software Foundation, either version 3 of the License, or
00010 *!  (at your option) any later version.
00011 *!
00012 *!  This program is distributed in the hope that it will be useful,
00013 *!  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 *!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 *!  GNU General Public License for more details.
00016 *!
00017 *!  You should have received a copy of the GNU General Public License
00018 *!  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00019 *! -----------------------------------------------------------------------------**
00020 *!  $Log: exif353.c,v $
00021 *!  Revision 1.4  2008/04/25 21:28:56  elphel
00022 *!  added more functions for access from the IRQ, changed them to inline
00023 *!
00024 *!  Revision 1.3  2008/04/11 23:16:51  elphel
00025 *!  removed unneeded local_irq_disable() after local_irq_save_flags()
00026 *!
00027 *!  Revision 1.2  2008/04/07 09:45:30  elphel
00028 *!  removed unused variable
00029 *!
00030 *!  Revision 1.1  2008/04/07 09:09:07  elphel
00031 *!  New driver to handle Exif
00032 *!
00033 *!
00034 */
00035 
00036 
00037 //copied freom cxi2c.c - TODO:remove unneeded
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 //#include <asm/svinto.h>
00052 #include <asm/byteorder.h> // endians
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"  // defines port_csp0_addr, port_csp4_addr 
00063 //
00064 //#include "x3x3.h"
00065 #include "cc3x3.h"
00066 
00067 
00068 #include "exif353.h"
00069 
00070 #define D(x)
00071 //#define D(x) printk("%s:%d:",__FILE__,__LINE__);x
00072 
00073 
00074 //Major
00075 //#define X3X3_EXIF 136
00076 //Minors
00077 //#define X3X3_EXIF_EXIF    0 // read encoded Exif data (SEEK_END,
00078 //#define X3X3_EXIF_META    1 // write metadata, concurently opened files. All writes atomic
00079 // control/setup devices
00080 //#define X3X3_EXIF_TEMPLATE 2 // write Exif template
00081 //#define X3X3_EXIF_METADIR  3 // write metadata to Exif header translation (dir_table[MAX_EXIF_FIELDS])
00082 // those 2 files will disable exif_enabled and exif_valid, truncate file size to file pointer on release.
00083 //#define X3X3_EXIF_TIME     4 // write today/tomorrow date (YYYY:MM:DD) and number of seconds at today/tomorrow
00084                              // midnight (00:00:00) in seconds from epoch (long, startting from LSB)
00085 
00086 
00087 
00088 #define  X3X3_EXIF_DRIVER_NAME "Elphel (R) model 353 Exif device driver"
00089 
00090 //#define MAX_EXIF_FIELDS  256 // number of Exif tags in the header
00091 //#define MAX_EXIF_SIZE   4096 // Exif data size 
00092 
00093 static struct exif_dir_table_t dir_table[MAX_EXIF_FIELDS];
00094 static int  exif_fields        = 0; // total number of the Exif fields in the header
00095 static int  exif_template_size = 0; // size of Exif template
00096 static int  exif_meta_size     = 0; // size of Exif meta data page
00097 static int  exif_wp            = 1; // frame write pointer in the meta_buffer
00098 static char exif_template[MAX_EXIF_SIZE];
00099 
00100 static int exif_enabled = 0; // enable storing of frame meta data, enable reading Exif data
00101 static int exif_valid  = 0; // Exif tables and buffer are valid.
00102 
00103 static char * meta_buffer=NULL; // dynamically allocated buffer to store frame meta data.
00104 // page 0 - tempoary storage, 1..MAX_EXIF_FRAMES - buffer
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) { //return current file size for different minors
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) { //return max file size for different minors
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 //reallocate meta buffer to store per-frame meta data (later output as Exif)
00160 int exif_rebuild(int frames) {
00161   int i,ml;
00162   exif_enabled = 0;
00163   exif_valid  = 0;
00164   exif_wp     = 1;
00165 // free buffer, if allocated
00166   if (meta_buffer) {
00167     vfree (meta_buffer);
00168     meta_buffer=NULL;
00169   }
00170 //  calculate page size
00171   if (exif_fields==0) return 0; // exif_valid==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) { //find location of the tag field in meta page 
00203   int indx;
00204 //  for (indx=0; indx < exif_fields; indx++) if (dir_table[indx].ltag==tag) return indx;
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) { //write data to meta, called from IRQ
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) { //write data to meta, called from IRQ(len==0 => use field length)
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; //ltag not found
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) { //write data to meta (4 bytes, big endian), called from IRQ
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) { //write data to meta (4 bytes, big endian), from IRQ
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; //ltag not found
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) { //write data to meta, called from outside IRQ (atomic)
00251   unsigned long flags;
00252   if (exif_enabled) {
00253     local_irq_save(flags);
00254     //local_irq_disable();
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) { //write data to meta, from outside IRQ (atomic) (len==0 => use field length)
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; //ltag not found
00267   }
00268   if (len==0) len=dir_table[i].len;
00269   local_irq_save(flags);
00270   //local_irq_disable();
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) { //write data to meta (4 bytes, big endian), called from outside IRQ (atomic)
00278   unsigned long flags;
00279   unsigned long bedata=__cpu_to_be32(data);
00280   if (exif_enabled) {
00281     local_irq_save(flags);
00282     //local_irq_disable();
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) { //write data to meta (4 bytes, big endian), from outside IRQ (atomic)
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; //ltag not found
00297   }
00298   local_irq_save(flags);
00299   //local_irq_disable();
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    exp_bigendian=__cpu_to_be32((int)fp->exposure);
00309 
00310 static struct exif_time_t {
00311   char          tomorrow_date[10]; //!"YYYY:MM:DD"
00312   unsigned long tomorrow_sec;      //!seconds from epoch tomorrow at 00:00
00313   char          today_date[10];    //!"YYYY:MM:DD"
00314   unsigned long today_sec;         //!seconds from epoch today at 00:00
00315 } exif_time;
00316 
00317 static struct exif_datetime_t {
00318   char          datetime[20];      //!"YYYY:MM:DD HH:MM:SS\0"
00319   char          subsec[7];         //!ASCII microseconds (0-padded), ."\0"
00320 } now_datetime;
00321 */
00322 // The next function is normally called from the interrupt service routine
00323 // Encode time (epoch sec, usec) into static buffer, return pointer to the buffer 
00324 // Uses struct exif_time that should be updater from the user space (once a day),
00325 // calculates date/time ignoring leap seconds if not updated in time
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)) {// today's time is not valid, try tomorrow:
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)) {// today's time is _still_ not valid, has to do it itself :-(
00331       d=sec/86400;
00332       s=d*86400;
00333       y4=d/1461; // number of 4-year periods
00334       d-=1461*y4; //days after 1970, 1974, ...
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 //      d+=(lp && (d>58))?1:0;
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;} // December
00346             else       {m=11;d-=304;} // November
00347           } else       {m=10;d-=273;} // October
00348         } else {
00349           if (d>212) {
00350             if (d>243) {m= 9;d-=243;} // September
00351             else       {m= 8;d-=212;} // August
00352           } else       {m= 7;d-=181;} // July
00353         }
00354       } else {
00355         if (d>90) {
00356           if (d>120) {
00357             if (d>151) {m=6; d-=151;} // June
00358             else       {m=5; d-=120;} // May
00359           } else       {m=4; d-= 90;} // April
00360         } else {
00361           if (d>30) {
00362             if (d>59)  {m=3; d-= 59;} // March
00363             else       {m=2; d-= 30;} // February
00364           } else       {m=1; d++;   } // January
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 // now we have valid exif_time.today_date, exif_time.today_sec;
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) { //called from IRQ service - put current metadata to meta_buffer, return page index
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; // just a minor number
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; // just a minor number
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: //enable/disable
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; //TODO: change code
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; //TODO: change code
00476                 break;
00477               default:return -EINVAL;
00478             }
00479             break;
00480           case X3X3_EXIF_EXIF: // select page in the buffer
00481             if (offset > MAX_EXIF_FRAMES) return -EOVERFLOW; //larger than buffer
00482 //            file->f_pos=exif_meta_size * offset;
00483             file->f_pos=exif_template_size * offset;
00484 
00485             break;
00486           case X3X3_EXIF_META: // iterate
00487             fp= dir_find_tag (offset);
00488             if (fp < 0) return -EOVERFLOW; // tag is not in the directory
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    /* truncate position */
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 //  int thissize=minor_file_size(p);
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: //write date/time first, then - midnight seconds
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        //local_irq_disable();
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; // no writing - read only
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 //  int maxsize=minor_max_size(p);
00589   char * cp, * metap;
00590   int start_p, page_p,i;
00591   
00592   char tmp[MAX_EXIF_SIZE]; 
00593 /*
00594   Does not work with PHP - always read 8192 bytes
00595   if ((*off+count)>maxsize) {
00596     printk ("%s:%d: Data (0x%x) does not fit into 0x%x bytes\n",__FILE__,__LINE__, (int) (*off+count), maxsize);
00597     return -EOVERFLOW;
00598   }
00599 */
00600   if (*off > thissize) {
00601     return 0; // nothing to read
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: // generates exif data by merging exif_template with the selected meta_buffer page
00624 //will truncate by the end of current page
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 //arch/cris/arch-v32/drivers/elphel/exif353.c:590:count= 0x2000, *off= 0x410, i=0x82, exif_template_size=0x208
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 //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
00633 
00634        metap= &meta_buffer[i*exif_meta_size]; // pointer to the start of the selected page in frame meta_buffer
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);

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