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.1.1.1  2008/11/27 20:04:00  elphel
00022 *!
00023 *!
00024 *!  Revision 1.3  2008/09/20 00:29:49  elphel
00025 *!  moved driver major/minor numbers to a single file - include/asm-cris/elphel/driver_numbers.h
00026 *!
00027 *!  Revision 1.2  2008/09/12 00:23:59  elphel
00028 *!  removed cc353.c, cc353.h
00029 *!
00030 *!  Revision 1.4  2008/04/25 21:28:56  elphel
00031 *!  added more functions for access from the IRQ, changed them to inline
00032 *!
00033 *!  Revision 1.3  2008/04/11 23:16:51  elphel
00034 *!  removed unneeded local_irq_disable() after local_irq_save_flags()
00035 *!
00036 *!  Revision 1.2  2008/04/07 09:45:30  elphel
00037 *!  removed unused variable
00038 *!
00039 *!  Revision 1.1  2008/04/07 09:09:07  elphel
00040 *!  New driver to handle Exif
00041 *!
00042 *!
00043 */
00044 
00045 
00046 //copied freom cxi2c.c - TODO:remove unneeded
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 //#include <asm/svinto.h>
00061 #include <asm/byteorder.h> // endians
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"  // defines port_csp0_addr, port_csp4_addr 
00074 //
00075 //#include "x3x3.h"
00076 //#include "cc3x3.h"
00077 
00078 
00079 #include "exif353.h"
00080 
00081 #define D(x)
00082 //#define D(x) printk("%s:%d:",__FILE__,__LINE__);x
00083 
00084 
00085 //Major
00086 //#define X3X3_EXIF 136
00087 //Minors
00088 //#define X3X3_EXIF_EXIF    0 // read encoded Exif data (SEEK_END,
00089 //#define X3X3_EXIF_META    1 // write metadata, concurently opened files. All writes atomic
00090 // control/setup devices
00091 //#define X3X3_EXIF_TEMPLATE 2 // write Exif template
00092 //#define X3X3_EXIF_METADIR  3 // write metadata to Exif header translation (dir_table[MAX_EXIF_FIELDS])
00093 // those 2 files will disable exif_enabled and exif_valid, truncate file size to file pointer on release.
00094 //#define X3X3_EXIF_TIME     4 // write today/tomorrow date (YYYY:MM:DD) and number of seconds at today/tomorrow
00095                              // midnight (00:00:00) in seconds from epoch (long, startting from LSB)
00096 
00097 
00098 
00099 #define  X3X3_EXIF_DRIVER_NAME "Elphel (R) model 353 Exif device driver"
00100 
00101 //#define MAX_EXIF_FIELDS  256 // number of Exif tags in the header
00102 //#define MAX_EXIF_SIZE   4096 // Exif data size 
00103 
00104 static struct exif_dir_table_t dir_table[MAX_EXIF_FIELDS];
00105 static int  exif_fields        = 0; // total number of the Exif fields in the header
00106 static int  exif_template_size = 0; // size of Exif template
00107 static int  exif_meta_size     = 0; // size of Exif meta data page
00108 static int  exif_wp            = 1; // frame write pointer in the meta_buffer
00109 static char exif_template[MAX_EXIF_SIZE];
00110 
00111 static int exif_enabled = 0; // enable storing of frame meta data, enable reading Exif data
00112 static int exif_valid  = 0; // Exif tables and buffer are valid.
00113 
00114 static char * meta_buffer=NULL; // dynamically allocated buffer to store frame meta data.
00115 // page 0 - tempoary storage, 1..MAX_EXIF_FRAMES - buffer
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) { //return current file size for different minors
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) { //return max file size for different minors
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 //reallocate meta buffer to store per-frame meta data (later output as Exif)
00171 int exif_rebuild(int frames) {
00172   int i,ml;
00173   exif_enabled = 0;
00174   exif_valid  = 0;
00175   exif_wp     = 1;
00176 // free buffer, if allocated
00177   if (meta_buffer) {
00178     vfree (meta_buffer);
00179     meta_buffer=NULL;
00180   }
00181 //  calculate page size
00182   if (exif_fields==0) return 0; // exif_valid==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) { //find location of the tag field in meta page 
00214   int indx;
00215 //  for (indx=0; indx < exif_fields; indx++) if (dir_table[indx].ltag==tag) return indx;
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) { //write data to meta, called from IRQ
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) { //write data to meta, called from IRQ(len==0 => use field length)
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; //ltag not found
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) { //write data to meta (4 bytes, big endian), called from IRQ
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) { //write data to meta (4 bytes, big endian), from IRQ
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; //ltag not found
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) { //write data to meta, called from outside IRQ (atomic)
00262   unsigned long flags;
00263   if (exif_enabled) {
00264     local_irq_save(flags);
00265     //local_irq_disable();
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) { //write data to meta, from outside IRQ (atomic) (len==0 => use field length)
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; //ltag not found
00278   }
00279   if (len==0) len=dir_table[i].len;
00280   local_irq_save(flags);
00281   //local_irq_disable();
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) { //write data to meta (4 bytes, big endian), called from outside IRQ (atomic)
00289   unsigned long flags;
00290   unsigned long bedata=__cpu_to_be32(data);
00291   if (exif_enabled) {
00292     local_irq_save(flags);
00293     //local_irq_disable();
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) { //write data to meta (4 bytes, big endian), from outside IRQ (atomic)
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; //ltag not found
00308   }
00309   local_irq_save(flags);
00310   //local_irq_disable();
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    exp_bigendian=__cpu_to_be32((int)fp->exposure);
00320 
00321 static struct exif_time_t {
00322   char          tomorrow_date[10]; //!"YYYY:MM:DD"
00323   unsigned long tomorrow_sec;      //!seconds from epoch tomorrow at 00:00
00324   char          today_date[10];    //!"YYYY:MM:DD"
00325   unsigned long today_sec;         //!seconds from epoch today at 00:00
00326 } exif_time;
00327 
00328 static struct exif_datetime_t {
00329   char          datetime[20];      //!"YYYY:MM:DD HH:MM:SS\0"
00330   char          subsec[7];         //!ASCII microseconds (0-padded), ."\0"
00331 } now_datetime;
00332 */
00333 // The next function is normally called from the interrupt service routine
00334 // Encode time (epoch sec, usec) into static buffer, return pointer to the buffer 
00335 // Uses struct exif_time that should be updater from the user space (once a day),
00336 // calculates date/time ignoring leap seconds if not updated in time
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)) {// today's time is not valid, try tomorrow:
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)) {// today's time is _still_ not valid, has to do it itself :-(
00342       d=sec/86400;
00343       s=d*86400;
00344       y4=d/1461; // number of 4-year periods
00345       d-=1461*y4; //days after 1970, 1974, ...
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 //      d+=(lp && (d>58))?1:0;
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;} // December
00357             else       {m=11;d-=304;} // November
00358           } else       {m=10;d-=273;} // October
00359         } else {
00360           if (d>212) {
00361             if (d>243) {m= 9;d-=243;} // September
00362             else       {m= 8;d-=212;} // August
00363           } else       {m= 7;d-=181;} // July
00364         }
00365       } else {
00366         if (d>90) {
00367           if (d>120) {
00368             if (d>151) {m=6; d-=151;} // June
00369             else       {m=5; d-=120;} // May
00370           } else       {m=4; d-= 90;} // April
00371         } else {
00372           if (d>30) {
00373             if (d>59)  {m=3; d-= 59;} // March
00374             else       {m=2; d-= 30;} // February
00375           } else       {m=1; d++;   } // January
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 // now we have valid exif_time.today_date, exif_time.today_sec;
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) { //called from IRQ service - put current metadata to meta_buffer, return page index
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; // just a minor number
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; // just a minor number
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: //enable/disable
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; //TODO: change code
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; //TODO: change code
00487                 break;
00488               default:return -EINVAL;
00489             }
00490             break;
00491           case X3X3_EXIF_EXIF: // select page in the buffer
00492             if (offset > MAX_EXIF_FRAMES) return -EOVERFLOW; //larger than buffer
00493 //            file->f_pos=exif_meta_size * offset;
00494             file->f_pos=exif_template_size * offset;
00495 
00496             break;
00497           case X3X3_EXIF_META: // iterate
00498             fp= dir_find_tag (offset);
00499             if (fp < 0) return -EOVERFLOW; // tag is not in the directory
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    /* truncate position */
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 //  int thissize=minor_file_size(p);
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: //write date/time first, then - midnight seconds
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        //local_irq_disable();
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; // no writing - read only
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 //  int maxsize=minor_max_size(p);
00600   char * cp, * metap;
00601   int start_p, page_p,i;
00602   
00603   char tmp[MAX_EXIF_SIZE]; 
00604 /*
00605   Does not work with PHP - always read 8192 bytes
00606   if ((*off+count)>maxsize) {
00607     printk ("%s:%d: Data (0x%x) does not fit into 0x%x bytes\n",__FILE__,__LINE__, (int) (*off+count), maxsize);
00608     return -EOVERFLOW;
00609   }
00610 */
00611   if (*off > thissize) {
00612     return 0; // nothing to read
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: // generates exif data by merging exif_template with the selected meta_buffer page
00635 //will truncate by the end of current page
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 //arch/cris/arch-v32/drivers/elphel/exif353.c:590:count= 0x2000, *off= 0x410, i=0x82, exif_template_size=0x208
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 //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
00644 
00645        metap= &meta_buffer[i*exif_meta_size]; // pointer to the start of the selected page in frame meta_buffer
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);

Generated on Fri Nov 28 00:06:23 2008 for elphel by  doxygen 1.5.1